@camstack/addon-notifiers 1.2.130 → 1.2.132
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 +256 -30
- package/dist/addon.mjs +256 -30
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -13714,7 +13714,14 @@ var BrokerProviderInfoSchema = object({
|
|
|
13714
13714
|
/** Broker kinds this provider can create, with a display label. */
|
|
13715
13715
|
kinds: array(object({
|
|
13716
13716
|
kind: string(),
|
|
13717
|
-
label: string()
|
|
13717
|
+
label: string(),
|
|
13718
|
+
/**
|
|
13719
|
+
* Relative hub path to start an interactive account link (OAuth popup).
|
|
13720
|
+
* May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
|
|
13721
|
+
*/
|
|
13722
|
+
interactiveConnectPath: string().min(1).optional(),
|
|
13723
|
+
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
13724
|
+
interactiveDisconnectPath: string().min(1).optional()
|
|
13718
13725
|
}))
|
|
13719
13726
|
});
|
|
13720
13727
|
var ListInputSchema = object({
|
|
@@ -51976,18 +51983,18 @@ var HTML_ESCAPES = [
|
|
|
51976
51983
|
[/"/g, """],
|
|
51977
51984
|
[/'/g, "'"]
|
|
51978
51985
|
];
|
|
51979
|
-
function escapeHtml$
|
|
51986
|
+
function escapeHtml$2(text) {
|
|
51980
51987
|
let out = text;
|
|
51981
51988
|
for (const [re, rep] of HTML_ESCAPES) out = out.replace(re, rep);
|
|
51982
51989
|
return out;
|
|
51983
51990
|
}
|
|
51984
51991
|
/** Plain text → HTML-lite (escape + newlines to <br>). */
|
|
51985
51992
|
function textToHtml(text) {
|
|
51986
|
-
return escapeHtml$
|
|
51993
|
+
return escapeHtml$2(text).replace(/\n/g, "<br>");
|
|
51987
51994
|
}
|
|
51988
51995
|
/** Markdown → HTML-lite (bold/italic/code/links; used e.g. for Pushover). */
|
|
51989
51996
|
function markdownToHtmlLite(md) {
|
|
51990
|
-
return escapeHtml$
|
|
51997
|
+
return escapeHtml$2(md).replace(/(\*\*|__)(.*?)\1/g, "<b>$2</b>").replace(/(\*|_)(.*?)\1/g, "<i>$2</i>").replace(/`([^`]*)`/g, "<code>$1</code>").replace(/\[([^\]]*)\]\(([^)]*)\)/g, "<a href=\"$2\">$1</a>").replace(/\n/g, "<br>");
|
|
51991
51998
|
}
|
|
51992
51999
|
/**
|
|
51993
52000
|
* Preference order when the source format is NOT supported — first supported
|
|
@@ -53346,6 +53353,134 @@ var discordAdapter = {
|
|
|
53346
53353
|
}
|
|
53347
53354
|
};
|
|
53348
53355
|
//#endregion
|
|
53356
|
+
//#region src/adapters/email.ts
|
|
53357
|
+
var EMAIL_KIND = "email";
|
|
53358
|
+
var BODY_MAX = 1e5;
|
|
53359
|
+
/** Build the email kind descriptor, optionally stamping live provider options. */
|
|
53360
|
+
function buildEmailDescriptor(providers = []) {
|
|
53361
|
+
const options = providers.map((p) => ({
|
|
53362
|
+
value: p.value,
|
|
53363
|
+
label: p.label,
|
|
53364
|
+
...p.description !== void 0 ? { description: p.description } : {}
|
|
53365
|
+
}));
|
|
53366
|
+
return {
|
|
53367
|
+
kind: EMAIL_KIND,
|
|
53368
|
+
label: "Email",
|
|
53369
|
+
icon: "mail",
|
|
53370
|
+
addonId: "notifiers",
|
|
53371
|
+
supportsDiscovery: false,
|
|
53372
|
+
configSchema: { sections: [{
|
|
53373
|
+
id: "email",
|
|
53374
|
+
title: "Email",
|
|
53375
|
+
description: "Send via a Connectivity → Email provider (Google Services or SMTP). Install and Verify a provider first.",
|
|
53376
|
+
fields: [
|
|
53377
|
+
{
|
|
53378
|
+
type: "text",
|
|
53379
|
+
key: "to",
|
|
53380
|
+
label: "To",
|
|
53381
|
+
description: "Recipient address, or comma-separated list.",
|
|
53382
|
+
required: true
|
|
53383
|
+
},
|
|
53384
|
+
{
|
|
53385
|
+
type: "select",
|
|
53386
|
+
key: "smtpAddonId",
|
|
53387
|
+
label: "Email provider",
|
|
53388
|
+
description: options.length === 0 ? "No ready provider yet. Open Connectivity → Email, install Google Services or SMTP, then Verify." : "Which Connectivity → Email entry delivers this target.",
|
|
53389
|
+
required: true,
|
|
53390
|
+
options
|
|
53391
|
+
},
|
|
53392
|
+
{
|
|
53393
|
+
type: "text",
|
|
53394
|
+
key: "from",
|
|
53395
|
+
label: "From (optional)",
|
|
53396
|
+
description: "Override From when the relay allows it."
|
|
53397
|
+
}
|
|
53398
|
+
]
|
|
53399
|
+
}] },
|
|
53400
|
+
caps: {
|
|
53401
|
+
attachments: {
|
|
53402
|
+
mediaTypes: ["image"],
|
|
53403
|
+
mode: "url",
|
|
53404
|
+
max: 0
|
|
53405
|
+
},
|
|
53406
|
+
actions: 0,
|
|
53407
|
+
levels: [{
|
|
53408
|
+
id: "normal",
|
|
53409
|
+
label: "Normal",
|
|
53410
|
+
ordinal: 3
|
|
53411
|
+
}, {
|
|
53412
|
+
id: "high",
|
|
53413
|
+
label: "High",
|
|
53414
|
+
ordinal: 4
|
|
53415
|
+
}],
|
|
53416
|
+
format: [
|
|
53417
|
+
"text",
|
|
53418
|
+
"html",
|
|
53419
|
+
"markdown"
|
|
53420
|
+
],
|
|
53421
|
+
clickUrl: true,
|
|
53422
|
+
sound: false,
|
|
53423
|
+
ttl: false,
|
|
53424
|
+
bodyMaxLen: BODY_MAX
|
|
53425
|
+
}
|
|
53426
|
+
};
|
|
53427
|
+
}
|
|
53428
|
+
function requireTo(config) {
|
|
53429
|
+
const raw = config["to"];
|
|
53430
|
+
if (typeof raw !== "string" || raw.trim() === "") throw new Error("email: missing required config 'to'");
|
|
53431
|
+
const list = raw.split(/[,;\s]+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
53432
|
+
if (list.length === 0) throw new Error("email: missing required config 'to'");
|
|
53433
|
+
return list;
|
|
53434
|
+
}
|
|
53435
|
+
function renderBodies(prepared) {
|
|
53436
|
+
const body = prepared.bodyParts[0] ?? prepared.body;
|
|
53437
|
+
const title = prepared.title?.trim() ?? "";
|
|
53438
|
+
const click = prepared.clickUrl !== null && prepared.clickUrl !== void 0 ? `\n\n${prepared.clickUrl}` : "";
|
|
53439
|
+
const text = title !== "" ? `${title}\n\n${body}${click}` : `${body}${click}`;
|
|
53440
|
+
if (prepared.format === "html") return {
|
|
53441
|
+
text,
|
|
53442
|
+
html: `${title !== "" ? `<h2>${escapeHtml$1(title)}</h2>` : ""}<div>${body}</div>${prepared.clickUrl !== null && prepared.clickUrl !== void 0 ? `<p><a href="${escapeHtml$1(prepared.clickUrl)}">${escapeHtml$1(prepared.clickUrl)}</a></p>` : ""}`
|
|
53443
|
+
};
|
|
53444
|
+
return { text };
|
|
53445
|
+
}
|
|
53446
|
+
function escapeHtml$1(value) {
|
|
53447
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
53448
|
+
}
|
|
53449
|
+
/** Build the email adapter bound to a live smtp-provider client. */
|
|
53450
|
+
function createEmailAdapter(smtp) {
|
|
53451
|
+
return {
|
|
53452
|
+
descriptor: buildEmailDescriptor(),
|
|
53453
|
+
hydrateDescriptor: async () => {
|
|
53454
|
+
return buildEmailDescriptor(await smtp.listReadyProviders?.() ?? []);
|
|
53455
|
+
},
|
|
53456
|
+
destinationKeys: ["to", "smtpAddonId"],
|
|
53457
|
+
async sendDirect(config, prepared) {
|
|
53458
|
+
try {
|
|
53459
|
+
const to = requireTo(config);
|
|
53460
|
+
const bodies = renderBodies(prepared);
|
|
53461
|
+
const addonId = (typeof config["smtpAddonId"] === "string" && config["smtpAddonId"].trim() !== "" ? config["smtpAddonId"].trim() : void 0) ?? await smtp.resolveDefaultAddonId?.();
|
|
53462
|
+
if (addonId === void 0) throw new Error("email: pick an Email provider (Connectivity → Email) — none ready or none selected");
|
|
53463
|
+
const subject = prepared.title?.trim() && prepared.title.trim().length > 0 ? prepared.title.trim() : "CamStack notification";
|
|
53464
|
+
const from = typeof config["from"] === "string" && config["from"].trim() !== "" ? config["from"].trim() : void 0;
|
|
53465
|
+
await smtp.sendEmail({
|
|
53466
|
+
to,
|
|
53467
|
+
subject,
|
|
53468
|
+
text: bodies.text,
|
|
53469
|
+
...bodies.html !== void 0 ? { html: bodies.html } : {},
|
|
53470
|
+
addonId,
|
|
53471
|
+
...from !== void 0 ? { from } : {}
|
|
53472
|
+
});
|
|
53473
|
+
return { success: true };
|
|
53474
|
+
} catch (err) {
|
|
53475
|
+
return {
|
|
53476
|
+
success: false,
|
|
53477
|
+
error: err instanceof Error ? err.message : String(err)
|
|
53478
|
+
};
|
|
53479
|
+
}
|
|
53480
|
+
}
|
|
53481
|
+
};
|
|
53482
|
+
}
|
|
53483
|
+
//#endregion
|
|
53349
53484
|
//#region src/http.ts
|
|
53350
53485
|
/** Default per-request timeout for notification dispatch. */
|
|
53351
53486
|
var DEFAULT_OUTPUT_TIMEOUT_MS = 1e4;
|
|
@@ -55280,7 +55415,8 @@ function zentikConfigSchema() {
|
|
|
55280
55415
|
}
|
|
55281
55416
|
//#endregion
|
|
55282
55417
|
//#region src/adapters/registry.ts
|
|
55283
|
-
|
|
55418
|
+
/** HTTP adapters that need no runtime deps. */
|
|
55419
|
+
var HTTP_NOTIFIER_ADAPTERS = [
|
|
55284
55420
|
ntfyAdapter,
|
|
55285
55421
|
pushoverAdapter,
|
|
55286
55422
|
gotifyAdapter,
|
|
@@ -55432,6 +55568,17 @@ var NOTIFIER_ADAPTERS = [
|
|
|
55432
55568
|
},
|
|
55433
55569
|
whatsappAdapter
|
|
55434
55570
|
];
|
|
55571
|
+
/**
|
|
55572
|
+
* Full catalog. When `smtp` is omitted the Email kind is still listed but
|
|
55573
|
+
* `sendDirect` fails until the addon wires a client (tests use this).
|
|
55574
|
+
*/
|
|
55575
|
+
function buildNotifierAdapters(smtp) {
|
|
55576
|
+
const emailSmtp = smtp ?? { async sendEmail() {
|
|
55577
|
+
throw new Error("email: no smtp-provider client — install Google Services or SMTP Email under Connectivity → Email and Verify it");
|
|
55578
|
+
} };
|
|
55579
|
+
return [...HTTP_NOTIFIER_ADAPTERS, createEmailAdapter(emailSmtp)];
|
|
55580
|
+
}
|
|
55581
|
+
buildNotifierAdapters();
|
|
55435
55582
|
var NOTIFIER_ICONS = {
|
|
55436
55583
|
telegram: {
|
|
55437
55584
|
contentType: "image/svg+xml",
|
|
@@ -55457,6 +55604,10 @@ var NOTIFIER_ICONS = {
|
|
|
55457
55604
|
contentType: "image/svg+xml",
|
|
55458
55605
|
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#7C3AED\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4.876 13.61a4 4 0 1 0 6.124 3.39h6\" /><path d=\"M15.066 20.502a4 4 0 1 0 1.934 -7.502c-.706 0 -1.424 .179 -2 .5l-3 -5.5\" /><path d=\"M16 8a4 4 0 1 0 -8 0c0 1.506 .77 2.818 2 3.5l-3 5.5\" /></svg>"
|
|
55459
55606
|
},
|
|
55607
|
+
email: {
|
|
55608
|
+
contentType: "image/svg+xml",
|
|
55609
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#EA4335\"><path d=\"M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z\"/></svg>"
|
|
55610
|
+
},
|
|
55460
55611
|
gotify: {
|
|
55461
55612
|
contentType: "image/svg+xml",
|
|
55462
55613
|
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500 500\" width=\"500\" height=\"500\"><style type=\"text/css\" id=\"style1\"> .st0{fill:#DDCBA2;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st1{fill:#71CAEE;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st2{fill:#FFFFFF;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st3{fill:#888E93;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st4{fill:#F0F0F0;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st5{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st6{fill:url(#SVGID_1_);} .st7{fill:url(#SVGID_2_);} .st8{fill:#FFFFFF;} .st9{fill:url(#SVGID_3_);} .st10{fill:url(#SVGID_4_);} .st11{fill:url(#SVGID_5_);} .st12{fill:none;stroke:#FFFFFF;stroke-width:63;stroke-linecap:round;stroke-miterlimit:10;} .st13{fill:none;stroke:#FFFFFF;stroke-width:56;stroke-linecap:round;stroke-miterlimit:10;} .st14{fill:none;stroke:#A4C639;stroke-width:45.1385;stroke-linecap:round;stroke-miterlimit:10;} .st15{fill:none;stroke:#FFFFFF;stroke-width:16;} .st16{fill:#A4C639;} .st17{fill:#E6E6E6;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st18{fill:none;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st19{fill:url(#SVGID_6_);} .st20{fill:url(#SVGID_7_);} .st21{fill:url(#SVGID_8_);} </style><g transform=\"matrix(2.3327641,0,0,2.3327641,-431.80457,-323.21807)\"><g id=\"g48\" transform=\"translate(-24.881692,25.94805)\"><g id=\"g47\"><path class=\"st1\" d=\"m 258.9,119.7 c -3,-0.9 -6,-1.8 -9,-2.7 -4.6,-1.4 -9.2,-2.8 -14,-2.5 -2.8,0.2 -6.1,1.3 -6.9,4 -0.6,2 -1.6,7.3 -1.3,7.9 1.5,3.4 13.9,6.7 18.3,6.7\" id=\"path2\" /><path d=\"m 392.6,177.9 c -1.4,1.4 -2.2,3.5 -2.5,5.5 -0.2,1.4 -0.1,3 0.5,4.3 0.6,1.3 1.8,2.3 3.1,3 1.3,0.6 2.8,0.9 4.3,0.9 1.1,0 2.3,-0.1 3.1,-0.9 0.6,-0.7 0.8,-1.6 0.9,-2.5 0.2,-2.3 -0.1,-4.7 -0.9,-6.9 -0.4,-1.1 -0.9,-2.3 -1.8,-3.1 -1.7,-1.8 -4.5,-2.2 -6.4,-0.5 -0.1,0 -0.2,0.1 -0.3,0.2 z\" id=\"path3\" /><path class=\"st2\" d=\"m 358.5,164.2 c -1,-1 0,-2.7 1,-3.7 5.8,-5.2 15.1,-4.6 21.8,-0.6 10.9,6.6 15.6,19.9 17.2,32.5 0.6,5.2 0.9,10.6 -0.5,15.7 -1.4,5.1 -4.6,9.9 -9.3,12.1 -1.1,0.5 -2.3,0.9 -3.4,0.5 -1.1,-0.4 -1.9,-1.8 -1.2,-2.8 -9.4,-13.6 -19,-26.8 -20.9,-43.2 -0.5,-4.1 -1.8,-7.4 -4.7,-10.5 z\" id=\"path4\" /><path class=\"st1\" d=\"m 220.05771,133 c 34.58546,-18 79.30862,-19.6 112.16964,-8.7 23.69194,7.9 41.3449,26.7 49.4515,50 7.11442,20.6 7.1441,43.6 3.04307,65.7 -7.4942,40.2 -26.19597,77.9 -48.96683,112.6 -12.56244,19 -24.57093,36 -44.23305,48.5 -38.69347,24.6 -88.90104,22.1 -129.28516,11.5 -19.50745,-5.1 -38.36842,-17.3 -44.32901,-37.3 -3.81479,-12.8 -2.07563,-27.6 4.5788,-40 13.50886,-24.8 46.15565,-38.4 50.82627,-67.9 1.36964,-8.7 -0.26842,-17.3 -1.62187,-25.7 -3.7989,-23.4 -5.37477,-45.8 6.68784,-68.7 9.46237,-17.7 24.28607,-31 41.6788,-40 z\" id=\"path6\" /><path class=\"st2\" d=\"m 264.5,174.9 c -0.5,0.5 -0.9,1 -1.3,1.6 -9,11.6 -12,27.9 -9.3,42.1 1.7,9 5.9,17.9 13.2,23.4 19.3,14.6 51.5,13.5 68.4,-1.5 24.4,-21.7 13,-67.6 -14,-78.8 -17.6,-7.2 -43.7,-1.6 -57,13.2 z\" id=\"path9\" /><g id=\"g11\"><path class=\"st2\" d=\"m 382.1,237.1 c 1.4,-0.1 2.9,-0.1 4.3,0.1 0.3,0 0.7,0.1 1,0.4 0.2,0.3 0.4,0.7 0.5,1.1 1,3.9 0.5,8.2 0.1,12.4 -0.1,0.9 -0.2,1.8 -0.6,2.6 -1,2.1 -3.1,2.7 -4.7,2.7 -0.1,0 -0.2,0 -0.3,-0.1 -0.3,-0.2 -0.3,-0.7 -0.2,-1.2 0.3,-5.9 -0.1,-11.9 -0.1,-18 0,0.1 0,0.1 0,0 z\" id=\"path10\" /><path class=\"st2\" d=\"m 378.7,236.8 c -1.4,0.4 -2.5,2 -2.8,4.4 -0.5,4.4 -0.7,8.9 -0.5,13.4 0,0.9 0.1,1.9 0.5,2.4 0.2,0.3 0.5,0.4 0.8,0.4 1.6,0.3 4.1,-0.6 5.6,-1 0,0 0,-5.2 -0.1,-8 -0.1,-2.8 -0.1,-6.1 -0.2,-8.9 0,-0.6 0,-1.5 0,-2.2 0.1,-0.7 -2.6,-0.7 -3.3,-0.5 z\" id=\"path11\" /></g><path class=\"st0\" d=\"m 358.3,231.8 c -0.3,2.2 0.1,4.7 1.7,7.4 2.6,4.4 7,6.1 11.9,5.8 8.9,-0.6 25.3,-5.4 27.5,-15.7 0.6,-3 -0.3,-6.1 -2.2,-8.5 -6.2,-7.8 -17.8,-5.7 -25.6,-2 -5.9,2.7 -12.4,7 -13.3,13 z\" id=\"path12\" /><path class=\"st3\" d=\"m 386.4,208.6 c 2.2,1.4 3.7,3.8 4,7 0.3,3.6 -1.4,7.5 -5,8.8 -2.9,1.1 -6.2,0.6 -9.1,-0.4 -2.9,-1 -5.8,-2.8 -6.8,-5.7 -0.7,-2 -0.3,-4.3 0.7,-6.1 1.1,-1.8 2.8,-3.2 4.7,-4.1 3.9,-1.8 8.4,-1.6 11.5,0.5 z\" id=\"path13\" /><path class=\"st0\" d=\"m 414.7,262.6 c 2.4,0.6 4.8,2.1 5.6,4.4 0.8,2.3 0.1,4.9 -1.6,6.7 -1.7,1.8 -4.2,2.5 -6.6,2.5 -0.8,0 -1.7,-0.1 -2.4,-0.5 -2.5,-1.1 -3.5,-4 -4.2,-6.6 -1.8,-6.8 3.6,-7.8 9.2,-6.5 z\" id=\"path14\" /><g id=\"g17\"><path class=\"st4\" d=\"m 267.1,284.7 c 2.3,-4.5 141.3,-36.2 144.7,-31.6 3.4,4.5 15.8,88.2 9,90.4 -6.8,2.3 -119.8,37.3 -126.6,35 -6.8,-2.3 -29.4,-89.3 -27.1,-93.8 z\" id=\"path15\" /><path class=\"st5\" d=\"m 294.2,378.5 c 0,0 54.3,-74.6 59.9,-76.9 5.7,-2.3 67.3,41.3 67.3,41.3\" id=\"path16\" /><path class=\"st4\" d=\"m 267,287.7 c 0,0 86,38.8 91.6,36.6 5.7,-2.3 53.1,-71.2 53.1,-71.2\" id=\"path17\" /></g><g id=\"g33\"><linearGradient id=\"SVGID_2_\" gradientUnits=\"userSpaceOnUse\" x1=\"265.03339\" y1=\"280.2951\" x2=\"275.3009\" y2=\"302.31369\"><stop offset=\"5.152266e-07\" style=\"stop-color:#71CAEE\" id=\"stop25\" /><stop offset=\"4.104413e-02\" style=\"stop-color:#83CAE2\" id=\"stop26\" /><stop offset=\"0.1206\" style=\"stop-color:#9FCACE\" id=\"stop27\" /><stop offset=\"0.2107\" style=\"stop-color:#B6CBBE\" id=\"stop28\" /><stop offset=\"0.3139\" style=\"stop-color:#C7CBB1\" id=\"stop29\" /><stop offset=\"0.4384\" style=\"stop-color:#D4CBA8\" id=\"stop30\" /><stop offset=\"0.6058\" style=\"stop-color:#DBCBA3\" id=\"stop31\" /><stop offset=\"1\" style=\"stop-color:#DDCBA2\" id=\"stop32\" /></linearGradient><path class=\"st7\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path32\" style=\"fill:url(#SVGID_2_)\" /><path class=\"st5\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path33\" /></g><path d=\"m 318.4,198.4 c -2,-0.3 -4.1,0.1 -5.9,1.3 -3.2,2.1 -4.7,6.2 -4.7,9.9 0,1.9 0.4,3.8 1.4,5.3 1.2,1.7 3.1,2.9 5.2,3.4 3.4,0.8 8.2,0.7 10.5,-2.5 1,-1.5 1.4,-3.3 1.5,-5.1 0.5,-5.7 -1.8,-11.4 -8,-12.3 z\" id=\"path34\" /><path class=\"st8\" d=\"m 320.4,203.3 c 0.9,0.3 1.7,0.8 2.1,1.7 0.4,0.8 0.4,1.7 0.3,2.5 -0.1,1 -0.6,2 -1.5,2.7 -0.7,0.5 -1.7,0.7 -2.6,0.5 -0.9,-0.2 -1.7,-0.8 -2.2,-1.6 -1.1,-1.6 -0.9,-4.4 0.9,-5.5 0.9,-0.4 2,-0.6 3,-0.3 z\" id=\"path35\" /></g></g></g></svg>"
|
|
@@ -56273,6 +56424,32 @@ function createNotificationOutputProvider(deps) {
|
|
|
56273
56424
|
...prepared,
|
|
56274
56425
|
attachments
|
|
56275
56426
|
};
|
|
56427
|
+
if (adapter.sendDirect) try {
|
|
56428
|
+
const result = await adapter.sendDirect(target.config, readyPrepared);
|
|
56429
|
+
return result.error === void 0 ? {
|
|
56430
|
+
...result,
|
|
56431
|
+
renderedAs: prepared.renderedAs
|
|
56432
|
+
} : {
|
|
56433
|
+
...result,
|
|
56434
|
+
error: stripUrls(result.error),
|
|
56435
|
+
renderedAs: prepared.renderedAs
|
|
56436
|
+
};
|
|
56437
|
+
} catch (err) {
|
|
56438
|
+
logger?.warn("sendDirect failed", { meta: {
|
|
56439
|
+
kind: target.kind,
|
|
56440
|
+
error: errMsg(err)
|
|
56441
|
+
} });
|
|
56442
|
+
return {
|
|
56443
|
+
success: false,
|
|
56444
|
+
error: `sendDirect failed: ${errMsg(err)}`,
|
|
56445
|
+
renderedAs: prepared.renderedAs
|
|
56446
|
+
};
|
|
56447
|
+
}
|
|
56448
|
+
if (!adapter.buildRequest) return {
|
|
56449
|
+
success: false,
|
|
56450
|
+
error: `No adapter send path for kind '${target.kind}'`,
|
|
56451
|
+
renderedAs: prepared.renderedAs
|
|
56452
|
+
};
|
|
56276
56453
|
let plan;
|
|
56277
56454
|
try {
|
|
56278
56455
|
plan = adapter.buildRequest(target.config, readyPrepared);
|
|
@@ -56333,24 +56510,32 @@ function createNotificationOutputProvider(deps) {
|
|
|
56333
56510
|
const iconUrlFor = deps.iconUrlFor;
|
|
56334
56511
|
const iconMediaTypeFor = deps.iconMediaTypeFor;
|
|
56335
56512
|
return {
|
|
56336
|
-
listTargetKinds: async () =>
|
|
56337
|
-
const
|
|
56338
|
-
|
|
56339
|
-
|
|
56340
|
-
|
|
56341
|
-
|
|
56342
|
-
|
|
56343
|
-
|
|
56344
|
-
|
|
56345
|
-
|
|
56346
|
-
|
|
56347
|
-
|
|
56348
|
-
|
|
56349
|
-
|
|
56350
|
-
|
|
56351
|
-
|
|
56352
|
-
|
|
56353
|
-
|
|
56513
|
+
listTargetKinds: async () => {
|
|
56514
|
+
const kinds = [];
|
|
56515
|
+
for (const a of deps.adapters) {
|
|
56516
|
+
const base = a.hydrateDescriptor !== void 0 ? await a.hydrateDescriptor() : a.descriptor;
|
|
56517
|
+
const descriptor = {
|
|
56518
|
+
...base,
|
|
56519
|
+
addonId,
|
|
56520
|
+
destinationKeys: [...a.destinationKeys]
|
|
56521
|
+
};
|
|
56522
|
+
const iconUrl = iconUrlFor?.(base.kind);
|
|
56523
|
+
if (iconUrl === void 0) {
|
|
56524
|
+
kinds.push(descriptor);
|
|
56525
|
+
continue;
|
|
56526
|
+
}
|
|
56527
|
+
const iconMediaType = iconMediaTypeFor?.(base.kind);
|
|
56528
|
+
kinds.push(iconMediaType !== void 0 ? {
|
|
56529
|
+
...descriptor,
|
|
56530
|
+
iconUrl,
|
|
56531
|
+
iconMediaType
|
|
56532
|
+
} : {
|
|
56533
|
+
...descriptor,
|
|
56534
|
+
iconUrl
|
|
56535
|
+
});
|
|
56536
|
+
}
|
|
56537
|
+
return kinds;
|
|
56538
|
+
},
|
|
56354
56539
|
listTargets: async () => {
|
|
56355
56540
|
return (await store.list()).map((target) => {
|
|
56356
56541
|
const adapter = adapterByKind.get(target.kind);
|
|
@@ -56640,11 +56825,12 @@ var TargetStore = class {
|
|
|
56640
56825
|
* Notifiers addon — a system `notification-output` collection provider.
|
|
56641
56826
|
*
|
|
56642
56827
|
* It hosts per-kind `NotifierAdapter`s (ntfy, pushover, gotify, telegram,
|
|
56643
|
-
* discord, webhook, zentik, whatsapp) behind one uniform cap surface.
|
|
56644
|
-
* persist via the `settings-store` cap; the canonical notification is
|
|
56645
|
-
* per each target's declared capabilities by the pure
|
|
56646
|
-
* engine in `@camstack/types`. The catalog is
|
|
56647
|
-
* (`adapters/registry.ts`)
|
|
56828
|
+
* discord, webhook, zentik, whatsapp, email) behind one uniform cap surface.
|
|
56829
|
+
* Targets persist via the `settings-store` cap; the canonical notification is
|
|
56830
|
+
* degraded per each target's declared capabilities by the pure
|
|
56831
|
+
* `prepareNotification` engine in `@camstack/types`. The catalog is
|
|
56832
|
+
* `buildNotifierAdapters` (`adapters/registry.ts`); email uses `sendDirect` →
|
|
56833
|
+
* `smtp-provider`.
|
|
56648
56834
|
*/
|
|
56649
56835
|
var NotifiersAddon = class extends BaseAddon {
|
|
56650
56836
|
constructor() {
|
|
@@ -56656,9 +56842,49 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
56656
56842
|
if (!api) this.ctx.logger.warn("notifiers: no ctx.api — targets persist in-memory only");
|
|
56657
56843
|
const store = new TargetStore(port);
|
|
56658
56844
|
await store.init();
|
|
56845
|
+
const listReadyProviders = async () => {
|
|
56846
|
+
if (api === void 0) return [];
|
|
56847
|
+
const [providers, addons] = await Promise.all([api.addons.listCapabilityProviders.query({ capName: "smtp-provider" }), api.addons.list.query()]);
|
|
56848
|
+
const names = /* @__PURE__ */ new Map();
|
|
56849
|
+
for (const row of addons) {
|
|
56850
|
+
const id = row.manifest.id;
|
|
56851
|
+
names.set(id, row.manifest.name ?? row.manifest.packageDisplayName ?? id);
|
|
56852
|
+
}
|
|
56853
|
+
const out = [];
|
|
56854
|
+
for (const p of providers) {
|
|
56855
|
+
if (!p.isActive) continue;
|
|
56856
|
+
try {
|
|
56857
|
+
const status = await api.smtpProvider.getStatus.query({ addonId: p.addonId });
|
|
56858
|
+
if (!status.ready) continue;
|
|
56859
|
+
const name = names.get(p.addonId) ?? p.addonId;
|
|
56860
|
+
out.push({
|
|
56861
|
+
value: p.addonId,
|
|
56862
|
+
label: status.host !== "" ? `${name} — ${status.host}` : name,
|
|
56863
|
+
description: p.addonId
|
|
56864
|
+
});
|
|
56865
|
+
} catch {}
|
|
56866
|
+
}
|
|
56867
|
+
return out;
|
|
56868
|
+
};
|
|
56869
|
+
const adapters = buildNotifierAdapters(api !== void 0 ? {
|
|
56870
|
+
sendEmail: async (input) => {
|
|
56871
|
+
return { messageId: (await api.smtpProvider.sendEmail.mutate({
|
|
56872
|
+
to: typeof input.to === "string" ? input.to : [...input.to],
|
|
56873
|
+
subject: input.subject,
|
|
56874
|
+
text: input.text,
|
|
56875
|
+
...input.html !== void 0 ? { html: input.html } : {},
|
|
56876
|
+
...input.from !== void 0 ? { from: input.from } : {},
|
|
56877
|
+
...input.addonId !== void 0 ? { addonId: input.addonId } : {}
|
|
56878
|
+
})).messageId };
|
|
56879
|
+
},
|
|
56880
|
+
listReadyProviders,
|
|
56881
|
+
resolveDefaultAddonId: async () => {
|
|
56882
|
+
return (await listReadyProviders())[0]?.value;
|
|
56883
|
+
}
|
|
56884
|
+
} : void 0);
|
|
56659
56885
|
const provider = createNotificationOutputProvider({
|
|
56660
56886
|
store,
|
|
56661
|
-
adapters
|
|
56887
|
+
adapters,
|
|
56662
56888
|
logger: this.ctx.logger.child("notification-output"),
|
|
56663
56889
|
iconUrlFor,
|
|
56664
56890
|
iconMediaTypeFor
|
|
@@ -56668,7 +56894,7 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
56668
56894
|
provider,
|
|
56669
56895
|
logger: this.ctx.logger.child("nc-target-actions")
|
|
56670
56896
|
});
|
|
56671
|
-
this.ctx.logger.info("NotifiersAddon initialized", { meta: { adapterCount:
|
|
56897
|
+
this.ctx.logger.info("NotifiersAddon initialized", { meta: { adapterCount: adapters.length } });
|
|
56672
56898
|
return {
|
|
56673
56899
|
providers: [{
|
|
56674
56900
|
capability: notificationOutputCapability,
|
package/dist/addon.mjs
CHANGED
|
@@ -13687,7 +13687,14 @@ var BrokerProviderInfoSchema = object({
|
|
|
13687
13687
|
/** Broker kinds this provider can create, with a display label. */
|
|
13688
13688
|
kinds: array(object({
|
|
13689
13689
|
kind: string(),
|
|
13690
|
-
label: string()
|
|
13690
|
+
label: string(),
|
|
13691
|
+
/**
|
|
13692
|
+
* Relative hub path to start an interactive account link (OAuth popup).
|
|
13693
|
+
* May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
|
|
13694
|
+
*/
|
|
13695
|
+
interactiveConnectPath: string().min(1).optional(),
|
|
13696
|
+
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
13697
|
+
interactiveDisconnectPath: string().min(1).optional()
|
|
13691
13698
|
}))
|
|
13692
13699
|
});
|
|
13693
13700
|
var ListInputSchema = object({
|
|
@@ -51949,18 +51956,18 @@ var HTML_ESCAPES = [
|
|
|
51949
51956
|
[/"/g, """],
|
|
51950
51957
|
[/'/g, "'"]
|
|
51951
51958
|
];
|
|
51952
|
-
function escapeHtml$
|
|
51959
|
+
function escapeHtml$2(text) {
|
|
51953
51960
|
let out = text;
|
|
51954
51961
|
for (const [re, rep] of HTML_ESCAPES) out = out.replace(re, rep);
|
|
51955
51962
|
return out;
|
|
51956
51963
|
}
|
|
51957
51964
|
/** Plain text → HTML-lite (escape + newlines to <br>). */
|
|
51958
51965
|
function textToHtml(text) {
|
|
51959
|
-
return escapeHtml$
|
|
51966
|
+
return escapeHtml$2(text).replace(/\n/g, "<br>");
|
|
51960
51967
|
}
|
|
51961
51968
|
/** Markdown → HTML-lite (bold/italic/code/links; used e.g. for Pushover). */
|
|
51962
51969
|
function markdownToHtmlLite(md) {
|
|
51963
|
-
return escapeHtml$
|
|
51970
|
+
return escapeHtml$2(md).replace(/(\*\*|__)(.*?)\1/g, "<b>$2</b>").replace(/(\*|_)(.*?)\1/g, "<i>$2</i>").replace(/`([^`]*)`/g, "<code>$1</code>").replace(/\[([^\]]*)\]\(([^)]*)\)/g, "<a href=\"$2\">$1</a>").replace(/\n/g, "<br>");
|
|
51964
51971
|
}
|
|
51965
51972
|
/**
|
|
51966
51973
|
* Preference order when the source format is NOT supported — first supported
|
|
@@ -53319,6 +53326,134 @@ var discordAdapter = {
|
|
|
53319
53326
|
}
|
|
53320
53327
|
};
|
|
53321
53328
|
//#endregion
|
|
53329
|
+
//#region src/adapters/email.ts
|
|
53330
|
+
var EMAIL_KIND = "email";
|
|
53331
|
+
var BODY_MAX = 1e5;
|
|
53332
|
+
/** Build the email kind descriptor, optionally stamping live provider options. */
|
|
53333
|
+
function buildEmailDescriptor(providers = []) {
|
|
53334
|
+
const options = providers.map((p) => ({
|
|
53335
|
+
value: p.value,
|
|
53336
|
+
label: p.label,
|
|
53337
|
+
...p.description !== void 0 ? { description: p.description } : {}
|
|
53338
|
+
}));
|
|
53339
|
+
return {
|
|
53340
|
+
kind: EMAIL_KIND,
|
|
53341
|
+
label: "Email",
|
|
53342
|
+
icon: "mail",
|
|
53343
|
+
addonId: "notifiers",
|
|
53344
|
+
supportsDiscovery: false,
|
|
53345
|
+
configSchema: { sections: [{
|
|
53346
|
+
id: "email",
|
|
53347
|
+
title: "Email",
|
|
53348
|
+
description: "Send via a Connectivity → Email provider (Google Services or SMTP). Install and Verify a provider first.",
|
|
53349
|
+
fields: [
|
|
53350
|
+
{
|
|
53351
|
+
type: "text",
|
|
53352
|
+
key: "to",
|
|
53353
|
+
label: "To",
|
|
53354
|
+
description: "Recipient address, or comma-separated list.",
|
|
53355
|
+
required: true
|
|
53356
|
+
},
|
|
53357
|
+
{
|
|
53358
|
+
type: "select",
|
|
53359
|
+
key: "smtpAddonId",
|
|
53360
|
+
label: "Email provider",
|
|
53361
|
+
description: options.length === 0 ? "No ready provider yet. Open Connectivity → Email, install Google Services or SMTP, then Verify." : "Which Connectivity → Email entry delivers this target.",
|
|
53362
|
+
required: true,
|
|
53363
|
+
options
|
|
53364
|
+
},
|
|
53365
|
+
{
|
|
53366
|
+
type: "text",
|
|
53367
|
+
key: "from",
|
|
53368
|
+
label: "From (optional)",
|
|
53369
|
+
description: "Override From when the relay allows it."
|
|
53370
|
+
}
|
|
53371
|
+
]
|
|
53372
|
+
}] },
|
|
53373
|
+
caps: {
|
|
53374
|
+
attachments: {
|
|
53375
|
+
mediaTypes: ["image"],
|
|
53376
|
+
mode: "url",
|
|
53377
|
+
max: 0
|
|
53378
|
+
},
|
|
53379
|
+
actions: 0,
|
|
53380
|
+
levels: [{
|
|
53381
|
+
id: "normal",
|
|
53382
|
+
label: "Normal",
|
|
53383
|
+
ordinal: 3
|
|
53384
|
+
}, {
|
|
53385
|
+
id: "high",
|
|
53386
|
+
label: "High",
|
|
53387
|
+
ordinal: 4
|
|
53388
|
+
}],
|
|
53389
|
+
format: [
|
|
53390
|
+
"text",
|
|
53391
|
+
"html",
|
|
53392
|
+
"markdown"
|
|
53393
|
+
],
|
|
53394
|
+
clickUrl: true,
|
|
53395
|
+
sound: false,
|
|
53396
|
+
ttl: false,
|
|
53397
|
+
bodyMaxLen: BODY_MAX
|
|
53398
|
+
}
|
|
53399
|
+
};
|
|
53400
|
+
}
|
|
53401
|
+
function requireTo(config) {
|
|
53402
|
+
const raw = config["to"];
|
|
53403
|
+
if (typeof raw !== "string" || raw.trim() === "") throw new Error("email: missing required config 'to'");
|
|
53404
|
+
const list = raw.split(/[,;\s]+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
53405
|
+
if (list.length === 0) throw new Error("email: missing required config 'to'");
|
|
53406
|
+
return list;
|
|
53407
|
+
}
|
|
53408
|
+
function renderBodies(prepared) {
|
|
53409
|
+
const body = prepared.bodyParts[0] ?? prepared.body;
|
|
53410
|
+
const title = prepared.title?.trim() ?? "";
|
|
53411
|
+
const click = prepared.clickUrl !== null && prepared.clickUrl !== void 0 ? `\n\n${prepared.clickUrl}` : "";
|
|
53412
|
+
const text = title !== "" ? `${title}\n\n${body}${click}` : `${body}${click}`;
|
|
53413
|
+
if (prepared.format === "html") return {
|
|
53414
|
+
text,
|
|
53415
|
+
html: `${title !== "" ? `<h2>${escapeHtml$1(title)}</h2>` : ""}<div>${body}</div>${prepared.clickUrl !== null && prepared.clickUrl !== void 0 ? `<p><a href="${escapeHtml$1(prepared.clickUrl)}">${escapeHtml$1(prepared.clickUrl)}</a></p>` : ""}`
|
|
53416
|
+
};
|
|
53417
|
+
return { text };
|
|
53418
|
+
}
|
|
53419
|
+
function escapeHtml$1(value) {
|
|
53420
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
53421
|
+
}
|
|
53422
|
+
/** Build the email adapter bound to a live smtp-provider client. */
|
|
53423
|
+
function createEmailAdapter(smtp) {
|
|
53424
|
+
return {
|
|
53425
|
+
descriptor: buildEmailDescriptor(),
|
|
53426
|
+
hydrateDescriptor: async () => {
|
|
53427
|
+
return buildEmailDescriptor(await smtp.listReadyProviders?.() ?? []);
|
|
53428
|
+
},
|
|
53429
|
+
destinationKeys: ["to", "smtpAddonId"],
|
|
53430
|
+
async sendDirect(config, prepared) {
|
|
53431
|
+
try {
|
|
53432
|
+
const to = requireTo(config);
|
|
53433
|
+
const bodies = renderBodies(prepared);
|
|
53434
|
+
const addonId = (typeof config["smtpAddonId"] === "string" && config["smtpAddonId"].trim() !== "" ? config["smtpAddonId"].trim() : void 0) ?? await smtp.resolveDefaultAddonId?.();
|
|
53435
|
+
if (addonId === void 0) throw new Error("email: pick an Email provider (Connectivity → Email) — none ready or none selected");
|
|
53436
|
+
const subject = prepared.title?.trim() && prepared.title.trim().length > 0 ? prepared.title.trim() : "CamStack notification";
|
|
53437
|
+
const from = typeof config["from"] === "string" && config["from"].trim() !== "" ? config["from"].trim() : void 0;
|
|
53438
|
+
await smtp.sendEmail({
|
|
53439
|
+
to,
|
|
53440
|
+
subject,
|
|
53441
|
+
text: bodies.text,
|
|
53442
|
+
...bodies.html !== void 0 ? { html: bodies.html } : {},
|
|
53443
|
+
addonId,
|
|
53444
|
+
...from !== void 0 ? { from } : {}
|
|
53445
|
+
});
|
|
53446
|
+
return { success: true };
|
|
53447
|
+
} catch (err) {
|
|
53448
|
+
return {
|
|
53449
|
+
success: false,
|
|
53450
|
+
error: err instanceof Error ? err.message : String(err)
|
|
53451
|
+
};
|
|
53452
|
+
}
|
|
53453
|
+
}
|
|
53454
|
+
};
|
|
53455
|
+
}
|
|
53456
|
+
//#endregion
|
|
53322
53457
|
//#region src/http.ts
|
|
53323
53458
|
/** Default per-request timeout for notification dispatch. */
|
|
53324
53459
|
var DEFAULT_OUTPUT_TIMEOUT_MS = 1e4;
|
|
@@ -55253,7 +55388,8 @@ function zentikConfigSchema() {
|
|
|
55253
55388
|
}
|
|
55254
55389
|
//#endregion
|
|
55255
55390
|
//#region src/adapters/registry.ts
|
|
55256
|
-
|
|
55391
|
+
/** HTTP adapters that need no runtime deps. */
|
|
55392
|
+
var HTTP_NOTIFIER_ADAPTERS = [
|
|
55257
55393
|
ntfyAdapter,
|
|
55258
55394
|
pushoverAdapter,
|
|
55259
55395
|
gotifyAdapter,
|
|
@@ -55405,6 +55541,17 @@ var NOTIFIER_ADAPTERS = [
|
|
|
55405
55541
|
},
|
|
55406
55542
|
whatsappAdapter
|
|
55407
55543
|
];
|
|
55544
|
+
/**
|
|
55545
|
+
* Full catalog. When `smtp` is omitted the Email kind is still listed but
|
|
55546
|
+
* `sendDirect` fails until the addon wires a client (tests use this).
|
|
55547
|
+
*/
|
|
55548
|
+
function buildNotifierAdapters(smtp) {
|
|
55549
|
+
const emailSmtp = smtp ?? { async sendEmail() {
|
|
55550
|
+
throw new Error("email: no smtp-provider client — install Google Services or SMTP Email under Connectivity → Email and Verify it");
|
|
55551
|
+
} };
|
|
55552
|
+
return [...HTTP_NOTIFIER_ADAPTERS, createEmailAdapter(emailSmtp)];
|
|
55553
|
+
}
|
|
55554
|
+
buildNotifierAdapters();
|
|
55408
55555
|
var NOTIFIER_ICONS = {
|
|
55409
55556
|
telegram: {
|
|
55410
55557
|
contentType: "image/svg+xml",
|
|
@@ -55430,6 +55577,10 @@ var NOTIFIER_ICONS = {
|
|
|
55430
55577
|
contentType: "image/svg+xml",
|
|
55431
55578
|
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#7C3AED\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4.876 13.61a4 4 0 1 0 6.124 3.39h6\" /><path d=\"M15.066 20.502a4 4 0 1 0 1.934 -7.502c-.706 0 -1.424 .179 -2 .5l-3 -5.5\" /><path d=\"M16 8a4 4 0 1 0 -8 0c0 1.506 .77 2.818 2 3.5l-3 5.5\" /></svg>"
|
|
55432
55579
|
},
|
|
55580
|
+
email: {
|
|
55581
|
+
contentType: "image/svg+xml",
|
|
55582
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#EA4335\"><path d=\"M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z\"/></svg>"
|
|
55583
|
+
},
|
|
55433
55584
|
gotify: {
|
|
55434
55585
|
contentType: "image/svg+xml",
|
|
55435
55586
|
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500 500\" width=\"500\" height=\"500\"><style type=\"text/css\" id=\"style1\"> .st0{fill:#DDCBA2;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st1{fill:#71CAEE;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st2{fill:#FFFFFF;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st3{fill:#888E93;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st4{fill:#F0F0F0;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st5{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st6{fill:url(#SVGID_1_);} .st7{fill:url(#SVGID_2_);} .st8{fill:#FFFFFF;} .st9{fill:url(#SVGID_3_);} .st10{fill:url(#SVGID_4_);} .st11{fill:url(#SVGID_5_);} .st12{fill:none;stroke:#FFFFFF;stroke-width:63;stroke-linecap:round;stroke-miterlimit:10;} .st13{fill:none;stroke:#FFFFFF;stroke-width:56;stroke-linecap:round;stroke-miterlimit:10;} .st14{fill:none;stroke:#A4C639;stroke-width:45.1385;stroke-linecap:round;stroke-miterlimit:10;} .st15{fill:none;stroke:#FFFFFF;stroke-width:16;} .st16{fill:#A4C639;} .st17{fill:#E6E6E6;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st18{fill:none;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st19{fill:url(#SVGID_6_);} .st20{fill:url(#SVGID_7_);} .st21{fill:url(#SVGID_8_);} </style><g transform=\"matrix(2.3327641,0,0,2.3327641,-431.80457,-323.21807)\"><g id=\"g48\" transform=\"translate(-24.881692,25.94805)\"><g id=\"g47\"><path class=\"st1\" d=\"m 258.9,119.7 c -3,-0.9 -6,-1.8 -9,-2.7 -4.6,-1.4 -9.2,-2.8 -14,-2.5 -2.8,0.2 -6.1,1.3 -6.9,4 -0.6,2 -1.6,7.3 -1.3,7.9 1.5,3.4 13.9,6.7 18.3,6.7\" id=\"path2\" /><path d=\"m 392.6,177.9 c -1.4,1.4 -2.2,3.5 -2.5,5.5 -0.2,1.4 -0.1,3 0.5,4.3 0.6,1.3 1.8,2.3 3.1,3 1.3,0.6 2.8,0.9 4.3,0.9 1.1,0 2.3,-0.1 3.1,-0.9 0.6,-0.7 0.8,-1.6 0.9,-2.5 0.2,-2.3 -0.1,-4.7 -0.9,-6.9 -0.4,-1.1 -0.9,-2.3 -1.8,-3.1 -1.7,-1.8 -4.5,-2.2 -6.4,-0.5 -0.1,0 -0.2,0.1 -0.3,0.2 z\" id=\"path3\" /><path class=\"st2\" d=\"m 358.5,164.2 c -1,-1 0,-2.7 1,-3.7 5.8,-5.2 15.1,-4.6 21.8,-0.6 10.9,6.6 15.6,19.9 17.2,32.5 0.6,5.2 0.9,10.6 -0.5,15.7 -1.4,5.1 -4.6,9.9 -9.3,12.1 -1.1,0.5 -2.3,0.9 -3.4,0.5 -1.1,-0.4 -1.9,-1.8 -1.2,-2.8 -9.4,-13.6 -19,-26.8 -20.9,-43.2 -0.5,-4.1 -1.8,-7.4 -4.7,-10.5 z\" id=\"path4\" /><path class=\"st1\" d=\"m 220.05771,133 c 34.58546,-18 79.30862,-19.6 112.16964,-8.7 23.69194,7.9 41.3449,26.7 49.4515,50 7.11442,20.6 7.1441,43.6 3.04307,65.7 -7.4942,40.2 -26.19597,77.9 -48.96683,112.6 -12.56244,19 -24.57093,36 -44.23305,48.5 -38.69347,24.6 -88.90104,22.1 -129.28516,11.5 -19.50745,-5.1 -38.36842,-17.3 -44.32901,-37.3 -3.81479,-12.8 -2.07563,-27.6 4.5788,-40 13.50886,-24.8 46.15565,-38.4 50.82627,-67.9 1.36964,-8.7 -0.26842,-17.3 -1.62187,-25.7 -3.7989,-23.4 -5.37477,-45.8 6.68784,-68.7 9.46237,-17.7 24.28607,-31 41.6788,-40 z\" id=\"path6\" /><path class=\"st2\" d=\"m 264.5,174.9 c -0.5,0.5 -0.9,1 -1.3,1.6 -9,11.6 -12,27.9 -9.3,42.1 1.7,9 5.9,17.9 13.2,23.4 19.3,14.6 51.5,13.5 68.4,-1.5 24.4,-21.7 13,-67.6 -14,-78.8 -17.6,-7.2 -43.7,-1.6 -57,13.2 z\" id=\"path9\" /><g id=\"g11\"><path class=\"st2\" d=\"m 382.1,237.1 c 1.4,-0.1 2.9,-0.1 4.3,0.1 0.3,0 0.7,0.1 1,0.4 0.2,0.3 0.4,0.7 0.5,1.1 1,3.9 0.5,8.2 0.1,12.4 -0.1,0.9 -0.2,1.8 -0.6,2.6 -1,2.1 -3.1,2.7 -4.7,2.7 -0.1,0 -0.2,0 -0.3,-0.1 -0.3,-0.2 -0.3,-0.7 -0.2,-1.2 0.3,-5.9 -0.1,-11.9 -0.1,-18 0,0.1 0,0.1 0,0 z\" id=\"path10\" /><path class=\"st2\" d=\"m 378.7,236.8 c -1.4,0.4 -2.5,2 -2.8,4.4 -0.5,4.4 -0.7,8.9 -0.5,13.4 0,0.9 0.1,1.9 0.5,2.4 0.2,0.3 0.5,0.4 0.8,0.4 1.6,0.3 4.1,-0.6 5.6,-1 0,0 0,-5.2 -0.1,-8 -0.1,-2.8 -0.1,-6.1 -0.2,-8.9 0,-0.6 0,-1.5 0,-2.2 0.1,-0.7 -2.6,-0.7 -3.3,-0.5 z\" id=\"path11\" /></g><path class=\"st0\" d=\"m 358.3,231.8 c -0.3,2.2 0.1,4.7 1.7,7.4 2.6,4.4 7,6.1 11.9,5.8 8.9,-0.6 25.3,-5.4 27.5,-15.7 0.6,-3 -0.3,-6.1 -2.2,-8.5 -6.2,-7.8 -17.8,-5.7 -25.6,-2 -5.9,2.7 -12.4,7 -13.3,13 z\" id=\"path12\" /><path class=\"st3\" d=\"m 386.4,208.6 c 2.2,1.4 3.7,3.8 4,7 0.3,3.6 -1.4,7.5 -5,8.8 -2.9,1.1 -6.2,0.6 -9.1,-0.4 -2.9,-1 -5.8,-2.8 -6.8,-5.7 -0.7,-2 -0.3,-4.3 0.7,-6.1 1.1,-1.8 2.8,-3.2 4.7,-4.1 3.9,-1.8 8.4,-1.6 11.5,0.5 z\" id=\"path13\" /><path class=\"st0\" d=\"m 414.7,262.6 c 2.4,0.6 4.8,2.1 5.6,4.4 0.8,2.3 0.1,4.9 -1.6,6.7 -1.7,1.8 -4.2,2.5 -6.6,2.5 -0.8,0 -1.7,-0.1 -2.4,-0.5 -2.5,-1.1 -3.5,-4 -4.2,-6.6 -1.8,-6.8 3.6,-7.8 9.2,-6.5 z\" id=\"path14\" /><g id=\"g17\"><path class=\"st4\" d=\"m 267.1,284.7 c 2.3,-4.5 141.3,-36.2 144.7,-31.6 3.4,4.5 15.8,88.2 9,90.4 -6.8,2.3 -119.8,37.3 -126.6,35 -6.8,-2.3 -29.4,-89.3 -27.1,-93.8 z\" id=\"path15\" /><path class=\"st5\" d=\"m 294.2,378.5 c 0,0 54.3,-74.6 59.9,-76.9 5.7,-2.3 67.3,41.3 67.3,41.3\" id=\"path16\" /><path class=\"st4\" d=\"m 267,287.7 c 0,0 86,38.8 91.6,36.6 5.7,-2.3 53.1,-71.2 53.1,-71.2\" id=\"path17\" /></g><g id=\"g33\"><linearGradient id=\"SVGID_2_\" gradientUnits=\"userSpaceOnUse\" x1=\"265.03339\" y1=\"280.2951\" x2=\"275.3009\" y2=\"302.31369\"><stop offset=\"5.152266e-07\" style=\"stop-color:#71CAEE\" id=\"stop25\" /><stop offset=\"4.104413e-02\" style=\"stop-color:#83CAE2\" id=\"stop26\" /><stop offset=\"0.1206\" style=\"stop-color:#9FCACE\" id=\"stop27\" /><stop offset=\"0.2107\" style=\"stop-color:#B6CBBE\" id=\"stop28\" /><stop offset=\"0.3139\" style=\"stop-color:#C7CBB1\" id=\"stop29\" /><stop offset=\"0.4384\" style=\"stop-color:#D4CBA8\" id=\"stop30\" /><stop offset=\"0.6058\" style=\"stop-color:#DBCBA3\" id=\"stop31\" /><stop offset=\"1\" style=\"stop-color:#DDCBA2\" id=\"stop32\" /></linearGradient><path class=\"st7\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path32\" style=\"fill:url(#SVGID_2_)\" /><path class=\"st5\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path33\" /></g><path d=\"m 318.4,198.4 c -2,-0.3 -4.1,0.1 -5.9,1.3 -3.2,2.1 -4.7,6.2 -4.7,9.9 0,1.9 0.4,3.8 1.4,5.3 1.2,1.7 3.1,2.9 5.2,3.4 3.4,0.8 8.2,0.7 10.5,-2.5 1,-1.5 1.4,-3.3 1.5,-5.1 0.5,-5.7 -1.8,-11.4 -8,-12.3 z\" id=\"path34\" /><path class=\"st8\" d=\"m 320.4,203.3 c 0.9,0.3 1.7,0.8 2.1,1.7 0.4,0.8 0.4,1.7 0.3,2.5 -0.1,1 -0.6,2 -1.5,2.7 -0.7,0.5 -1.7,0.7 -2.6,0.5 -0.9,-0.2 -1.7,-0.8 -2.2,-1.6 -1.1,-1.6 -0.9,-4.4 0.9,-5.5 0.9,-0.4 2,-0.6 3,-0.3 z\" id=\"path35\" /></g></g></g></svg>"
|
|
@@ -56246,6 +56397,32 @@ function createNotificationOutputProvider(deps) {
|
|
|
56246
56397
|
...prepared,
|
|
56247
56398
|
attachments
|
|
56248
56399
|
};
|
|
56400
|
+
if (adapter.sendDirect) try {
|
|
56401
|
+
const result = await adapter.sendDirect(target.config, readyPrepared);
|
|
56402
|
+
return result.error === void 0 ? {
|
|
56403
|
+
...result,
|
|
56404
|
+
renderedAs: prepared.renderedAs
|
|
56405
|
+
} : {
|
|
56406
|
+
...result,
|
|
56407
|
+
error: stripUrls(result.error),
|
|
56408
|
+
renderedAs: prepared.renderedAs
|
|
56409
|
+
};
|
|
56410
|
+
} catch (err) {
|
|
56411
|
+
logger?.warn("sendDirect failed", { meta: {
|
|
56412
|
+
kind: target.kind,
|
|
56413
|
+
error: errMsg(err)
|
|
56414
|
+
} });
|
|
56415
|
+
return {
|
|
56416
|
+
success: false,
|
|
56417
|
+
error: `sendDirect failed: ${errMsg(err)}`,
|
|
56418
|
+
renderedAs: prepared.renderedAs
|
|
56419
|
+
};
|
|
56420
|
+
}
|
|
56421
|
+
if (!adapter.buildRequest) return {
|
|
56422
|
+
success: false,
|
|
56423
|
+
error: `No adapter send path for kind '${target.kind}'`,
|
|
56424
|
+
renderedAs: prepared.renderedAs
|
|
56425
|
+
};
|
|
56249
56426
|
let plan;
|
|
56250
56427
|
try {
|
|
56251
56428
|
plan = adapter.buildRequest(target.config, readyPrepared);
|
|
@@ -56306,24 +56483,32 @@ function createNotificationOutputProvider(deps) {
|
|
|
56306
56483
|
const iconUrlFor = deps.iconUrlFor;
|
|
56307
56484
|
const iconMediaTypeFor = deps.iconMediaTypeFor;
|
|
56308
56485
|
return {
|
|
56309
|
-
listTargetKinds: async () =>
|
|
56310
|
-
const
|
|
56311
|
-
|
|
56312
|
-
|
|
56313
|
-
|
|
56314
|
-
|
|
56315
|
-
|
|
56316
|
-
|
|
56317
|
-
|
|
56318
|
-
|
|
56319
|
-
|
|
56320
|
-
|
|
56321
|
-
|
|
56322
|
-
|
|
56323
|
-
|
|
56324
|
-
|
|
56325
|
-
|
|
56326
|
-
|
|
56486
|
+
listTargetKinds: async () => {
|
|
56487
|
+
const kinds = [];
|
|
56488
|
+
for (const a of deps.adapters) {
|
|
56489
|
+
const base = a.hydrateDescriptor !== void 0 ? await a.hydrateDescriptor() : a.descriptor;
|
|
56490
|
+
const descriptor = {
|
|
56491
|
+
...base,
|
|
56492
|
+
addonId,
|
|
56493
|
+
destinationKeys: [...a.destinationKeys]
|
|
56494
|
+
};
|
|
56495
|
+
const iconUrl = iconUrlFor?.(base.kind);
|
|
56496
|
+
if (iconUrl === void 0) {
|
|
56497
|
+
kinds.push(descriptor);
|
|
56498
|
+
continue;
|
|
56499
|
+
}
|
|
56500
|
+
const iconMediaType = iconMediaTypeFor?.(base.kind);
|
|
56501
|
+
kinds.push(iconMediaType !== void 0 ? {
|
|
56502
|
+
...descriptor,
|
|
56503
|
+
iconUrl,
|
|
56504
|
+
iconMediaType
|
|
56505
|
+
} : {
|
|
56506
|
+
...descriptor,
|
|
56507
|
+
iconUrl
|
|
56508
|
+
});
|
|
56509
|
+
}
|
|
56510
|
+
return kinds;
|
|
56511
|
+
},
|
|
56327
56512
|
listTargets: async () => {
|
|
56328
56513
|
return (await store.list()).map((target) => {
|
|
56329
56514
|
const adapter = adapterByKind.get(target.kind);
|
|
@@ -56613,11 +56798,12 @@ var TargetStore = class {
|
|
|
56613
56798
|
* Notifiers addon — a system `notification-output` collection provider.
|
|
56614
56799
|
*
|
|
56615
56800
|
* It hosts per-kind `NotifierAdapter`s (ntfy, pushover, gotify, telegram,
|
|
56616
|
-
* discord, webhook, zentik, whatsapp) behind one uniform cap surface.
|
|
56617
|
-
* persist via the `settings-store` cap; the canonical notification is
|
|
56618
|
-
* per each target's declared capabilities by the pure
|
|
56619
|
-
* engine in `@camstack/types`. The catalog is
|
|
56620
|
-
* (`adapters/registry.ts`)
|
|
56801
|
+
* discord, webhook, zentik, whatsapp, email) behind one uniform cap surface.
|
|
56802
|
+
* Targets persist via the `settings-store` cap; the canonical notification is
|
|
56803
|
+
* degraded per each target's declared capabilities by the pure
|
|
56804
|
+
* `prepareNotification` engine in `@camstack/types`. The catalog is
|
|
56805
|
+
* `buildNotifierAdapters` (`adapters/registry.ts`); email uses `sendDirect` →
|
|
56806
|
+
* `smtp-provider`.
|
|
56621
56807
|
*/
|
|
56622
56808
|
var NotifiersAddon = class extends BaseAddon {
|
|
56623
56809
|
constructor() {
|
|
@@ -56629,9 +56815,49 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
56629
56815
|
if (!api) this.ctx.logger.warn("notifiers: no ctx.api — targets persist in-memory only");
|
|
56630
56816
|
const store = new TargetStore(port);
|
|
56631
56817
|
await store.init();
|
|
56818
|
+
const listReadyProviders = async () => {
|
|
56819
|
+
if (api === void 0) return [];
|
|
56820
|
+
const [providers, addons] = await Promise.all([api.addons.listCapabilityProviders.query({ capName: "smtp-provider" }), api.addons.list.query()]);
|
|
56821
|
+
const names = /* @__PURE__ */ new Map();
|
|
56822
|
+
for (const row of addons) {
|
|
56823
|
+
const id = row.manifest.id;
|
|
56824
|
+
names.set(id, row.manifest.name ?? row.manifest.packageDisplayName ?? id);
|
|
56825
|
+
}
|
|
56826
|
+
const out = [];
|
|
56827
|
+
for (const p of providers) {
|
|
56828
|
+
if (!p.isActive) continue;
|
|
56829
|
+
try {
|
|
56830
|
+
const status = await api.smtpProvider.getStatus.query({ addonId: p.addonId });
|
|
56831
|
+
if (!status.ready) continue;
|
|
56832
|
+
const name = names.get(p.addonId) ?? p.addonId;
|
|
56833
|
+
out.push({
|
|
56834
|
+
value: p.addonId,
|
|
56835
|
+
label: status.host !== "" ? `${name} — ${status.host}` : name,
|
|
56836
|
+
description: p.addonId
|
|
56837
|
+
});
|
|
56838
|
+
} catch {}
|
|
56839
|
+
}
|
|
56840
|
+
return out;
|
|
56841
|
+
};
|
|
56842
|
+
const adapters = buildNotifierAdapters(api !== void 0 ? {
|
|
56843
|
+
sendEmail: async (input) => {
|
|
56844
|
+
return { messageId: (await api.smtpProvider.sendEmail.mutate({
|
|
56845
|
+
to: typeof input.to === "string" ? input.to : [...input.to],
|
|
56846
|
+
subject: input.subject,
|
|
56847
|
+
text: input.text,
|
|
56848
|
+
...input.html !== void 0 ? { html: input.html } : {},
|
|
56849
|
+
...input.from !== void 0 ? { from: input.from } : {},
|
|
56850
|
+
...input.addonId !== void 0 ? { addonId: input.addonId } : {}
|
|
56851
|
+
})).messageId };
|
|
56852
|
+
},
|
|
56853
|
+
listReadyProviders,
|
|
56854
|
+
resolveDefaultAddonId: async () => {
|
|
56855
|
+
return (await listReadyProviders())[0]?.value;
|
|
56856
|
+
}
|
|
56857
|
+
} : void 0);
|
|
56632
56858
|
const provider = createNotificationOutputProvider({
|
|
56633
56859
|
store,
|
|
56634
|
-
adapters
|
|
56860
|
+
adapters,
|
|
56635
56861
|
logger: this.ctx.logger.child("notification-output"),
|
|
56636
56862
|
iconUrlFor,
|
|
56637
56863
|
iconMediaTypeFor
|
|
@@ -56641,7 +56867,7 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
56641
56867
|
provider,
|
|
56642
56868
|
logger: this.ctx.logger.child("nc-target-actions")
|
|
56643
56869
|
});
|
|
56644
|
-
this.ctx.logger.info("NotifiersAddon initialized", { meta: { adapterCount:
|
|
56870
|
+
this.ctx.logger.info("NotifiersAddon initialized", { meta: { adapterCount: adapters.length } });
|
|
56645
56871
|
return {
|
|
56646
56872
|
providers: [{
|
|
56647
56873
|
capability: notificationOutputCapability,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-notifiers",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.132",
|
|
4
4
|
"description": "System notifiers addon for CamStack — a `notification-output` collection provider hosting per-kind notifier adapters (ntfy, pushover, gotify, telegram, discord, webhook, zentik).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|