@camstack/addon-post-analysis 1.1.13 → 1.1.14

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.
@@ -4649,7 +4649,7 @@ function _instanceof(cls, params = {}) {
4649
4649
  return inst;
4650
4650
  }
4651
4651
  //#endregion
4652
- //#region ../types/dist/sleep-C2M2zF7x.mjs
4652
+ //#region ../types/dist/sleep-MHm--th-.mjs
4653
4653
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4654
4654
  EventCategory["SystemBoot"] = "system.boot";
4655
4655
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5911,6 +5911,7 @@ var CamStreamKindSchema = _enum([
5911
5911
  "pull-rtsp",
5912
5912
  "pull-rtmp",
5913
5913
  "pull-http",
5914
+ "pull-flv",
5914
5915
  "pull-rfc4571",
5915
5916
  "push-annexb",
5916
5917
  "derived"
@@ -6832,6 +6833,25 @@ var ConvertResultSchema = object({
6832
6833
  })).readonly()
6833
6834
  });
6834
6835
  /**
6836
+ * THE canonical event-clip pad: the time window a single-timestamp analytics
6837
+ * event expands to when joined with footage (clip window = `[timestamp - preMs,
6838
+ * timestamp + postMs]`). Matches the admin-ui clip window (−5s/+10s).
6839
+ *
6840
+ * Every consumer derives from this ONE constant so event↔footage boundaries
6841
+ * agree everywhere (C1):
6842
+ * - the `videoclips` default provider (addon-post-analysis) pads its clip
6843
+ * windows with it;
6844
+ * - the recorder's ephemeral in-RAM `EventMap` markers (addon-pipeline) pad
6845
+ * their `startMs/endMs` with it.
6846
+ *
6847
+ * NOTE: this is a UI/JOIN convention, NOT the `events`-band keep/discard gate —
6848
+ * that uses the per-device `preBufferSec`/`postBufferSec` config.
6849
+ */
6850
+ var EVENT_PAD_MS = {
6851
+ preMs: 5e3,
6852
+ postMs: 1e4
6853
+ };
6854
+ /**
6835
6855
  * Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
6836
6856
  * Named `RecordingWeekday` to avoid collision with the string-union
6837
6857
  * `Weekday` exported from `interfaces/timezones.ts`.
@@ -9862,6 +9882,31 @@ var ReportMotionInputSchema = object({
9862
9882
  regions: array(MotionRegionSchema).readonly().optional()
9863
9883
  });
9864
9884
  /**
9885
+ * Where a runner gets a camera's decoded frames (cross-node Phase 2,
9886
+ * restream-owner model — P2c).
9887
+ *
9888
+ * - `local-broker` (DEFAULT): today's path — subscribe to the co-located
9889
+ * stream-broker's shm frame plane. Every pre-P2c attach payload (no
9890
+ * `frameSource` key) parses to this, so the field is additive with zero
9891
+ * behavior change.
9892
+ * - `remote-restream`: the detect node is NOT the camera's source-owner.
9893
+ * The runner acquires the owner's COMPRESSED passthrough restream
9894
+ * (`streamBroker.getStreamWithCodec({video:'copy'})` — refcounted, the
9895
+ * double-pull guard) and decodes LOCALLY via a satellite frame plane +
9896
+ * pull-mode decoder session pinned to its own node. The shm ring stays
9897
+ * node-local; only H.264/H.265 packets cross the wire.
9898
+ * `hubHostnameOverride` mirrors the recorder's `recordingHubHostname`:
9899
+ * when set it overrides the `CAMSTACK_HUB_URL`-derived host the runner
9900
+ * dials for the owner's restream.
9901
+ */
9902
+ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal("local-broker") }), object({
9903
+ kind: literal("remote-restream"),
9904
+ /** The camera's source-owner node (slice 1: always the hub). */
9905
+ ownerNodeId: string(),
9906
+ /** Operator override for the owner host the runner dials. */
9907
+ hubHostnameOverride: string().optional()
9908
+ })]).describe("Per-camera frame-source mode for the runner (P2c)");
9909
+ /**
9865
9910
  * Camera assignment payload sent by `addon-pipeline-orchestrator` to a
9866
9911
  * specific runner instance via `attachCamera`. Carries everything the
9867
9912
  * runner needs to subscribe to the local broker and execute inference.
@@ -9959,7 +10004,15 @@ var RunnerCameraConfigSchema = object({
9959
10004
  */
