@camstack/addon-tailscale 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.
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-eH91demF.js");
27
+ const require_dist = require("../dist-fx1JMLox.js");
28
28
  let node_child_process = require("node:child_process");
29
29
  let node_util = require("node:util");
30
30
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { i as EventCategory, n as networkAccessCapability, r as BaseAddon, t as meshNetworkCapability } from "../dist-CfULNCIt.mjs";
1
+ import { i as EventCategory, n as networkAccessCapability, r as BaseAddon, t as meshNetworkCapability } from "../dist-Cv7JkzHN.mjs";
2
2
  import { execFile, spawn } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as fs from "node:fs";
@@ -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"
@@ -13186,7 +13187,7 @@ var AddBrokerInputSchema = object({
13186
13187
  });
13187
13188
  var AddBrokerResultSchema = object({ id: string() });
13188
13189
  var IdInputSchema = object({ id: string() });
13189
- var TestResultSchema = discriminatedUnion("ok", [object({
13190
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13190
13191
  ok: literal(true),
13191
13192
  latencyMs: number()
13192
13193
  }), object({
@@ -13209,7 +13210,7 @@ var StatusSchema = object({
13209
13210
  brokerCount: number(),
13210
13211
  embeddedRunning: boolean()
13211
13212
  });
13212
- 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);
13213
13214
  var NetworkEndpointSchema = object({
13214
13215
  url: string(),
13215
13216
  hostname: string(),
@@ -13260,23 +13261,198 @@ var networkAccessCapability = {
13260
13261
  listEndpoints: method(_void(), array(NetworkEndpointEntrySchema).readonly())
13261
13262
  }
13262
13263
  };
13263
- method(object({
13264
- title: string(),
13264
+ /**
13265
+ * notification-output — canonical, capability-gated notification delivery.
13266
+ *
13267
+ * Apprise-derived model (see
13268
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13269
+ * callers emit ONE canonical `Notification`; each provider declares a
13270
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13271
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13272
+ * message to what the kind supports — callers never special-case a service.
13273
+ *
13274
+ * DESIGN DECISIONS (locked):
13275
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13276
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13277
+ * cap. Rationale: the admin UI needs one uniform surface across the
13278
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13279
+ * alternative would fork the UI per addon and cannot host the
13280
+ * discovery→adopt flow.
13281
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13282
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13283
+ * registered provider (notifiers addon + HA addon) so one catalog is
13284
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13285
+ * `addonId` the generated collection router extracts from the call input.
13286
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13287
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13288
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13289
+ * base64 fallback needed.
13290
+ *
13291
+ * TODO (deferred, closed-set change — separate decision): add
13292
+ * `providerKind: 'notify'` so notification providers surface on the unified
13293
+ * admin "Integrations" page.
13294
+ */
13295
+ /**
13296
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13297
+ * adapter picks what it supports and the degrade engine filters the rest.
13298
+ */
13299
+ var AttachmentMediaTypeSchema = _enum([
13300
+ "image",
13301
+ "video",
13302
+ "gif",
13303
+ "audio",
13304
+ "icon"
13305
+ ]);
13306
+ /**
13307
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13308
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13309
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13310
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13311
+ */
13312
+ var AttachmentSchema = object({
13313
+ mediaType: AttachmentMediaTypeSchema,
13314
+ url: string().optional(),
13315
+ bytes: _instanceof(Uint8Array).optional(),
13316
+ mime: string().optional(),
13317
+ name: string().optional()
13318
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13319
+ var NotificationFormatSchema = _enum([
13320
+ "text",
13321
+ "markdown",
13322
+ "html"
13323
+ ]);
13324
+ /** A single tap-through action button. */
13325
+ var NotificationActionSchema = object({
13326
+ id: string(),
13327
+ label: string(),
13328
+ url: string().optional()
13329
+ });
13330
+ /**
13331
+ * The canonical notification. `body` is the only hard field (Apprise model).
13332
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13333
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13334
+ * the adapter maps this ordinal onto its native level. `level?` is an
13335
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13336
+ * `priority` for that one target.
13337
+ */
13338
+ var NotificationSchema = object({
13265
13339
  body: string(),
13266
- imageUrl: string().optional(),
13340
+ title: string().optional(),
13341
+ format: NotificationFormatSchema.default("text"),
13342
+ priority: number().int().min(1).max(5).default(3),
13343
+ level: string().optional(),
13344
+ attachments: array(AttachmentSchema).optional(),
13345
+ clickUrl: string().optional(),
13346
+ actions: array(NotificationActionSchema).optional(),
13347
+ sound: string().optional(),
13348
+ ttl: number().optional(),
13349
+ tag: string().optional(),
13267
13350
  deviceId: number().optional(),
13268
13351
  eventId: string().optional(),
13269
- priority: _enum([
13270
- "low",
13271
- "normal",
13272
- "high",
13273
- "critical"
13274
- ]).default("normal"),
13275
13352
  metadata: record(string(), unknown()).optional()
13276
- }), _void(), { kind: "mutation" }), method(_void(), object({
13353
+ });
13354
+ /** One declared native severity/priority level for a kind. */
13355
+ var TargetKindLevelSchema = object({
13356
+ id: string(),
13357
+ label: string(),
13358
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13359
+ ordinal: number().int().min(1).max(5).nullable(),
13360
+ flags: object({
13361
+ critical: boolean().optional(),
13362
+ silent: boolean().optional(),
13363
+ noPush: boolean().optional()
13364
+ }).optional(),
13365
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13366
+ requires: array(string()).optional(),
13367
+ description: string().optional()
13368
+ });
13369
+ /** The full capability block consulted before dispatch. */
13370
+ var TargetKindCapsSchema = object({
13371
+ attachments: object({
13372
+ mediaTypes: array(AttachmentMediaTypeSchema),
13373
+ mode: _enum([
13374
+ "url",
13375
+ "bytes",
13376
+ "both"
13377
+ ]),
13378
+ max: number().int().nonnegative(),
13379
+ maxBytes: number().int().positive().optional()
13380
+ }),
13381
+ /** Max action buttons (0 = none). */
13382
+ actions: number().int().nonnegative(),
13383
+ levels: array(TargetKindLevelSchema),
13384
+ format: array(NotificationFormatSchema),
13385
+ clickUrl: boolean(),
13386
+ sound: boolean(),
13387
+ ttl: boolean(),
13388
+ bodyMaxLen: number().int().positive()
13389
+ });
13390
+ /**
13391
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13392
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13393
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13394
+ * the union is large and not meant for runtime validation here; the exported
13395
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13396
+ */
13397
+ var ConfigSchemaPassthrough = unknown();
13398
+ var TargetKindSchema = object({
13399
+ kind: string(),
13400
+ label: string(),
13401
+ icon: string(),
13402
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13403
+ addonId: string(),
13404
+ configSchema: ConfigSchemaPassthrough,
13405
+ supportsDiscovery: boolean(),
13406
+ caps: TargetKindCapsSchema
13407
+ });
13408
+ /**
13409
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13410
+ * (return a presence marker only) when serving `listTargets` — never
13411
+ * round-trip a stored secret to the UI.
13412
+ */
13413
+ var TargetSchema = object({
13414
+ id: string(),
13415
+ name: string(),
13416
+ kind: string(),
13417
+ addonId: string(),
13418
+ enabled: boolean(),
13419
+ config: record(string(), unknown())
13420
+ });
13421
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13422
+ var DiscoveredTargetSchema = object({
13423
+ kind: string(),
13424
+ suggestedName: string(),
13425
+ config: record(string(), unknown())
13426
+ });
13427
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13428
+ var RenderedAsSchema = object({
13429
+ level: string(),
13430
+ format: NotificationFormatSchema,
13431
+ attachmentsSent: number().int().nonnegative(),
13432
+ actionsSent: number().int().nonnegative(),
13433
+ truncated: boolean(),
13434
+ dropped: array(string())
13435
+ });
13436
+ var SendResultSchema = object({
13277
13437
  success: boolean(),
13278
- error: string().optional()
13279
- }), { kind: "mutation" });
13438
+ error: string().optional(),
13439
+ renderedAs: RenderedAsSchema.optional()
13440
+ });
13441
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13442
+ var TestResultSchema = SendResultSchema;
13443
+ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
13444
+ kind: string(),
13445
+ config: record(string(), unknown()).optional()
13446
+ }), array(DiscoveredTargetSchema)), method(object({
13447
+ targetId: string(),
13448
+ notification: NotificationSchema
13449
+ }), SendResultSchema, { kind: "mutation" }), method(object({
13450
+ targetId: string(),
13451
+ sample: NotificationSchema.optional()
13452
+ }), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
13453
+ targetId: string(),
13454
+ enabled: boolean()
13455
+ }), _void(), { kind: "mutation" });
13280
13456
  /**
13281
13457
  * Zod schemas for persisted record types.
13282
13458
  *
@@ -19332,13 +19508,49 @@ Object.freeze({
19332
19508
  addonId: null,
19333
19509
  access: "create"
19334
19510
  },
19511
+ "notificationOutput.deleteTarget": {
19512
+ capName: "notification-output",
19513
+ capScope: "system",
19514
+ addonId: null,
19515
+ access: "delete"
19516
+ },
19517
+ "notificationOutput.discoverTargets": {
19518
+ capName: "notification-output",
19519
+ capScope: "system",
19520
+ addonId: null,
19521
+ access: "view"
19522
+ },
19523
+ "notificationOutput.listTargetKinds": {
19524
+ capName: "notification-output",
19525
+ capScope: "system",
19526
+ addonId: null,
19527
+ access: "view"
19528
+ },
19529
+ "notificationOutput.listTargets": {
19530
+ capName: "notification-output",
19531
+ capScope: "system",
19532
+ addonId: null,
19533
+ access: "view"
19534
+ },
19335
19535
  "notificationOutput.send": {
19336
19536
  capName: "notification-output",
19337
19537
  capScope: "system",
19338
19538
  addonId: null,
19339
19539
  access: "create"
19340
19540
  },
19341
- "notificationOutput.sendTest": {
19541
+ "notificationOutput.setTargetEnabled": {
19542
+ capName: "notification-output",
19543
+ capScope: "system",
19544
+ addonId: null,
19545
+ access: "create"
19546
+ },
19547
+ "notificationOutput.testTarget": {
19548
+ capName: "notification-output",
19549
+ capScope: "system",
19550
+ addonId: null,
19551
+ access: "create"
19552
+ },
19553
+ "notificationOutput.upsertTarget": {
19342
19554
  capName: "notification-output",
19343
19555
  capScope: "system",
19344
19556
  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"
@@ -13186,7 +13187,7 @@ var AddBrokerInputSchema = object({
13186
13187
  });
13187
13188
  var AddBrokerResultSchema = object({ id: string() });
13188
13189
  var IdInputSchema = object({ id: string() });
13189
- var TestResultSchema = discriminatedUnion("ok", [object({
13190
+ var TestResultSchema$1 = discriminatedUnion("ok", [object({
13190
13191
  ok: literal(true),
13191
13192
  latencyMs: number()
13192
13193
  }), object({
@@ -13209,7 +13210,7 @@ var StatusSchema = object({
13209
13210
  brokerCount: number(),
13210
13211
  embeddedRunning: boolean()
13211
13212
  });
13212
- 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);
13213
13214
  var NetworkEndpointSchema = object({
13214
13215
  url: string(),
13215
13216
  hostname: string(),
@@ -13260,23 +13261,198 @@ var networkAccessCapability = {
13260
13261
  listEndpoints: method(_void(), array(NetworkEndpointEntrySchema).readonly())
13261
13262
  }
13262
13263
  };
13263
- method(object({
13264
- title: string(),
13264
+ /**
13265
+ * notification-output — canonical, capability-gated notification delivery.
13266
+ *
13267
+ * Apprise-derived model (see
13268
+ * `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
13269
+ * callers emit ONE canonical `Notification`; each provider declares a
13270
+ * per-kind capability descriptor (`TargetKind`), and the pure degrade
13271
+ * engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
13272
+ * message to what the kind supports — callers never special-case a service.
13273
+ *
13274
+ * DESIGN DECISIONS (locked):
13275
+ * - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
13276
+ * `setTargetEnabled`), each provider persisting via the `settings-store`
13277
+ * cap. Rationale: the admin UI needs one uniform surface across the
13278
+ * notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
13279
+ * alternative would fork the UI per addon and cannot host the
13280
+ * discovery→adopt flow.
13281
+ * - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
13282
+ * the generated cap-mount auto-`concatCollection`-fans them across every
13283
+ * registered provider (notifiers addon + HA addon) so one catalog is
13284
+ * routable. `send` / `testTarget` / CRUD route to ONE provider by the
13285
+ * `addonId` the generated collection router extracts from the call input.
13286
+ * - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
13287
+ * transformer) + UDS MsgPack both round-trip typed arrays — already used by
13288
+ * `storage` / `storage-provider` / `recording` caps over the same path. No
13289
+ * base64 fallback needed.
13290
+ *
13291
+ * TODO (deferred, closed-set change — separate decision): add
13292
+ * `providerKind: 'notify'` so notification providers surface on the unified
13293
+ * admin "Integrations" page.
13294
+ */
13295
+ /**
13296
+ * Zentik-derived typed-media enum — the superset across every kind. Each
13297
+ * adapter picks what it supports and the degrade engine filters the rest.
13298
+ */
13299
+ var AttachmentMediaTypeSchema = _enum([
13300
+ "image",
13301
+ "video",
13302
+ "gif",
13303
+ "audio",
13304
+ "icon"
13305
+ ]);
13306
+ /**
13307
+ * A single attachment. Exactly one of `url` (remote source, most adapters
13308
+ * prefer this) or `bytes` (inline source; required for Pushover-style
13309
+ * bytes-only kinds) MUST be present — the degrade engine expresses a
13310
+ * url→bytes fetch as a `needsFetch` directive the adapter executes.
13311
+ */
13312
+ var AttachmentSchema = object({
13313
+ mediaType: AttachmentMediaTypeSchema,
13314
+ url: string().optional(),
13315
+ bytes: _instanceof(Uint8Array).optional(),
13316
+ mime: string().optional(),
13317
+ name: string().optional()
13318
+ }).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
13319
+ var NotificationFormatSchema = _enum([
13320
+ "text",
13321
+ "markdown",
13322
+ "html"
13323
+ ]);
13324
+ /** A single tap-through action button. */
13325
+ var NotificationActionSchema = object({
13326
+ id: string(),
13327
+ label: string(),
13328
+ url: string().optional()
13329
+ });
13330
+ /**
13331
+ * The canonical notification. `body` is the only hard field (Apprise model).
13332
+ * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
13333
+ * NOT a fixed severity enum — each kind declares its own `caps.levels` and
13334
+ * the adapter maps this ordinal onto its native level. `level?` is an
13335
+ * optional kind-native level id (`emergency`, `silent`, …) that overrides
13336
+ * `priority` for that one target.
13337
+ */
13338
+ var NotificationSchema = object({
13265
13339
  body: string(),
13266
- imageUrl: string().optional(),
13340
+ title: string().optional(),
13341
+ format: NotificationFormatSchema.default("text"),
13342
+ priority: number().int().min(1).max(5).default(3),
13343
+ level: string().optional(),
13344
+ attachments: array(AttachmentSchema).optional(),
13345
+ clickUrl: string().optional(),
13346
+ actions: array(NotificationActionSchema).optional(),
13347
+ sound: string().optional(),
13348
+ ttl: number().optional(),
13349
+ tag: string().optional(),
13267
13350
  deviceId: number().optional(),
13268
13351
  eventId: string().optional(),
13269
- priority: _enum([
13270
- "low",
13271
- "normal",
13272
- "high",
13273
- "critical"
13274
- ]).default("normal"),
13275
13352
  metadata: record(string(), unknown()).optional()
13276
- }), _void(), { kind: "mutation" }), method(_void(), object({
13353
+ });
13354
+ /** One declared native severity/priority level for a kind. */
13355
+ var TargetKindLevelSchema = object({
13356
+ id: string(),
13357
+ label: string(),
13358
+ /** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
13359
+ ordinal: number().int().min(1).max(5).nullable(),
13360
+ flags: object({
13361
+ critical: boolean().optional(),
13362
+ silent: boolean().optional(),
13363
+ noPush: boolean().optional()
13364
+ }).optional(),
13365
+ /** e.g. Pushover `emergency` requires `retry` / `expire`. */
13366
+ requires: array(string()).optional(),
13367
+ description: string().optional()
13368
+ });
13369
+ /** The full capability block consulted before dispatch. */
13370
+ var TargetKindCapsSchema = object({
13371
+ attachments: object({
13372
+ mediaTypes: array(AttachmentMediaTypeSchema),
13373
+ mode: _enum([
13374
+ "url",
13375
+ "bytes",
13376
+ "both"
13377
+ ]),
13378
+ max: number().int().nonnegative(),
13379
+ maxBytes: number().int().positive().optional()
13380
+ }),
13381
+ /** Max action buttons (0 = none). */
13382
+ actions: number().int().nonnegative(),
13383
+ levels: array(TargetKindLevelSchema),
13384
+ format: array(NotificationFormatSchema),
13385
+ clickUrl: boolean(),
13386
+ sound: boolean(),
13387
+ ttl: boolean(),
13388
+ bodyMaxLen: number().int().positive()
13389
+ });
13390
+ /**
13391
+ * `configSchema` is a `ConfigUISchema` tree passed through to the admin
13392
+ * FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
13393
+ * `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
13394
+ * the union is large and not meant for runtime validation here; the exported
13395
+ * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
13396
+ */
13397
+ var ConfigSchemaPassthrough = unknown();
13398
+ var TargetKindSchema = object({
13399
+ kind: string(),
13400
+ label: string(),
13401
+ icon: string(),
13402
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
13403
+ addonId: string(),
13404
+ configSchema: ConfigSchemaPassthrough,
13405
+ supportsDiscovery: boolean(),
13406
+ caps: TargetKindCapsSchema
13407
+ });
13408
+ /**
13409
+ * A persisted target. `config` holds secrets; providers REDACT secret fields
13410
+ * (return a presence marker only) when serving `listTargets` — never
13411
+ * round-trip a stored secret to the UI.
13412
+ */
13413
+ var TargetSchema = object({
13414
+ id: string(),
13415
+ name: string(),
13416
+ kind: string(),
13417
+ addonId: string(),
13418
+ enabled: boolean(),
13419
+ config: record(string(), unknown())
13420
+ });
13421
+ /** A discovery-surfaced candidate (config is partial + non-secret). */
13422
+ var DiscoveredTargetSchema = object({
13423
+ kind: string(),
13424
+ suggestedName: string(),
13425
+ config: record(string(), unknown())
13426
+ });
13427
+ /** The degrade engine's report — what was resolved / dropped / degraded. */
13428
+ var RenderedAsSchema = object({
13429
+ level: string(),
13430
+ format: NotificationFormatSchema,
13431
+ attachmentsSent: number().int().nonnegative(),
13432
+ actionsSent: number().int().nonnegative(),
13433
+ truncated: boolean(),
13434
+ dropped: array(string())
13435
+ });
13436
+ var SendResultSchema = object({
13277
13437
  success: boolean(),
13278
- error: string().optional()
13279
- }), { kind: "mutation" });
13438
+ error: string().optional(),
13439
+ renderedAs: RenderedAsSchema.optional()
13440
+ });
13441
+ /** Same shape as SendResult — kept as a distinct name for the test panel. */
13442
+ var TestResultSchema = SendResultSchema;
13443
+ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
13444
+ kind: string(),
13445
+ config: record(string(), unknown()).optional()
13446
+ }), array(DiscoveredTargetSchema)), method(object({
13447
+ targetId: string(),
13448
+ notification: NotificationSchema
13449
+ }), SendResultSchema, { kind: "mutation" }), method(object({
13450
+ targetId: string(),
13451
+ sample: NotificationSchema.optional()
13452
+ }), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
13453
+ targetId: string(),
13454
+ enabled: boolean()
13455
+ }), _void(), { kind: "mutation" });
13280
13456
  /**
13281
13457
  * Zod schemas for persisted record types.
13282
13458
  *
@@ -19332,13 +19508,49 @@ Object.freeze({
19332
19508
  addonId: null,
19333
19509
  access: "create"
19334
19510
  },
19511
+ "notificationOutput.deleteTarget": {
19512
+ capName: "notification-output",
19513
+ capScope: "system",
19514
+ addonId: null,
19515
+ access: "delete"
19516
+ },
19517
+ "notificationOutput.discoverTargets": {
19518
+ capName: "notification-output",
19519
+ capScope: "system",
19520
+ addonId: null,
19521
+ access: "view"
19522
+ },
19523
+ "notificationOutput.listTargetKinds": {
19524
+ capName: "notification-output",
19525
+ capScope: "system",
19526
+ addonId: null,
19527
+ access: "view"
19528
+ },
19529
+ "notificationOutput.listTargets": {
19530
+ capName: "notification-output",
19531
+ capScope: "system",
19532
+ addonId: null,
19533
+ access: "view"
19534
+ },
19335
19535
  "notificationOutput.send": {
19336
19536
  capName: "notification-output",
19337
19537
  capScope: "system",
19338
19538
  addonId: null,
19339
19539
  access: "create"
19340
19540
  },
19341
- "notificationOutput.sendTest": {
19541
+ "notificationOutput.setTargetEnabled": {
19542
+ capName: "notification-output",
19543
+ capScope: "system",
19544
+ addonId: null,
19545
+ access: "create"
19546
+ },
19547
+ "notificationOutput.testTarget": {
19548
+ capName: "notification-output",
19549
+ capScope: "system",
19550
+ addonId: null,
19551
+ access: "create"
19552
+ },
19553
+ "notificationOutput.upsertTarget": {
19342
19554
  capName: "notification-output",
19343
19555
  capScope: "system",
19344
19556
  addonId: null,
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-eH91demF.js");
5
+ const require_dist = require("../dist-fx1JMLox.js");
6
6
  let node_child_process = require("node:child_process");
7
7
  let node_util = require("node:util");
8
8
  let node_crypto = require("node:crypto");
@@ -1,4 +1,4 @@
1
- import { i as EventCategory, n as networkAccessCapability, r as BaseAddon } from "../dist-CfULNCIt.mjs";
1
+ import { i as EventCategory, n as networkAccessCapability, r as BaseAddon } from "../dist-Cv7JkzHN.mjs";
2
2
  import { execFile } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import { randomUUID } from "node:crypto";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-tailscale",
3
- "version": "1.1.13",
3
+ "version": "1.1.14",
4
4
  "description": "Tailscale bundle for CamStack — joins the host to a tailnet (client) and exposes the hub via Serve/Funnel (ingress). Multi-entry npm package shipping 2 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",
@@ -44,7 +44,8 @@
44
44
  "version": "1.0.0",
45
45
  "entry": "./dist/client/tailscale.addon.js",
46
46
  "execution": {
47
- "placement": "hub-only"
47
+ "placement": "hub-only",
48
+ "group": "net-access"
48
49
  },
49
50
  "capabilities": [
50
51
  {
@@ -65,7 +66,8 @@
65
66
  "description": "Exposes the CamStack hub on the tailnet (Serve) or the public internet (Funnel). Requires the Tailscale Client addon to be installed and joined first.",
66
67
  "entry": "./dist/ingress/tailscale-ingress.addon.js",
67
68
  "execution": {
68
- "placement": "hub-only"
69
+ "placement": "hub-only",
70
+ "group": "net-access"
69
71
  },
70
72
  "capabilities": [
71
73
  {