@camstack/addon-provider-reolink 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.
- package/dist/addon.js +268 -17
- package/dist/addon.mjs +268 -17
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -4655,7 +4655,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4655
4655
|
return inst;
|
|
4656
4656
|
}
|
|
4657
4657
|
//#endregion
|
|
4658
|
-
//#region ../types/dist/sleep-
|
|
4658
|
+
//#region ../types/dist/sleep-MHm--th-.mjs
|
|
4659
4659
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4660
4660
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4661
4661
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5917,6 +5917,7 @@ var CamStreamKindSchema = _enum([
|
|
|
5917
5917
|
"pull-rtsp",
|
|
5918
5918
|
"pull-rtmp",
|
|
5919
5919
|
"pull-http",
|
|
5920
|
+
"pull-flv",
|
|
5920
5921
|
"pull-rfc4571",
|
|
5921
5922
|
"push-annexb",
|
|
5922
5923
|
"derived"
|
|
@@ -16291,7 +16292,7 @@ var AddBrokerInputSchema = object({
|
|
|
16291
16292
|
});
|
|
16292
16293
|
var AddBrokerResultSchema = object({ id: string() });
|
|
16293
16294
|
var IdInputSchema = object({ id: string() });
|
|
16294
|
-
var TestResultSchema = discriminatedUnion("ok", [object({
|
|
16295
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
16295
16296
|
ok: literal(true),
|
|
16296
16297
|
latencyMs: number()
|
|
16297
16298
|
}), object({
|
|
@@ -16314,7 +16315,7 @@ var StatusSchema = object({
|
|
|
16314
16315
|
brokerCount: number(),
|
|
16315
16316
|
embeddedRunning: boolean()
|
|
16316
16317
|
});
|
|
16317
|
-
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);
|
|
16318
|
+
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);
|
|
16318
16319
|
var NetworkEndpointSchema = object({
|
|
16319
16320
|
url: string(),
|
|
16320
16321
|
hostname: string(),
|
|
@@ -16348,23 +16349,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
|
16348
16349
|
sourcePort: number().optional()
|
|
16349
16350
|
});
|
|
16350
16351
|
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
16351
|
-
|
|
16352
|
-
|
|
16352
|
+
/**
|
|
16353
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16354
|
+
*
|
|
16355
|
+
* Apprise-derived model (see
|
|
16356
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16357
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16358
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16359
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16360
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16361
|
+
*
|
|
16362
|
+
* DESIGN DECISIONS (locked):
|
|
16363
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16364
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16365
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16366
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16367
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16368
|
+
* discovery→adopt flow.
|
|
16369
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16370
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16371
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16372
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16373
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16374
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16375
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16376
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16377
|
+
* base64 fallback needed.
|
|
16378
|
+
*
|
|
16379
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16380
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16381
|
+
* admin "Integrations" page.
|
|
16382
|
+
*/
|
|
16383
|
+
/**
|
|
16384
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16385
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16386
|
+
*/
|
|
16387
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16388
|
+
"image",
|
|
16389
|
+
"video",
|
|
16390
|
+
"gif",
|
|
16391
|
+
"audio",
|
|
16392
|
+
"icon"
|
|
16393
|
+
]);
|
|
16394
|
+
/**
|
|
16395
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16396
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16397
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16398
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16399
|
+
*/
|
|
16400
|
+
var AttachmentSchema = object({
|
|
16401
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16402
|
+
url: string().optional(),
|
|
16403
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16404
|
+
mime: string().optional(),
|
|
16405
|
+
name: string().optional()
|
|
16406
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16407
|
+
var NotificationFormatSchema = _enum([
|
|
16408
|
+
"text",
|
|
16409
|
+
"markdown",
|
|
16410
|
+
"html"
|
|
16411
|
+
]);
|
|
16412
|
+
/** A single tap-through action button. */
|
|
16413
|
+
var NotificationActionSchema = object({
|
|
16414
|
+
id: string(),
|
|
16415
|
+
label: string(),
|
|
16416
|
+
url: string().optional()
|
|
16417
|
+
});
|
|
16418
|
+
/**
|
|
16419
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16420
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16421
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16422
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16423
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16424
|
+
* `priority` for that one target.
|
|
16425
|
+
*/
|
|
16426
|
+
var NotificationSchema = object({
|
|
16353
16427
|
body: string(),
|
|
16354
|
-
|
|
16428
|
+
title: string().optional(),
|
|
16429
|
+
format: NotificationFormatSchema.default("text"),
|
|
16430
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16431
|
+
level: string().optional(),
|
|
16432
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16433
|
+
clickUrl: string().optional(),
|
|
16434
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16435
|
+
sound: string().optional(),
|
|
16436
|
+
ttl: number().optional(),
|
|
16437
|
+
tag: string().optional(),
|
|
16355
16438
|
deviceId: number().optional(),
|
|
16356
16439
|
eventId: string().optional(),
|
|
16357
|
-
priority: _enum([
|
|
16358
|
-
"low",
|
|
16359
|
-
"normal",
|
|
16360
|
-
"high",
|
|
16361
|
-
"critical"
|
|
16362
|
-
]).default("normal"),
|
|
16363
16440
|
metadata: record(string(), unknown()).optional()
|
|
16364
|
-
})
|
|
16441
|
+
});
|
|
16442
|
+
/** One declared native severity/priority level for a kind. */
|
|
16443
|
+
var TargetKindLevelSchema = object({
|
|
16444
|
+
id: string(),
|
|
16445
|
+
label: string(),
|
|
16446
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16447
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16448
|
+
flags: object({
|
|
16449
|
+
critical: boolean().optional(),
|
|
16450
|
+
silent: boolean().optional(),
|
|
16451
|
+
noPush: boolean().optional()
|
|
16452
|
+
}).optional(),
|
|
16453
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16454
|
+
requires: array(string()).optional(),
|
|
16455
|
+
description: string().optional()
|
|
16456
|
+
});
|
|
16457
|
+
/** The full capability block consulted before dispatch. */
|
|
16458
|
+
var TargetKindCapsSchema = object({
|
|
16459
|
+
attachments: object({
|
|
16460
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16461
|
+
mode: _enum([
|
|
16462
|
+
"url",
|
|
16463
|
+
"bytes",
|
|
16464
|
+
"both"
|
|
16465
|
+
]),
|
|
16466
|
+
max: number().int().nonnegative(),
|
|
16467
|
+
maxBytes: number().int().positive().optional()
|
|
16468
|
+
}),
|
|
16469
|
+
/** Max action buttons (0 = none). */
|
|
16470
|
+
actions: number().int().nonnegative(),
|
|
16471
|
+
levels: array(TargetKindLevelSchema),
|
|
16472
|
+
format: array(NotificationFormatSchema),
|
|
16473
|
+
clickUrl: boolean(),
|
|
16474
|
+
sound: boolean(),
|
|
16475
|
+
ttl: boolean(),
|
|
16476
|
+
bodyMaxLen: number().int().positive()
|
|
16477
|
+
});
|
|
16478
|
+
/**
|
|
16479
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16480
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16481
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16482
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16483
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16484
|
+
*/
|
|
16485
|
+
var ConfigSchemaPassthrough = unknown();
|
|
16486
|
+
var TargetKindSchema = object({
|
|
16487
|
+
kind: string(),
|
|
16488
|
+
label: string(),
|
|
16489
|
+
icon: string(),
|
|
16490
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16491
|
+
addonId: string(),
|
|
16492
|
+
configSchema: ConfigSchemaPassthrough,
|
|
16493
|
+
supportsDiscovery: boolean(),
|
|
16494
|
+
caps: TargetKindCapsSchema
|
|
16495
|
+
});
|
|
16496
|
+
/**
|
|
16497
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16498
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16499
|
+
* round-trip a stored secret to the UI.
|
|
16500
|
+
*/
|
|
16501
|
+
var TargetSchema = object({
|
|
16502
|
+
id: string(),
|
|
16503
|
+
name: string(),
|
|
16504
|
+
kind: string(),
|
|
16505
|
+
addonId: string(),
|
|
16506
|
+
enabled: boolean(),
|
|
16507
|
+
config: record(string(), unknown())
|
|
16508
|
+
});
|
|
16509
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16510
|
+
var DiscoveredTargetSchema = object({
|
|
16511
|
+
kind: string(),
|
|
16512
|
+
suggestedName: string(),
|
|
16513
|
+
config: record(string(), unknown())
|
|
16514
|
+
});
|
|
16515
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16516
|
+
var RenderedAsSchema = object({
|
|
16517
|
+
level: string(),
|
|
16518
|
+
format: NotificationFormatSchema,
|
|
16519
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16520
|
+
actionsSent: number().int().nonnegative(),
|
|
16521
|
+
truncated: boolean(),
|
|
16522
|
+
dropped: array(string())
|
|
16523
|
+
});
|
|
16524
|
+
var SendResultSchema = object({
|
|
16365
16525
|
success: boolean(),
|
|
16366
|
-
error: string().optional()
|
|
16367
|
-
|
|
16526
|
+
error: string().optional(),
|
|
16527
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16528
|
+
});
|
|
16529
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16530
|
+
var TestResultSchema = SendResultSchema;
|
|
16531
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
|
|
16532
|
+
kind: string(),
|
|
16533
|
+
config: record(string(), unknown()).optional()
|
|
16534
|
+
}), array(DiscoveredTargetSchema)), method(object({
|
|
16535
|
+
targetId: string(),
|
|
16536
|
+
notification: NotificationSchema
|
|
16537
|
+
}), SendResultSchema, { kind: "mutation" }), method(object({
|
|
16538
|
+
targetId: string(),
|
|
16539
|
+
sample: NotificationSchema.optional()
|
|
16540
|
+
}), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
16541
|
+
targetId: string(),
|
|
16542
|
+
enabled: boolean()
|
|
16543
|
+
}), _void(), { kind: "mutation" });
|
|
16368
16544
|
/**
|
|
16369
16545
|
* Zod schemas for persisted record types.
|
|
16370
16546
|
*
|
|
@@ -22731,13 +22907,49 @@ Object.freeze({
|
|
|
22731
22907
|
addonId: null,
|
|
22732
22908
|
access: "create"
|
|
22733
22909
|
},
|
|
22910
|
+
"notificationOutput.deleteTarget": {
|
|
22911
|
+
capName: "notification-output",
|
|
22912
|
+
capScope: "system",
|
|
22913
|
+
addonId: null,
|
|
22914
|
+
access: "delete"
|
|
22915
|
+
},
|
|
22916
|
+
"notificationOutput.discoverTargets": {
|
|
22917
|
+
capName: "notification-output",
|
|
22918
|
+
capScope: "system",
|
|
22919
|
+
addonId: null,
|
|
22920
|
+
access: "view"
|
|
22921
|
+
},
|
|
22922
|
+
"notificationOutput.listTargetKinds": {
|
|
22923
|
+
capName: "notification-output",
|
|
22924
|
+
capScope: "system",
|
|
22925
|
+
addonId: null,
|
|
22926
|
+
access: "view"
|
|
22927
|
+
},
|
|
22928
|
+
"notificationOutput.listTargets": {
|
|
22929
|
+
capName: "notification-output",
|
|
22930
|
+
capScope: "system",
|
|
22931
|
+
addonId: null,
|
|
22932
|
+
access: "view"
|
|
22933
|
+
},
|
|
22734
22934
|
"notificationOutput.send": {
|
|
22735
22935
|
capName: "notification-output",
|
|
22736
22936
|
capScope: "system",
|
|
22737
22937
|
addonId: null,
|
|
22738
22938
|
access: "create"
|
|
22739
22939
|
},
|
|
22740
|
-
"notificationOutput.
|
|
22940
|
+
"notificationOutput.setTargetEnabled": {
|
|
22941
|
+
capName: "notification-output",
|
|
22942
|
+
capScope: "system",
|
|
22943
|
+
addonId: null,
|
|
22944
|
+
access: "create"
|
|
22945
|
+
},
|
|
22946
|
+
"notificationOutput.testTarget": {
|
|
22947
|
+
capName: "notification-output",
|
|
22948
|
+
capScope: "system",
|
|
22949
|
+
addonId: null,
|
|
22950
|
+
access: "create"
|
|
22951
|
+
},
|
|
22952
|
+
"notificationOutput.upsertTarget": {
|
|
22741
22953
|
capName: "notification-output",
|
|
22742
22954
|
capScope: "system",
|
|
22743
22955
|
addonId: null,
|
|
@@ -215236,7 +215448,7 @@ function isNativeObjectForwardingEnabled(capState) {
|
|
|
215236
215448
|
}
|
|
215237
215449
|
//#endregion
|
|
215238
215450
|
//#region src/stream-routing.ts
|
|
215239
|
-
var KIND_RE = /^(native|rtsp|rtmp):(.+)$/;
|
|
215451
|
+
var KIND_RE = /^(native|rtsp|rtmp|flv):(.+)$/;
|
|
215240
215452
|
var CH_PROFILE_RE = /^ch(\d+)-(main|sub|ext)$/;
|
|
215241
215453
|
var PROFILE_ONLY_RE = /^(main|sub|ext)$/;
|
|
215242
215454
|
/**
|
|
@@ -215286,6 +215498,7 @@ function kindLabel(kind) {
|
|
|
215286
215498
|
case "native": return "Native";
|
|
215287
215499
|
case "rtsp": return "RTSP";
|
|
215288
215500
|
case "rtmp": return "RTMP";
|
|
215501
|
+
case "flv": return "FLV";
|
|
215289
215502
|
}
|
|
215290
215503
|
}
|
|
215291
215504
|
/**
|
|
@@ -219172,6 +219385,23 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
219172
219385
|
}
|
|
219173
219386
|
}
|
|
219174
219387
|
/**
|
|
219388
|
+
* Synthesize the HTTP-FLV pull URL for a (channel, profile) pair. FLV is
|
|
219389
|
+
* served off the Reolink Baichuan media port (default 1935, app `bcs`) as
|
|
219390
|
+
* `channel<channel>_<profile>.bcs` — the same shape Frigate/go2rtc use. The
|
|
219391
|
+
* lib does NOT surface this URL, so we build it from the SAME connection
|
|
219392
|
+
* creds the RTSP/native paths use (`host`/`username`/`password` on the
|
|
219393
|
+
* device config), URL-encoding the credentials.
|
|
219394
|
+
*
|
|
219395
|
+
* Returns `null` when the host isn't locally resolvable (hub-child cameras
|
|
219396
|
+
* borrow the parent's socket and hold no own `host`), so the caller skips
|
|
219397
|
+
* FLV publication for those devices rather than emitting a broken URL.
|
|
219398
|
+
*/
|
|
219399
|
+
buildFlvUrl(channel, profile) {
|
|
219400
|
+
const host = this.config.get("host");
|
|
219401
|
+
if (typeof host !== "string" || host.length === 0) return null;
|
|
219402
|
+
return `http://${host}/flv?port=1935&app=bcs&stream=channel${channel}_${profile}.bcs&user=${encodeURIComponent(String(this.config.get("username") ?? ""))}&password=${encodeURIComponent(String(this.config.get("password") ?? ""))}`;
|
|
219403
|
+
}
|
|
219404
|
+
/**
|
|
219175
219405
|
* Heavy path: talk to the camera and assemble the descriptors. Only ever
|
|
219176
219406
|
* entered when there is no cached catalog (see `buildStreamCatalog`).
|
|
219177
219407
|
*
|
|
@@ -219257,6 +219487,27 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
219257
219487
|
};
|
|
219258
219488
|
enqueueAlt("rtsp", streamOptions.rtspStreams);
|
|
219259
219489
|
enqueueAlt("rtmp", streamOptions.rtmpStreams);
|
|
219490
|
+
for (const s of streamOptions.nativeStreams) {
|
|
219491
|
+
const channel = s.channel ?? (isChild ? ownChannel : 0);
|
|
219492
|
+
const id = buildCamStreamId("flv", channel, s.profile, channelCount);
|
|
219493
|
+
if (desired.has(id)) continue;
|
|
219494
|
+
const flvUrl = this.buildFlvUrl(channel, s.profile);
|
|
219495
|
+
if (!flvUrl) break;
|
|
219496
|
+
const m = s.metadata;
|
|
219497
|
+
desired.set(id, {
|
|
219498
|
+
camStreamId: id,
|
|
219499
|
+
kind: "pull-flv",
|
|
219500
|
+
label: streamLabel(s, "flv"),
|
|
219501
|
+
url: flvUrl,
|
|
219502
|
+
autoEligible: false,
|
|
219503
|
+
...m && m.width > 0 && m.height > 0 ? { resolution: {
|
|
219504
|
+
width: m.width,
|
|
219505
|
+
height: m.height
|
|
219506
|
+
} } : {},
|
|
219507
|
+
...m && m.frameRate > 0 ? { fps: m.frameRate } : {},
|
|
219508
|
+
...normalizeCodecName(m?.videoEncType) ? { codec: normalizeCodecName(m?.videoEncType) } : {}
|
|
219509
|
+
});
|
|
219510
|
+
}
|
|
219260
219511
|
if (desired.size === 0) {
|
|
219261
219512
|
this.ctx.logger.warn("buildStreamCatalog: camera reports no streams — empty catalog", { tags: { deviceId: this.id } });
|
|
219262
219513
|
return [];
|
package/dist/addon.mjs
CHANGED
|
@@ -4650,7 +4650,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4650
4650
|
return inst;
|
|
4651
4651
|
}
|
|
4652
4652
|
//#endregion
|
|
4653
|
-
//#region ../types/dist/sleep-
|
|
4653
|
+
//#region ../types/dist/sleep-MHm--th-.mjs
|
|
4654
4654
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4655
4655
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4656
4656
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5912,6 +5912,7 @@ var CamStreamKindSchema = _enum([
|
|
|
5912
5912
|
"pull-rtsp",
|
|
5913
5913
|
"pull-rtmp",
|
|
5914
5914
|
"pull-http",
|
|
5915
|
+
"pull-flv",
|
|
5915
5916
|
"pull-rfc4571",
|
|
5916
5917
|
"push-annexb",
|
|
5917
5918
|
"derived"
|
|
@@ -16286,7 +16287,7 @@ var AddBrokerInputSchema = object({
|
|
|
16286
16287
|
});
|
|
16287
16288
|
var AddBrokerResultSchema = object({ id: string() });
|
|
16288
16289
|
var IdInputSchema = object({ id: string() });
|
|
16289
|
-
var TestResultSchema = discriminatedUnion("ok", [object({
|
|
16290
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
16290
16291
|
ok: literal(true),
|
|
16291
16292
|
latencyMs: number()
|
|
16292
16293
|
}), object({
|
|
@@ -16309,7 +16310,7 @@ var StatusSchema = object({
|
|
|
16309
16310
|
brokerCount: number(),
|
|
16310
16311
|
embeddedRunning: boolean()
|
|
16311
16312
|
});
|
|
16312
|
-
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);
|
|
16313
|
+
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);
|
|
16313
16314
|
var NetworkEndpointSchema = object({
|
|
16314
16315
|
url: string(),
|
|
16315
16316
|
hostname: string(),
|
|
@@ -16343,23 +16344,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
|
16343
16344
|
sourcePort: number().optional()
|
|
16344
16345
|
});
|
|
16345
16346
|
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
16346
|
-
|
|
16347
|
-
|
|
16347
|
+
/**
|
|
16348
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
16349
|
+
*
|
|
16350
|
+
* Apprise-derived model (see
|
|
16351
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
16352
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
16353
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
16354
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
16355
|
+
* message to what the kind supports — callers never special-case a service.
|
|
16356
|
+
*
|
|
16357
|
+
* DESIGN DECISIONS (locked):
|
|
16358
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
16359
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
16360
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
16361
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
16362
|
+
* alternative would fork the UI per addon and cannot host the
|
|
16363
|
+
* discovery→adopt flow.
|
|
16364
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
16365
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
16366
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
16367
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
16368
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
16369
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
16370
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
16371
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
16372
|
+
* base64 fallback needed.
|
|
16373
|
+
*
|
|
16374
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
16375
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
16376
|
+
* admin "Integrations" page.
|
|
16377
|
+
*/
|
|
16378
|
+
/**
|
|
16379
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
16380
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
16381
|
+
*/
|
|
16382
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
16383
|
+
"image",
|
|
16384
|
+
"video",
|
|
16385
|
+
"gif",
|
|
16386
|
+
"audio",
|
|
16387
|
+
"icon"
|
|
16388
|
+
]);
|
|
16389
|
+
/**
|
|
16390
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
16391
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
16392
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
16393
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
16394
|
+
*/
|
|
16395
|
+
var AttachmentSchema = object({
|
|
16396
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
16397
|
+
url: string().optional(),
|
|
16398
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
16399
|
+
mime: string().optional(),
|
|
16400
|
+
name: string().optional()
|
|
16401
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
16402
|
+
var NotificationFormatSchema = _enum([
|
|
16403
|
+
"text",
|
|
16404
|
+
"markdown",
|
|
16405
|
+
"html"
|
|
16406
|
+
]);
|
|
16407
|
+
/** A single tap-through action button. */
|
|
16408
|
+
var NotificationActionSchema = object({
|
|
16409
|
+
id: string(),
|
|
16410
|
+
label: string(),
|
|
16411
|
+
url: string().optional()
|
|
16412
|
+
});
|
|
16413
|
+
/**
|
|
16414
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
16415
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
16416
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
16417
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
16418
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
16419
|
+
* `priority` for that one target.
|
|
16420
|
+
*/
|
|
16421
|
+
var NotificationSchema = object({
|
|
16348
16422
|
body: string(),
|
|
16349
|
-
|
|
16423
|
+
title: string().optional(),
|
|
16424
|
+
format: NotificationFormatSchema.default("text"),
|
|
16425
|
+
priority: number().int().min(1).max(5).default(3),
|
|
16426
|
+
level: string().optional(),
|
|
16427
|
+
attachments: array(AttachmentSchema).optional(),
|
|
16428
|
+
clickUrl: string().optional(),
|
|
16429
|
+
actions: array(NotificationActionSchema).optional(),
|
|
16430
|
+
sound: string().optional(),
|
|
16431
|
+
ttl: number().optional(),
|
|
16432
|
+
tag: string().optional(),
|
|
16350
16433
|
deviceId: number().optional(),
|
|
16351
16434
|
eventId: string().optional(),
|
|
16352
|
-
priority: _enum([
|
|
16353
|
-
"low",
|
|
16354
|
-
"normal",
|
|
16355
|
-
"high",
|
|
16356
|
-
"critical"
|
|
16357
|
-
]).default("normal"),
|
|
16358
16435
|
metadata: record(string(), unknown()).optional()
|
|
16359
|
-
})
|
|
16436
|
+
});
|
|
16437
|
+
/** One declared native severity/priority level for a kind. */
|
|
16438
|
+
var TargetKindLevelSchema = object({
|
|
16439
|
+
id: string(),
|
|
16440
|
+
label: string(),
|
|
16441
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
16442
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
16443
|
+
flags: object({
|
|
16444
|
+
critical: boolean().optional(),
|
|
16445
|
+
silent: boolean().optional(),
|
|
16446
|
+
noPush: boolean().optional()
|
|
16447
|
+
}).optional(),
|
|
16448
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
16449
|
+
requires: array(string()).optional(),
|
|
16450
|
+
description: string().optional()
|
|
16451
|
+
});
|
|
16452
|
+
/** The full capability block consulted before dispatch. */
|
|
16453
|
+
var TargetKindCapsSchema = object({
|
|
16454
|
+
attachments: object({
|
|
16455
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
16456
|
+
mode: _enum([
|
|
16457
|
+
"url",
|
|
16458
|
+
"bytes",
|
|
16459
|
+
"both"
|
|
16460
|
+
]),
|
|
16461
|
+
max: number().int().nonnegative(),
|
|
16462
|
+
maxBytes: number().int().positive().optional()
|
|
16463
|
+
}),
|
|
16464
|
+
/** Max action buttons (0 = none). */
|
|
16465
|
+
actions: number().int().nonnegative(),
|
|
16466
|
+
levels: array(TargetKindLevelSchema),
|
|
16467
|
+
format: array(NotificationFormatSchema),
|
|
16468
|
+
clickUrl: boolean(),
|
|
16469
|
+
sound: boolean(),
|
|
16470
|
+
ttl: boolean(),
|
|
16471
|
+
bodyMaxLen: number().int().positive()
|
|
16472
|
+
});
|
|
16473
|
+
/**
|
|
16474
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
16475
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
16476
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
16477
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
16478
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
16479
|
+
*/
|
|
16480
|
+
var ConfigSchemaPassthrough = unknown();
|
|
16481
|
+
var TargetKindSchema = object({
|
|
16482
|
+
kind: string(),
|
|
16483
|
+
label: string(),
|
|
16484
|
+
icon: string(),
|
|
16485
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
16486
|
+
addonId: string(),
|
|
16487
|
+
configSchema: ConfigSchemaPassthrough,
|
|
16488
|
+
supportsDiscovery: boolean(),
|
|
16489
|
+
caps: TargetKindCapsSchema
|
|
16490
|
+
});
|
|
16491
|
+
/**
|
|
16492
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
16493
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
16494
|
+
* round-trip a stored secret to the UI.
|
|
16495
|
+
*/
|
|
16496
|
+
var TargetSchema = object({
|
|
16497
|
+
id: string(),
|
|
16498
|
+
name: string(),
|
|
16499
|
+
kind: string(),
|
|
16500
|
+
addonId: string(),
|
|
16501
|
+
enabled: boolean(),
|
|
16502
|
+
config: record(string(), unknown())
|
|
16503
|
+
});
|
|
16504
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
16505
|
+
var DiscoveredTargetSchema = object({
|
|
16506
|
+
kind: string(),
|
|
16507
|
+
suggestedName: string(),
|
|
16508
|
+
config: record(string(), unknown())
|
|
16509
|
+
});
|
|
16510
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
16511
|
+
var RenderedAsSchema = object({
|
|
16512
|
+
level: string(),
|
|
16513
|
+
format: NotificationFormatSchema,
|
|
16514
|
+
attachmentsSent: number().int().nonnegative(),
|
|
16515
|
+
actionsSent: number().int().nonnegative(),
|
|
16516
|
+
truncated: boolean(),
|
|
16517
|
+
dropped: array(string())
|
|
16518
|
+
});
|
|
16519
|
+
var SendResultSchema = object({
|
|
16360
16520
|
success: boolean(),
|
|
16361
|
-
error: string().optional()
|
|
16362
|
-
|
|
16521
|
+
error: string().optional(),
|
|
16522
|
+
renderedAs: RenderedAsSchema.optional()
|
|
16523
|
+
});
|
|
16524
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
16525
|
+
var TestResultSchema = SendResultSchema;
|
|
16526
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
|
|
16527
|
+
kind: string(),
|
|
16528
|
+
config: record(string(), unknown()).optional()
|
|
16529
|
+
}), array(DiscoveredTargetSchema)), method(object({
|
|
16530
|
+
targetId: string(),
|
|
16531
|
+
notification: NotificationSchema
|
|
16532
|
+
}), SendResultSchema, { kind: "mutation" }), method(object({
|
|
16533
|
+
targetId: string(),
|
|
16534
|
+
sample: NotificationSchema.optional()
|
|
16535
|
+
}), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
16536
|
+
targetId: string(),
|
|
16537
|
+
enabled: boolean()
|
|
16538
|
+
}), _void(), { kind: "mutation" });
|
|
16363
16539
|
/**
|
|
16364
16540
|
* Zod schemas for persisted record types.
|
|
16365
16541
|
*
|
|
@@ -22726,13 +22902,49 @@ Object.freeze({
|
|
|
22726
22902
|
addonId: null,
|
|
22727
22903
|
access: "create"
|
|
22728
22904
|
},
|
|
22905
|
+
"notificationOutput.deleteTarget": {
|
|
22906
|
+
capName: "notification-output",
|
|
22907
|
+
capScope: "system",
|
|
22908
|
+
addonId: null,
|
|
22909
|
+
access: "delete"
|
|
22910
|
+
},
|
|
22911
|
+
"notificationOutput.discoverTargets": {
|
|
22912
|
+
capName: "notification-output",
|
|
22913
|
+
capScope: "system",
|
|
22914
|
+
addonId: null,
|
|
22915
|
+
access: "view"
|
|
22916
|
+
},
|
|
22917
|
+
"notificationOutput.listTargetKinds": {
|
|
22918
|
+
capName: "notification-output",
|
|
22919
|
+
capScope: "system",
|
|
22920
|
+
addonId: null,
|
|
22921
|
+
access: "view"
|
|
22922
|
+
},
|
|
22923
|
+
"notificationOutput.listTargets": {
|
|
22924
|
+
capName: "notification-output",
|
|
22925
|
+
capScope: "system",
|
|
22926
|
+
addonId: null,
|
|
22927
|
+
access: "view"
|
|
22928
|
+
},
|
|
22729
22929
|
"notificationOutput.send": {
|
|
22730
22930
|
capName: "notification-output",
|
|
22731
22931
|
capScope: "system",
|
|
22732
22932
|
addonId: null,
|
|
22733
22933
|
access: "create"
|
|
22734
22934
|
},
|
|
22735
|
-
"notificationOutput.
|
|
22935
|
+
"notificationOutput.setTargetEnabled": {
|
|
22936
|
+
capName: "notification-output",
|
|
22937
|
+
capScope: "system",
|
|
22938
|
+
addonId: null,
|
|
22939
|
+
access: "create"
|
|
22940
|
+
},
|
|
22941
|
+
"notificationOutput.testTarget": {
|
|
22942
|
+
capName: "notification-output",
|
|
22943
|
+
capScope: "system",
|
|
22944
|
+
addonId: null,
|
|
22945
|
+
access: "create"
|
|
22946
|
+
},
|
|
22947
|
+
"notificationOutput.upsertTarget": {
|
|
22736
22948
|
capName: "notification-output",
|
|
22737
22949
|
capScope: "system",
|
|
22738
22950
|
addonId: null,
|
|
@@ -215216,7 +215428,7 @@ function isNativeObjectForwardingEnabled(capState) {
|
|
|
215216
215428
|
}
|
|
215217
215429
|
//#endregion
|
|
215218
215430
|
//#region src/stream-routing.ts
|
|
215219
|
-
var KIND_RE = /^(native|rtsp|rtmp):(.+)$/;
|
|
215431
|
+
var KIND_RE = /^(native|rtsp|rtmp|flv):(.+)$/;
|
|
215220
215432
|
var CH_PROFILE_RE = /^ch(\d+)-(main|sub|ext)$/;
|
|
215221
215433
|
var PROFILE_ONLY_RE = /^(main|sub|ext)$/;
|
|
215222
215434
|
/**
|
|
@@ -215266,6 +215478,7 @@ function kindLabel(kind) {
|
|
|
215266
215478
|
case "native": return "Native";
|
|
215267
215479
|
case "rtsp": return "RTSP";
|
|
215268
215480
|
case "rtmp": return "RTMP";
|
|
215481
|
+
case "flv": return "FLV";
|
|
215269
215482
|
}
|
|
215270
215483
|
}
|
|
215271
215484
|
/**
|
|
@@ -219152,6 +219365,23 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
219152
219365
|
}
|
|
219153
219366
|
}
|
|
219154
219367
|
/**
|
|
219368
|
+
* Synthesize the HTTP-FLV pull URL for a (channel, profile) pair. FLV is
|
|
219369
|
+
* served off the Reolink Baichuan media port (default 1935, app `bcs`) as
|
|
219370
|
+
* `channel<channel>_<profile>.bcs` — the same shape Frigate/go2rtc use. The
|
|
219371
|
+
* lib does NOT surface this URL, so we build it from the SAME connection
|
|
219372
|
+
* creds the RTSP/native paths use (`host`/`username`/`password` on the
|
|
219373
|
+
* device config), URL-encoding the credentials.
|
|
219374
|
+
*
|
|
219375
|
+
* Returns `null` when the host isn't locally resolvable (hub-child cameras
|
|
219376
|
+
* borrow the parent's socket and hold no own `host`), so the caller skips
|
|
219377
|
+
* FLV publication for those devices rather than emitting a broken URL.
|
|
219378
|
+
*/
|
|
219379
|
+
buildFlvUrl(channel, profile) {
|
|
219380
|
+
const host = this.config.get("host");
|
|
219381
|
+
if (typeof host !== "string" || host.length === 0) return null;
|
|
219382
|
+
return `http://${host}/flv?port=1935&app=bcs&stream=channel${channel}_${profile}.bcs&user=${encodeURIComponent(String(this.config.get("username") ?? ""))}&password=${encodeURIComponent(String(this.config.get("password") ?? ""))}`;
|
|
219383
|
+
}
|
|
219384
|
+
/**
|
|
219155
219385
|
* Heavy path: talk to the camera and assemble the descriptors. Only ever
|
|
219156
219386
|
* entered when there is no cached catalog (see `buildStreamCatalog`).
|
|
219157
219387
|
*
|
|
@@ -219237,6 +219467,27 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
|
|
|
219237
219467
|
};
|
|
219238
219468
|
enqueueAlt("rtsp", streamOptions.rtspStreams);
|
|
219239
219469
|
enqueueAlt("rtmp", streamOptions.rtmpStreams);
|
|
219470
|
+
for (const s of streamOptions.nativeStreams) {
|
|
219471
|
+
const channel = s.channel ?? (isChild ? ownChannel : 0);
|
|
219472
|
+
const id = buildCamStreamId("flv", channel, s.profile, channelCount);
|
|
219473
|
+
if (desired.has(id)) continue;
|
|
219474
|
+
const flvUrl = this.buildFlvUrl(channel, s.profile);
|
|
219475
|
+
if (!flvUrl) break;
|
|
219476
|
+
const m = s.metadata;
|
|
219477
|
+
desired.set(id, {
|
|
219478
|
+
camStreamId: id,
|
|
219479
|
+
kind: "pull-flv",
|
|
219480
|
+
label: streamLabel(s, "flv"),
|
|
219481
|
+
url: flvUrl,
|
|
219482
|
+
autoEligible: false,
|
|
219483
|
+
...m && m.width > 0 && m.height > 0 ? { resolution: {
|
|
219484
|
+
width: m.width,
|
|
219485
|
+
height: m.height
|
|
219486
|
+
} } : {},
|
|
219487
|
+
...m && m.frameRate > 0 ? { fps: m.frameRate } : {},
|
|
219488
|
+
...normalizeCodecName(m?.videoEncType) ? { codec: normalizeCodecName(m?.videoEncType) } : {}
|
|
219489
|
+
});
|
|
219490
|
+
}
|
|
219240
219491
|
if (desired.size === 0) {
|
|
219241
219492
|
this.ctx.logger.warn("buildStreamCatalog: camera reports no streams — empty catalog", { tags: { deviceId: this.id } });
|
|
219242
219493
|
return [];
|