@camstack/addon-static-turn 1.1.12 → 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.
@@ -4628,7 +4628,7 @@ function _instanceof(cls, params = {}) {
4628
4628
  return inst;
4629
4629
  }
4630
4630
  //#endregion
4631
- //#region ../types/dist/sleep-C2M2zF7x.mjs
4631
+ //#region ../types/dist/sleep-MHm--th-.mjs
4632
4632
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4633
4633
  EventCategory["SystemBoot"] = "system.boot";
4634
4634
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5890,6 +5890,7 @@ var CamStreamKindSchema = _enum([
5890
5890
  "pull-rtsp",
5891
5891
  "pull-rtmp",
5892
5892
  "pull-http",
5893
+ "pull-flv",
5893
5894
  "pull-rfc4571",
5894
5895
  "push-annexb",
5895
5896
  "derived"
@@ -7033,7 +7034,21 @@ var StorageLocationDeclarationSchema = object({
7033
7034
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
7034
7035
  * configure the primary location.
7035
7036
  */
7036
- defaultsTo: string().optional()
7037
+ defaultsTo: string().optional(),
7038
+ /**
7039
+ * Which node root the seeded `<id>:default` instance is placed under on a
7040
+ * FRESH install:
7041
+ * - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
7042
+ * the appData volume. Right for small/durable data (backups, logs, models).
7043
+ * - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
7044
+ * env is set, else falls back to the data root. Right for bulky, hot media
7045
+ * (recordings, event media) that should stay off the appData disk.
7046
+ *
7047
+ * Only affects the seeded default's `basePath`; operators can repoint any
7048
+ * location afterwards, and a `defaultsTo` slot inherits its parent's root
7049
+ * regardless of this field. Absent (the common case) is treated as `'data'`.
7050
+ */
7051
+ defaultRoot: _enum(["data", "media"]).optional()
7037
7052
  });
7038
7053
  var DecoderStatsSchema = object({
7039
7054
  inputFps: number(),
@@ -7880,6 +7895,10 @@ var RtspRestreamEntrySchema = object({
7880
7895
  var BrokerRtspClientSchema = object({
7881
7896
  sessionId: string(),
7882
7897
  remoteAddr: string(),
7898
+ /** Client `User-Agent` (e.g. `recorder` for the recorder's RTSP pull), or
7899
+ * null/absent when the client sent none. Lets the UI label a consumer by
7900
+ * purpose. Optional so a client built against an older schema stays valid. */
7901
+ userAgent: string().nullish(),
7883
7902
  playing: boolean(),
7884
7903
  muted: boolean(),
7885
7904
  connectedAt: number(),
@@ -13169,7 +13188,7 @@ var AddBrokerInputSchema = object({
13169
13188
  });
13170
13189
  var AddBrokerResultSchema = object({ id: string() });
13171
13190
  var IdInputSchema = object({ id: string() });
13172
- var TestResultSchema = discriminatedUnion("ok", [object({
13191
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13173
13192
  ok: literal(true),
13174
13193
  latencyMs: number()
13175
13194
  }), object({
@@ -13192,7 +13211,7 @@ var StatusSchema = object({
13192
13211
  brokerCount: number(),
13193
13212
  embeddedRunning: boolean()
13194
13213
  });
13195
- 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);
13214
+ 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);
13196
13215
  var NetworkEndpointSchema = object({
13197
13216
  url: string(),
13198
13217
  hostname: string(),
@@ -13226,23 +13245,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
13226
13245
  sourcePort: number().optional()
13227
13246
  });
13228
13247
  method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
13229
- method(object({
13230
- title: string(),
13248
+ /**
13249
+ * notification-output — canonical, capability-gated notification delivery.
13250
+ *
13251
+ * Apprise-derived model (see
13252
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13253
+ * callers emit ONE canonical `Notification`; each provider declares a
13254
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13255
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13256
+ * message to what the kind supports — callers never special-case a service.
13257
+ *
13258
+ * DESIGN DECISIONS (locked):
13259
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13260
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13261
+ * cap. Rationale: the admin UI needs one uniform surface across the
13262
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13263
+ * alternative would fork the UI per addon and cannot host the
13264
+ * discovery→adopt flow.
13265
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13266
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13267
+ * registered provider (notifiers addon + HA addon) so one catalog is
13268
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13269
+ * `addonId` the generated collection router extracts from the call input.
13270
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13271
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13272
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13273
+ * base64 fallback needed.
13274
+ *
13275
+ * TODO (deferred, closed-set change — separate decision): add
13276
+ * `providerKind: 'notify'` so notification providers surface on the unified
13277
+ * admin "Integrations" page.
13278
+ */
13279
+ /**
13280
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13281
+ * adapter picks what it supports and the degrade engine filters the rest.
13282
+ */
13283
+ var AttachmentMediaTypeSchema = _enum([
13284
+ "image",
13285
+ "video",
13286
+ "gif",
13287
+ "audio",
13288
+ "icon"
13289
+ ]);
13290
+ /**
13291
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13292
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13293
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13294
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13295
+ */
13296
+ var AttachmentSchema = object({
13297
+ mediaType: AttachmentMediaTypeSchema,
13298
+ url: string().optional(),
13299
+ bytes: _instanceof(Uint8Array).optional(),
13300
+ mime: string().optional(),
13301
+ name: string().optional()
13302
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13303
+ var NotificationFormatSchema = _enum([
13304
+ "text",
13305
+ "markdown",
13306
+ "html"
13307
+ ]);
13308
+ /** A single tap-through action button. */
13309
+ var NotificationActionSchema = object({
13310
+ id: string(),
13311
+ label: string(),
13312
+ url: string().optional()
13313
+ });
13314
+ /**
13315
+ * The canonical notification. `body` is the only hard field (Apprise model).
13316
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13317
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13318
+ * the adapter maps this ordinal onto its native level. `level?` is an
13319
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13320
+ * `priority` for that one target.
13321
+ */
13322
+ var NotificationSchema = object({
13231
13323
  body: string(),
13232
- imageUrl: string().optional(),
13324
+ title: string().optional(),
13325
+ format: NotificationFormatSchema.default("text"),
13326
+ priority: number().int().min(1).max(5).default(3),
13327
+ level: string().optional(),
13328
+ attachments: array(AttachmentSchema).optional(),
13329
+ clickUrl: string().optional(),
13330
+ actions: array(NotificationActionSchema).optional(),
13331
+ sound: string().optional(),
13332
+ ttl: number().optional(),
13333
+ tag: string().optional(),
13233
13334
  deviceId: number().optional(),
13234
13335
  eventId: string().optional(),
13235
- priority: _enum([
13236
- "low",
13237
- "normal",
13238
- "high",
13239
- "critical"
13240
- ]).default("normal"),
13241
13336
  metadata: record(string(), unknown()).optional()
13242
- }), _void(), { kind: "mutation" }), method(_void(), object({
13337
+ });
13338
+ /** One declared native severity/priority level for a kind. */
13339
+ var TargetKindLevelSchema = object({
13340
+ id: string(),
13341
+ label: string(),
13342
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13343
+ ordinal: number().int().min(1).max(5).nullable(),
13344
+ flags: object({
13345
+ critical: boolean().optional(),
13346
+ silent: boolean().optional(),
13347
+ noPush: boolean().optional()
13348
+ }).optional(),
13349
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13350
+ requires: array(string()).optional(),
13351
+ description: string().optional()
13352
+ });
13353
+ /** The full capability block consulted before dispatch. */
13354
+ var TargetKindCapsSchema = object({
13355
+ attachments: object({
13356
+ mediaTypes: array(AttachmentMediaTypeSchema),
13357
+ mode: _enum([
13358
+ "url",
13359
+ "bytes",
13360
+ "both"
13361
+ ]),
13362
+ max: number().int().nonnegative(),
13363
+ maxBytes: number().int().positive().optional()
13364
+ }),
13365
+ /** Max action buttons (0 = none). */
13366
+ actions: number().int().nonnegative(),
13367
+ levels: array(TargetKindLevelSchema),
13368
+ format: array(NotificationFormatSchema),
13369
+ clickUrl: boolean(),
13370
+ sound: boolean(),
13371
+ ttl: boolean(),
13372
+ bodyMaxLen: number().int().positive()
13373
+ });
13374
+ /**
13375
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13376
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13377
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13378
+ * the union is large and not meant for runtime validation here; the exported
13379
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13380
+ */
13381
+ var ConfigSchemaPassthrough = unknown();
13382
+ var TargetKindSchema = object({
13383
+ kind: string(),
13384
+ label: string(),
13385
+ icon: string(),
13386
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13387
+ addonId: string(),
13388
+ configSchema: ConfigSchemaPassthrough,
13389
+ supportsDiscovery: boolean(),
13390
+ caps: TargetKindCapsSchema
13391
+ });
13392
+ /**
13393
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13394
+ * (return a presence marker only) when serving `listTargets` — never
13395
+ * round-trip a stored secret to the UI.
13396
+ */
13397
+ var TargetSchema = object({
13398
+ id: string(),
13399
+ name: string(),
13400
+ kind: string(),
13401
+ addonId: string(),
13402
+ enabled: boolean(),
13403
+ config: record(string(), unknown())
13404
+ });
13405
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13406
+ var DiscoveredTargetSchema = object({
13407
+ kind: string(),
13408
+ suggestedName: string(),
13409
+ config: record(string(), unknown())
13410
+ });
13411
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13412
+ var RenderedAsSchema = object({
13413
+ level: string(),
13414
+ format: NotificationFormatSchema,
13415
+ attachmentsSent: number().int().nonnegative(),
13416
+ actionsSent: number().int().nonnegative(),
13417
+ truncated: boolean(),
13418
+ dropped: array(string())
13419
+ });
13420
+ var SendResultSchema = object({
13243
13421
  success: boolean(),
13244
- error: string().optional()
13245
- }), { kind: "mutation" });
13422
+ error: string().optional(),
13423
+ renderedAs: RenderedAsSchema.optional()
13424
+ });
13425
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13426
+ var TestResultSchema = SendResultSchema;
13427
+ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
13428
+ kind: string(),
13429
+ config: record(string(), unknown()).optional()
13430
+ }), array(DiscoveredTargetSchema)), method(object({
13431
+ targetId: string(),
13432
+ notification: NotificationSchema
13433
+ }), SendResultSchema, { kind: "mutation" }), method(object({
13434
+ targetId: string(),
13435
+ sample: NotificationSchema.optional()
13436
+ }), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
13437
+ targetId: string(),
13438
+ enabled: boolean()
13439
+ }), _void(), { kind: "mutation" });
13246
13440
  /**
13247
13441
  * Zod schemas for persisted record types.
13248
13442
  *
@@ -19260,13 +19454,49 @@ Object.freeze({
19260
19454
  addonId: null,
19261
19455
  access: "create"
19262
19456
  },
19457
+ "notificationOutput.deleteTarget": {
19458
+ capName: "notification-output",
19459
+ capScope: "system",
19460
+ addonId: null,
19461
+ access: "delete"
19462
+ },
19463
+ "notificationOutput.discoverTargets": {
19464
+ capName: "notification-output",
19465
+ capScope: "system",
19466
+ addonId: null,
19467
+ access: "view"
19468
+ },
19469
+ "notificationOutput.listTargetKinds": {
19470
+ capName: "notification-output",
19471
+ capScope: "system",
19472
+ addonId: null,
19473
+ access: "view"
19474
+ },
19475
+ "notificationOutput.listTargets": {
19476
+ capName: "notification-output",
19477
+ capScope: "system",
19478
+ addonId: null,
19479
+ access: "view"
19480
+ },
19263
19481
  "notificationOutput.send": {
19264
19482
  capName: "notification-output",
19265
19483
  capScope: "system",
19266
19484
  addonId: null,
19267
19485
  access: "create"
19268
19486
  },
19269
- "notificationOutput.sendTest": {
19487
+ "notificationOutput.setTargetEnabled": {
19488
+ capName: "notification-output",
19489
+ capScope: "system",
19490
+ addonId: null,
19491
+ access: "create"
19492
+ },
19493
+ "notificationOutput.testTarget": {
19494
+ capName: "notification-output",
19495
+ capScope: "system",
19496
+ addonId: null,
19497
+ access: "create"
19498
+ },
19499
+ "notificationOutput.upsertTarget": {
19270
19500
  capName: "notification-output",
19271
19501
  capScope: "system",
19272
19502
  addonId: null,
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
4627
4627
  return inst;
4628
4628
  }
4629
4629
  //#endregion
4630
- //#region ../types/dist/sleep-C2M2zF7x.mjs
4630
+ //#region ../types/dist/sleep-MHm--th-.mjs
4631
4631
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4632
4632
  EventCategory["SystemBoot"] = "system.boot";
4633
4633
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5889,6 +5889,7 @@ var CamStreamKindSchema = _enum([
5889
5889
  "pull-rtsp",
5890
5890
  "pull-rtmp",
5891
5891
  "pull-http",
5892
+ "pull-flv",
5892
5893
  "pull-rfc4571",
5893
5894
  "push-annexb",
5894
5895
  "derived"
@@ -7032,7 +7033,21 @@ var StorageLocationDeclarationSchema = object({
7032
7033
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
7033
7034
  * configure the primary location.
7034
7035
  */
7035
- defaultsTo: string().optional()
7036
+ defaultsTo: string().optional(),
7037
+ /**
7038
+ * Which node root the seeded `<id>:default` instance is placed under on a
7039
+ * FRESH install:
7040
+ * - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
7041
+ * the appData volume. Right for small/durable data (backups, logs, models).
7042
+ * - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
7043
+ * env is set, else falls back to the data root. Right for bulky, hot media
7044
+ * (recordings, event media) that should stay off the appData disk.
7045
+ *
7046
+ * Only affects the seeded default's `basePath`; operators can repoint any
7047
+ * location afterwards, and a `defaultsTo` slot inherits its parent's root
7048
+ * regardless of this field. Absent (the common case) is treated as `'data'`.
7049
+ */
7050
+ defaultRoot: _enum(["data", "media"]).optional()
7036
7051
  });
7037
7052
  var DecoderStatsSchema = object({
7038
7053
  inputFps: number(),
@@ -7879,6 +7894,10 @@ var RtspRestreamEntrySchema = object({
7879
7894
  var BrokerRtspClientSchema = object({
7880
7895
  sessionId: string(),
7881
7896
  remoteAddr: string(),
7897
+ /** Client `User-Agent` (e.g. `recorder` for the recorder's RTSP pull), or
7898
+ * null/absent when the client sent none. Lets the UI label a consumer by
7899
+ * purpose. Optional so a client built against an older schema stays valid. */
7900
+ userAgent: string().nullish(),
7882
7901
  playing: boolean(),
7883
7902
  muted: boolean(),
7884
7903
  connectedAt: number(),
@@ -13168,7 +13187,7 @@ var AddBrokerInputSchema = object({
13168
13187
  });
13169
13188
  var AddBrokerResultSchema = object({ id: string() });
13170
13189
  var IdInputSchema = object({ id: string() });
13171
- var TestResultSchema = discriminatedUnion("ok", [object({
13190
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13172
13191
  ok: literal(true),
13173
13192
  latencyMs: number()
13174
13193
  }), object({
@@ -13191,7 +13210,7 @@ var StatusSchema = object({
13191
13210
  brokerCount: number(),
13192
13211
  embeddedRunning: boolean()
13193
13212
  });
13194
- 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);
13213
+ 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);
13195
13214
  var NetworkEndpointSchema = object({
13196
13215
  url: string(),
13197
13216
  hostname: string(),
@@ -13225,23 +13244,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
13225
13244
  sourcePort: number().optional()
13226
13245
  });
13227
13246
  method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
13228
- method(object({
13229
- title: string(),
13247
+ /**
13248
+ * notification-output — canonical, capability-gated notification delivery.
13249
+ *
13250
+ * Apprise-derived model (see
13251
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13252
+ * callers emit ONE canonical `Notification`; each provider declares a
13253
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13254
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13255
+ * message to what the kind supports — callers never special-case a service.
13256
+ *
13257
+ * DESIGN DECISIONS (locked):
13258
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13259
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13260
+ * cap. Rationale: the admin UI needs one uniform surface across the
13261
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13262
+ * alternative would fork the UI per addon and cannot host the
13263
+ * discovery→adopt flow.
13264
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13265
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13266
+ * registered provider (notifiers addon + HA addon) so one catalog is
13267
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13268
+ * `addonId` the generated collection router extracts from the call input.
13269
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13270
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13271
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13272
+ * base64 fallback needed.
13273
+ *
13274
+ * TODO (deferred, closed-set change — separate decision): add
13275
+ * `providerKind: 'notify'` so notification providers surface on the unified
13276
+ * admin "Integrations" page.
13277
+ */
13278
+ /**
13279
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13280
+ * adapter picks what it supports and the degrade engine filters the rest.
13281
+ */
13282
+ var AttachmentMediaTypeSchema = _enum([
13283
+ "image",
13284
+ "video",
13285
+ "gif",
13286
+ "audio",
13287
+ "icon"
13288
+ ]);
13289
+ /**
13290
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13291
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13292
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13293
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13294
+ */
13295
+ var AttachmentSchema = object({
13296
+ mediaType: AttachmentMediaTypeSchema,
13297
+ url: string().optional(),
13298
+ bytes: _instanceof(Uint8Array).optional(),
13299
+ mime: string().optional(),
13300
+ name: string().optional()
13301
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13302
+ var NotificationFormatSchema = _enum([
13303
+ "text",
13304
+ "markdown",
13305
+ "html"
13306
+ ]);
13307
+ /** A single tap-through action button. */
13308
+ var NotificationActionSchema = object({
13309
+ id: string(),
13310
+ label: string(),
13311
+ url: string().optional()
13312
+ });
13313
+ /**
13314
+ * The canonical notification. `body` is the only hard field (Apprise model).
13315
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13316
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13317
+ * the adapter maps this ordinal onto its native level. `level?` is an
13318
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13319
+ * `priority` for that one target.
13320
+ */
13321
+ var NotificationSchema = object({
13230
13322
  body: string(),
13231
- imageUrl: string().optional(),
13323
+ title: string().optional(),
13324
+ format: NotificationFormatSchema.default("text"),
13325
+ priority: number().int().min(1).max(5).default(3),
13326
+ level: string().optional(),
13327
+ attachments: array(AttachmentSchema).optional(),
13328
+ clickUrl: string().optional(),
13329
+ actions: array(NotificationActionSchema).optional(),
13330
+ sound: string().optional(),
13331
+ ttl: number().optional(),
13332
+ tag: string().optional(),
13232
13333
  deviceId: number().optional(),
13233
13334
  eventId: string().optional(),
13234
- priority: _enum([
13235
- "low",
13236
- "normal",
13237
- "high",
13238
- "critical"
13239
- ]).default("normal"),
13240
13335
  metadata: record(string(), unknown()).optional()
13241
- }), _void(), { kind: "mutation" }), method(_void(), object({
13336
+ });
13337
+ /** One declared native severity/priority level for a kind. */
13338
+ var TargetKindLevelSchema = object({
13339
+ id: string(),
13340
+ label: string(),
13341
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13342
+ ordinal: number().int().min(1).max(5).nullable(),
13343
+ flags: object({
13344
+ critical: boolean().optional(),
13345
+ silent: boolean().optional(),
13346
+ noPush: boolean().optional()
13347
+ }).optional(),
13348
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13349
+ requires: array(string()).optional(),
13350
+ description: string().optional()
13351
+ });
13352
+ /** The full capability block consulted before dispatch. */
13353
+ var TargetKindCapsSchema = object({
13354
+ attachments: object({
13355
+ mediaTypes: array(AttachmentMediaTypeSchema),
13356
+ mode: _enum([
13357
+ "url",
13358
+ "bytes",
13359
+ "both"
13360
+ ]),
13361
+ max: number().int().nonnegative(),
13362
+ maxBytes: number().int().positive().optional()
13363
+ }),
13364
+ /** Max action buttons (0 = none). */
13365
+ actions: number().int().nonnegative(),
13366
+ levels: array(TargetKindLevelSchema),
13367
+ format: array(NotificationFormatSchema),
13368
+ clickUrl: boolean(),
13369
+ sound: boolean(),
13370
+ ttl: boolean(),
13371
+ bodyMaxLen: number().int().positive()
13372
+ });
13373
+ /**
13374
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13375
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13376
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13377
+ * the union is large and not meant for runtime validation here; the exported
13378
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13379
+ */
13380
+ var ConfigSchemaPassthrough = unknown();
13381
+ var TargetKindSchema = object({
13382
+ kind: string(),
13383
+ label: string(),
13384
+ icon: string(),
13385
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13386
+ addonId: string(),
13387
+ configSchema: ConfigSchemaPassthrough,
13388
+ supportsDiscovery: boolean(),
13389
+ caps: TargetKindCapsSchema
13390
+ });
13391
+ /**
13392
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13393
+ * (return a presence marker only) when serving `listTargets` — never
13394
+ * round-trip a stored secret to the UI.
13395
+ */
13396
+ var TargetSchema = object({
13397
+ id: string(),
13398
+ name: string(),
13399
+ kind: string(),
13400
+ addonId: string(),
13401
+ enabled: boolean(),
13402
+ config: record(string(), unknown())
13403
+ });
13404
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13405
+ var DiscoveredTargetSchema = object({
13406
+ kind: string(),
13407
+ suggestedName: string(),
13408
+ config: record(string(), unknown())
13409
+ });
13410
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13411
+ var RenderedAsSchema = object({
13412
+ level: string(),
13413
+ format: NotificationFormatSchema,
13414
+ attachmentsSent: number().int().nonnegative(),
13415
+ actionsSent: number().int().nonnegative(),
13416
+ truncated: boolean(),
13417
+ dropped: array(string())
13418
+ });
13419
+ var SendResultSchema = object({
13242
13420
  success: boolean(),
13243
- error: string().optional()
13244
- }), { kind: "mutation" });
13421
+ error: string().optional(),
13422
+ renderedAs: RenderedAsSchema.optional()
13423
+ });
13424
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13425
+ var TestResultSchema = SendResultSchema;
13426
+ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
13427
+ kind: string(),
13428
+ config: record(string(), unknown()).optional()
13429
+ }), array(DiscoveredTargetSchema)), method(object({
13430
+ targetId: string(),
13431
+ notification: NotificationSchema
13432
+ }), SendResultSchema, { kind: "mutation" }), method(object({
13433
+ targetId: string(),
13434
+ sample: NotificationSchema.optional()
13435
+ }), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
13436
+ targetId: string(),
13437
+ enabled: boolean()
13438
+ }), _void(), { kind: "mutation" });
13245
13439
  /**
13246
13440
  * Zod schemas for persisted record types.
13247
13441
  *
@@ -19259,13 +19453,49 @@ Object.freeze({
19259
19453
  addonId: null,
19260
19454
  access: "create"
19261
19455
  },
19456
+ "notificationOutput.deleteTarget": {
19457
+ capName: "notification-output",
19458
+ capScope: "system",
19459
+ addonId: null,
19460
+ access: "delete"
19461
+ },
19462
+ "notificationOutput.discoverTargets": {
19463
+ capName: "notification-output",
19464
+ capScope: "system",
19465
+ addonId: null,
19466
+ access: "view"
19467
+ },
19468
+ "notificationOutput.listTargetKinds": {
19469
+ capName: "notification-output",
19470
+ capScope: "system",
19471
+ addonId: null,
19472
+ access: "view"
19473
+ },
19474
+ "notificationOutput.listTargets": {
19475
+ capName: "notification-output",
19476
+ capScope: "system",
19477
+ addonId: null,
19478
+ access: "view"
19479
+ },
19262
19480
  "notificationOutput.send": {
19263
19481
  capName: "notification-output",
19264
19482
  capScope: "system",
19265
19483
  addonId: null,
19266
19484
  access: "create"
19267
19485
  },
19268
- "notificationOutput.sendTest": {
19486
+ "notificationOutput.setTargetEnabled": {
19487
+ capName: "notification-output",
19488
+ capScope: "system",
19489
+ addonId: null,
19490
+ access: "create"
19491
+ },
19492
+ "notificationOutput.testTarget": {
19493
+ capName: "notification-output",
19494
+ capScope: "system",
19495
+ addonId: null,
19496
+ access: "create"
19497
+ },
19498
+ "notificationOutput.upsertTarget": {
19269
19499
  capName: "notification-output",
19270
19500
  capScope: "system",
19271
19501
  addonId: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-static-turn",
3
- "version": "1.1.12",
3
+ "version": "1.1.14",
4
4
  "description": "Static / self-hosted (coturn) TURN provider for CamStack",
5
5
  "keywords": [
6
6
  "camstack",
@@ -37,7 +37,8 @@
37
37
  "version": "1.0.0",
38
38
  "entry": "./dist/static-turn.addon.js",
39
39
  "execution": {
40
- "placement": "hub-only"
40
+ "placement": "hub-only",
41
+ "group": "net-access"
41
42
  },
42
43
  "capabilities": [
43
44
  {