9960
10005
  onboardMotionDrivesAnalyzer: boolean().default(true),
9961
10006
  occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
9962
- occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default)
10007
+ occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
10008
+ /**
10009
+ * Where this runner gets the camera's decoded frames (P2c). Defaulted so
10010
+ * every existing payload behaves as `local-broker` — the pre-Phase-2 path.
10011
+ * Populated with `remote-restream` by the orchestrator ONLY when the
10012
+ * camera's detect node differs from its source-owner (P2d, gated by the
10013
+ * `remoteSourcingNodes` rollout setting).
10014
+ */
10015
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
9963
10016
  });
9964
10017
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
9965
10018
  /**
@@ -13336,7 +13389,7 @@ var AddBrokerInputSchema = object({
13336
13389
  });
13337
13390
  var AddBrokerResultSchema = object({ id: string() });
13338
13391
  var IdInputSchema = object({ id: string() });
13339
- var TestResultSchema = discriminatedUnion("ok", [object({
13392
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13340
13393
  ok: literal(true),
13341
13394
  latencyMs: number()
13342
13395
  }), object({
@@ -13359,7 +13412,7 @@ var StatusSchema = object({
13359
13412
  brokerCount: number(),
13360
13413
  embeddedRunning: boolean()
13361
13414
  });
13362
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
13415
+ method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema$1, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
13363
13416
  var NetworkEndpointSchema = object({
13364
13417
  url: string(),
13365
13418
  hostname: string(),
@@ -13393,23 +13446,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
13393
13446
  sourcePort: number().optional()
13394
13447
  });
13395
13448
  method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
13396
- method(object({
13397
- title: string(),
13449
+ /**
13450
+ * notification-output — canonical, capability-gated notification delivery.
13451
+ *
13452
+ * Apprise-derived model (see
13453
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13454
+ * callers emit ONE canonical `Notification`; each provider declares a
13455
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13456
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13457
+ * message to what the kind supports — callers never special-case a service.
13458
+ *
13459
+ * DESIGN DECISIONS (locked):
13460
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13461
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13462
+ * cap. Rationale: the admin UI needs one uniform surface across the
13463
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13464
+ * alternative would fork the UI per addon and cannot host the
13465
+ * discovery→adopt flow.
13466
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13467
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13468
+ * registered provider (notifiers addon + HA addon) so one catalog is
13469
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13470
+ * `addonId` the generated collection router extracts from the call input.
13471
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13472
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13473
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13474
+ * base64 fallback needed.
13475
+ *
13476
+ * TODO (deferred, closed-set change — separate decision): add
13477
+ * `providerKind: 'notify'` so notification providers surface on the unified
13478
+ * admin "Integrations" page.
13479
+ */
13480
+ /**
13481
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13482
+ * adapter picks what it supports and the degrade engine filters the rest.
13483
+ */
13484
+ var AttachmentMediaTypeSchema = _enum([
13485
+ "image",
13486
+ "video",
13487
+ "gif",
13488
+ "audio",
13489
+ "icon"
13490
+ ]);
13491
+ /**
13492
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13493
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13494
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13495
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13496
+ */
13497
+ var AttachmentSchema = object({
13498
+ mediaType: AttachmentMediaTypeSchema,
13499
+ url: string().optional(),
13500
+ bytes: _instanceof(Uint8Array).optional(),
13501
+ mime: string().optional(),
13502
+ name: string().optional()
13503
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13504
+ var NotificationFormatSchema = _enum([
13505
+ "text",
13506
+ "markdown",
13507
+ "html"
13508
+ ]);
13509
+ /** A single tap-through action button. */
13510
+ var NotificationActionSchema = object({
13511
+ id: string(),
13512
+ label: string(),
13513
+ url: string().optional()
13514
+ });
13515
+ /**
13516
+ * The canonical notification. `body` is the only hard field (Apprise model).
13517
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13518
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13519
+ * the adapter maps this ordinal onto its native level. `level?` is an
13520
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13521
+ * `priority` for that one target.
13522
+ */
13523
+ var NotificationSchema = object({
13398
13524
  body: string(),
13399
- imageUrl: string().optional(),
13525
+ title: string().optional(),
13526
+ format: NotificationFormatSchema.default("text"),
13527
+ priority: number().int().min(1).max(5).default(3),
13528
+ level: string().optional(),
13529
+ attachments: array(AttachmentSchema).optional(),
13530
+ clickUrl: string().optional(),
13531
+ actions: array(NotificationActionSchema).optional(),
13532
+ sound: string().optional(),
13533
+ ttl: number().optional(),
13534
+ tag: string().optional(),
13400
13535
  deviceId: number().optional(),
13401
13536
  eventId: string().optional(),
13402
- priority: _enum([
13403
- "low",
13404
- "normal",
13405
- "high",
13406
- "critical"
13407
- ]).default("normal"),
13408
13537
  metadata: record(string(), unknown()).optional()
13409
- }), _void(), { kind: "mutation" }), method(_void(), object({
13538
+ });
13539
+ /** One declared native severity/priority level for a kind. */
13540
+ var TargetKindLevelSchema = object({
13541
+ id: string(),
13542
+ label: string(),
13543
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13544
+ ordinal: number().int().min(1).max(5).nullable(),
13545
+ flags: object({
13546
+ critical: boolean().optional(),
13547
+ silent: boolean().optional(),
13548
+ noPush: boolean().optional()
13549
+ }).optional(),
13550
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13551
+ requires: array(string()).optional(),
13552
+ description: string().optional()
13553
+ });
13554
+ /** The full capability block consulted before dispatch. */
13555
+ var TargetKindCapsSchema = object({
13556
+ attachments: object({
13557
+ mediaTypes: array(AttachmentMediaTypeSchema),
13558
+ mode: _enum([
13559
+ "url",
13560
+ "bytes",
13561
+ "both"
13562
+ ]),
13563
+ max: number().int().nonnegative(),
13564
+ maxBytes: number().int().positive().optional()
13565
+ }),
13566
+ /** Max action buttons (0 = none). */
13567
+ actions: number().int().nonnegative(),
13568
+ levels: array(TargetKindLevelSchema),
13569
+ format: array(NotificationFormatSchema),
13570
+ clickUrl: boolean(),
13571
+ sound: boolean(),
13572
+ ttl: boolean(),
13573
+ bodyMaxLen: number().int().positive()
13574
+ });
13575
+ /**
13576
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13577
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13578
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13579
+ * the union is large and not meant for runtime validation here; the exported
13580
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13581
+ */
13582
+ var ConfigSchemaPassthrough = unknown();
13583
+ var TargetKindSchema = object({
13584
+ kind: string(),
13585
+ label: string(),
13586
+ icon: string(),
13587
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13588
+ addonId: string(),
13589
+ configSchema: ConfigSchemaPassthrough,
13590
+ supportsDiscovery: boolean(),
13591
+ caps: TargetKindCapsSchema
13592
+ });
13593
+ /**
13594
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13595
+ * (return a presence marker only) when serving `listTargets` — never
13596
+ * round-trip a stored secret to the UI.
13597
+ */
13598
+ var TargetSchema = object({
13599
+ id: string(),
13600
+ name: string(),
13601
+ kind: string(),
13602
+ addonId: string(),
13603
+ enabled: boolean(),
13604
+ config: record(string(), unknown())
13605
+ });
13606
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13607
+ var DiscoveredTargetSchema = object({
13608
+ kind: string(),
13609
+ suggestedName: string(),
13610
+ config: record(string(), unknown())
13611
+ });
13612
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13613
+ var RenderedAsSchema = object({
13614
+ level: string(),
13615
+ format: NotificationFormatSchema,
13616
+ attachmentsSent: number().int().nonnegative(),
13617
+ actionsSent: number().int().nonnegative(),
13618
+ truncated: boolean(),
13619
+ dropped: array(string())
13620
+ });
13621
+ var SendResultSchema = object({
13410
13622
  success: boolean(),
13411
- error: string().optional()
13412
- }), { kind: "mutation" });
13623
+ error: string().optional(),
13624
+ renderedAs: RenderedAsSchema.optional()
13625
+ });
13626
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13627
+ var TestResultSchema = SendResultSchema;
13628
+ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
13629
+ kind: string(),
13630
+ config: record(string(), unknown()).optional()
13631
+ }), array(DiscoveredTargetSchema)), method(object({
13632
+ targetId: string(),
13633
+ notification: NotificationSchema
13634
+ }), SendResultSchema, { kind: "mutation" }), method(object({
13635
+ targetId: string(),
13636
+ sample: NotificationSchema.optional()
13637
+ }), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
13638
+ targetId: string(),
13639
+ enabled: boolean()
13640
+ }), _void(), { kind: "mutation" });
13413
13641
  /**
13414
13642
  * Zod schemas for persisted record types.
13415
13643
  *
@@ -16716,6 +16944,16 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
16716
16944
  kind: "mutation",
16717
16945
  auth: "admin"
16718
16946
  });
16947
+ /**
16948
+ * `recording` cap — footage availability + HLS playback manifests + per-device
16949
+ * recording config. NOTE on events (source of truth, R5/C3): this cap carries
16950
+ * NO event surface — `getPlaybackManifest` returns playlist URLs only. Timeline
16951
+ * events (motion/object/audio) come from `pipelineAnalytics` (durable SQLite
16952
+ * rows); the recorder's internal EventMap markers are ephemeral in-RAM
16953
+ * annotations that are not exposed here and must not be treated as an event
16954
+ * feed. Event<->footage joins are by time, padded with the shared `EVENT_PAD_MS`
16955
+ * (`interfaces/recording-config.ts`).
16956
+ */
16719
16957
  var RecordingStatusSchema = object({
16720
16958
  deviceId: number(),
16721
16959
  enabled: boolean(),
@@ -19522,13 +19760,49 @@ Object.freeze({
19522
19760
  addonId: null,
19523
19761
  access: "create"
19524
19762
  },
19763
+ "notificationOutput.deleteTarget": {
19764
+ capName: "notification-output",
19765
+ capScope: "system",
19766
+ addonId: null,
19767
+ access: "delete"
19768
+ },
19769
+ "notificationOutput.discoverTargets": {
19770
+ capName: "notification-output",
19771
+ capScope: "system",
19772
+ addonId: null,
19773
+ access: "view"
19774
+ },
19775
+ "notificationOutput.listTargetKinds": {
19776
+ capName: "notification-output",
19777
+ capScope: "system",
19778
+ addonId: null,
19779
+ access: "view"
19780
+ },
19781
+ "notificationOutput.listTargets": {
19782
+ capName: "notification-output",
19783
+ capScope: "system",
19784
+ addonId: null,
19785
+ access: "view"
19786
+ },
19525
19787
  "notificationOutput.send": {
19526
19788
  capName: "notification-output",
19527
19789
  capScope: "system",
19528
19790
  addonId: null,
19529
19791
  access: "create"
19530
19792
  },
19531
- "notificationOutput.sendTest": {
19793
+ "notificationOutput.setTargetEnabled": {
19794
+ capName: "notification-output",
19795
+ capScope: "system",
19796
+ addonId: null,
19797
+ access: "create"
19798
+ },
19799
+ "notificationOutput.testTarget": {
19800
+ capName: "notification-output",
19801
+ capScope: "system",
19802
+ addonId: null,
19803
+ access: "create"
19804
+ },
19805
+ "notificationOutput.upsertTarget": {
19532
19806
  capName: "notification-output",
19533
19807
  capScope: "system",
19534
19808
  addonId: null,
@@ -21526,6 +21800,12 @@ Object.defineProperty(exports, "DeviceType", {
21526
21800
  return DeviceType;
21527
21801
  }
21528
21802
  });
21803
+ Object.defineProperty(exports, "EVENT_PAD_MS", {
21804
+ enumerable: true,
21805
+ get: function() {
21806
+ return EVENT_PAD_MS;
21807
+ }
21808
+ });
21529
21809
  Object.defineProperty(exports, "EventCategory", {
21530
21810
  enumerable: true,
21531
21811
  get: function() {