@camstack/addon-notifiers 1.2.627 → 1.2.628
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/CHANGELOG.md +6 -0
- package/dist/addon.js +131 -11
- package/dist/addon.mjs +131 -11
- package/i18n/en.json +1 -1
- package/i18n/it.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.628] - 2026-11-02
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- An email target's relay is now a picker of the chosen provider's relays by name, with 'Default relay' as the empty choice; a relay that no longer exists shows as 'missing relay <id>'.
|
|
15
|
+
|
|
10
16
|
## [1.2.627] - 2026-11-02
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/dist/addon.js
CHANGED
|
@@ -815,7 +815,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
815
815
|
return EventCategory;
|
|
816
816
|
}({});
|
|
817
817
|
//#endregion
|
|
818
|
-
//#region ../types/dist/device-type-
|
|
818
|
+
//#region ../types/dist/device-type-CfHw_quR.mjs
|
|
819
819
|
/**
|
|
820
820
|
import { errMsg } from '@camstack/types'
|
|
821
821
|
* Extract a human-readable message from an unknown error value.
|
|
@@ -1004,6 +1004,9 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
|
1004
1004
|
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
1005
1005
|
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
1006
1006
|
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
1007
|
+
/** Cover has a real stop: `stop` halts the travel in place. Gates the stop
|
|
1008
|
+
* control in exporters; a provider whose `stop` is a no-op never declares it. */
|
|
1009
|
+
DeviceFeature["CoverStoppable"] = "cover-stoppable";
|
|
1007
1010
|
/** Valve exposes intermediate position control (0..100). Gates the
|
|
1008
1011
|
* position slider / drag surface UI. */
|
|
1009
1012
|
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
@@ -6002,7 +6005,7 @@ var ZodIssueCode = {
|
|
|
6002
6005
|
var ZodFirstPartyTypeKind;
|
|
6003
6006
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6004
6007
|
//#endregion
|
|
6005
|
-
//#region ../types/dist/sleep-
|
|
6008
|
+
//#region ../types/dist/sleep-QsoHs66J.mjs
|
|
6006
6009
|
/**
|
|
6007
6010
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6008
6011
|
* window to float samples (D455).
|
|
@@ -11669,7 +11672,7 @@ function userError(code, params, englishFallback) {
|
|
|
11669
11672
|
return new CamstackError(code, params, englishFallback);
|
|
11670
11673
|
}
|
|
11671
11674
|
//#endregion
|
|
11672
|
-
//#region ../types/dist/composition-
|
|
11675
|
+
//#region ../types/dist/composition-Dh3RfMx5.mjs
|
|
11673
11676
|
/**
|
|
11674
11677
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11675
11678
|
*
|
|
@@ -12883,6 +12886,73 @@ var NodeColorIdSchema = _enum([
|
|
|
12883
12886
|
"node-g",
|
|
12884
12887
|
"node-h"
|
|
12885
12888
|
]);
|
|
12889
|
+
//#endregion
|
|
12890
|
+
//#region ../types/dist/index.mjs
|
|
12891
|
+
var SMTP_INBOUND_DEFAULT_PORT = 2525;
|
|
12892
|
+
var SMTP_INBOUND_DEFAULT_DOMAIN = "camstack.local";
|
|
12893
|
+
var SMTP_INBOUND_DEFAULT_MAX_MESSAGE_BYTES = 25 * 1024 * 1024;
|
|
12894
|
+
/** The text excerpt a message carries on the bus. */
|
|
12895
|
+
var SMTP_INBOUND_TEXT_MAX_CHARS = 4096;
|
|
12896
|
+
var PortSchema = number().int().min(1).max(65535);
|
|
12897
|
+
/** A recipient local-part: what stands before the `@`. */
|
|
12898
|
+
var SmtpRecipientSchema = string().min(1).max(64).regex(/^[A-Za-z0-9._+-]+$/);
|
|
12899
|
+
object({
|
|
12900
|
+
port: PortSchema.default(SMTP_INBOUND_DEFAULT_PORT),
|
|
12901
|
+
bindHost: string().min(1).default("0.0.0.0"),
|
|
12902
|
+
domain: string().min(1).default(SMTP_INBOUND_DEFAULT_DOMAIN),
|
|
12903
|
+
requireAuth: boolean().default(true),
|
|
12904
|
+
username: string().default(""),
|
|
12905
|
+
password: string().default("").meta({ secret: true }),
|
|
12906
|
+
starttls: boolean().default(false),
|
|
12907
|
+
maxMessageBytes: number().int().positive().default(SMTP_INBOUND_DEFAULT_MAX_MESSAGE_BYTES)
|
|
12908
|
+
});
|
|
12909
|
+
object({
|
|
12910
|
+
host: string().min(1).nullable(),
|
|
12911
|
+
hostReason: string().nullable(),
|
|
12912
|
+
port: PortSchema,
|
|
12913
|
+
domain: string().min(1),
|
|
12914
|
+
requireAuth: boolean(),
|
|
12915
|
+
username: string(),
|
|
12916
|
+
password: string(),
|
|
12917
|
+
starttls: boolean()
|
|
12918
|
+
});
|
|
12919
|
+
object({
|
|
12920
|
+
recipients: array(SmtpRecipientSchema).min(1),
|
|
12921
|
+
/**
|
|
12922
|
+
* Who is subscribing. A second `subscribe` with the same id REPLACES that subscriber's
|
|
12923
|
+
* recipients (the way a consumer that restarted, or lost a device, declares its set again);
|
|
12924
|
+
* a recipient held by another subscriber is refused with `smtp-inbound/recipient-claimed`.
|
|
12925
|
+
* Absent, the subscriber is anonymous and unique.
|
|
12926
|
+
*/
|
|
12927
|
+
subscriberId: string().min(1).max(64).optional()
|
|
12928
|
+
});
|
|
12929
|
+
var SmtpInboundAttachmentSchema = object({
|
|
12930
|
+
filename: string(),
|
|
12931
|
+
contentType: string(),
|
|
12932
|
+
bytes: number().int().nonnegative()
|
|
12933
|
+
});
|
|
12934
|
+
/** The payload of one `broker.message` (the key is the recipient local-part). */
|
|
12935
|
+
var SmtpInboundMessageSchema = object({
|
|
12936
|
+
/** Monotonic per mailbox; a gap tells a consumer it missed an event. */
|
|
12937
|
+
seq: number().int().positive(),
|
|
12938
|
+
messageId: string(),
|
|
12939
|
+
receivedAt: number().int().nonnegative(),
|
|
12940
|
+
from: string(),
|
|
12941
|
+
to: string(),
|
|
12942
|
+
subject: string(),
|
|
12943
|
+
text: string().max(SMTP_INBOUND_TEXT_MAX_CHARS),
|
|
12944
|
+
attachments: array(SmtpInboundAttachmentSchema)
|
|
12945
|
+
});
|
|
12946
|
+
object({
|
|
12947
|
+
/** The newest seq issued so far (0 before any mail). */
|
|
12948
|
+
lastSeq: number().int().nonnegative(),
|
|
12949
|
+
/** The oldest seq still retained; messages below it are gone. */
|
|
12950
|
+
oldestSeq: number().int().nonnegative(),
|
|
12951
|
+
messages: array(object({
|
|
12952
|
+
key: string(),
|
|
12953
|
+
message: SmtpInboundMessageSchema
|
|
12954
|
+
}))
|
|
12955
|
+
});
|
|
12886
12956
|
new Set([
|
|
12887
12957
|
"track",
|
|
12888
12958
|
"face",
|
|
@@ -53256,6 +53326,11 @@ var IntegrationInstanceSchema = object({
|
|
|
53256
53326
|
name: string(),
|
|
53257
53327
|
/** The addon's own rule (an URL is present, a client id is present...). */
|
|
53258
53328
|
configured: boolean(),
|
|
53329
|
+
/**
|
|
53330
|
+
* The instance's own on/off switch (D996): always present, derived from the record body
|
|
53331
|
+
* (`enabled !== false`, so a row written before the field existed is on).
|
|
53332
|
+
*/
|
|
53333
|
+
enabled: boolean(),
|
|
53259
53334
|
/** Values for the instance form; a secret is a `SecretFieldView`, never text. */
|
|
53260
53335
|
formValues: record(string(), unknown()),
|
|
53261
53336
|
status: IntegrationInstanceStatusSchema.optional()
|
|
@@ -53275,6 +53350,12 @@ method(_void(), IntegrationInstanceDescriptionSchema, { auth: "admin" }), method
|
|
|
53275
53350
|
}), method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
53276
53351
|
kind: "mutation",
|
|
53277
53352
|
auth: "admin"
|
|
53353
|
+
}), method(object({
|
|
53354
|
+
id: IntegrationInstanceIdSchema,
|
|
53355
|
+
enabled: boolean()
|
|
53356
|
+
}), object({ ok: literal(true) }), {
|
|
53357
|
+
kind: "mutation",
|
|
53358
|
+
auth: "admin"
|
|
53278
53359
|
}), method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
53279
53360
|
kind: "mutation",
|
|
53280
53361
|
auth: "admin"
|
|
@@ -63318,7 +63399,14 @@ var NcMediaPolicySchema = object({
|
|
|
63318
63399
|
*/
|
|
63319
63400
|
profile: CamProfileSchema.optional(),
|
|
63320
63401
|
/** See {@link NcLinkedCameraModeSchema}. */
|
|
63321
|
-
linkedCameras: NcLinkedCameraModeSchema.optional()
|
|
63402
|
+
linkedCameras: NcLinkedCameraModeSchema.optional(),
|
|
63403
|
+
/**
|
|
63404
|
+
* Sensor rules only: may this rule wake a SLEEPING battery camera to take
|
|
63405
|
+
* the linked still it attaches (D998)? Absent means yes, an explicit `false`
|
|
63406
|
+
* opts out. Deliberately not a Zod default: a rule that never chose keeps
|
|
63407
|
+
* following the hub's. One bounded wake per event; nothing is attached later.
|
|
63408
|
+
*/
|
|
63409
|
+
wakeSleepingCamera: boolean().optional()
|
|
63322
63410
|
});
|
|
63323
63411
|
/**
|
|
63324
63412
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
@@ -71067,10 +71155,12 @@ DeviceType.Camera, method(object({
|
|
|
71067
71155
|
* even when the cache is well within the device's
|
|
71068
71156
|
* `snapshotMaxAgeS` window.
|
|
71069
71157
|
*
|
|
71070
|
-
* **`force` is
|
|
71158
|
+
* **`force` is a demand with a named principal, not a freshness
|
|
71159
|
+
* preference** — an operator button, the scheduled refresh (D847), or a
|
|
71160
|
+
* notification rule that left the camera's wake allowed (D998). On a
|
|
71071
71161
|
* battery camera it is the one thing that walks past the wrapper's
|
|
71072
|
-
* sleep gate and wakes the camera, so a
|
|
71073
|
-
*
|
|
71162
|
+
* sleep gate and wakes the camera, so a poller, a thumbnail or a
|
|
71163
|
+
* prestream must NEVER set it. Every such caller
|
|
71074
71164
|
* gets the cached frame, which on a sleeping battery camera is the
|
|
71075
71165
|
* correct answer: stale but honest beats woken.
|
|
71076
71166
|
*/
|
|
@@ -75028,7 +75118,7 @@ discriminatedUnion("kind", [object({
|
|
|
75028
75118
|
kind: literal("pronto"),
|
|
75029
75119
|
code: string()
|
|
75030
75120
|
})]);
|
|
75031
|
-
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
75121
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
75032
75122
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
75033
75123
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
75034
75124
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
@@ -78690,6 +78780,13 @@ Object.freeze({
|
|
|
78690
78780
|
access: "view",
|
|
78691
78781
|
role: "admin"
|
|
78692
78782
|
},
|
|
78783
|
+
"integrationInstances.setInstanceEnabled": {
|
|
78784
|
+
capName: "integration-instances",
|
|
78785
|
+
capScope: "system",
|
|
78786
|
+
addonId: null,
|
|
78787
|
+
access: "create",
|
|
78788
|
+
role: "admin"
|
|
78789
|
+
},
|
|
78693
78790
|
"integrationInstances.testInstance": {
|
|
78694
78791
|
capName: "integration-instances",
|
|
78695
78792
|
capScope: "system",
|
|
@@ -90510,12 +90607,19 @@ function buildEmailDescriptor(providers = []) {
|
|
|
90510
90607
|
options
|
|
90511
90608
|
},
|
|
90512
90609
|
{
|
|
90513
|
-
type: "
|
|
90610
|
+
type: "select",
|
|
90514
90611
|
key: "smtpInstanceId",
|
|
90515
90612
|
label: "Relay (optional)",
|
|
90516
90613
|
labelKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.label",
|
|
90517
|
-
description: "Pin this target to one relay of the provider
|
|
90518
|
-
descriptionKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.description"
|
|
90614
|
+
description: "Pin this target to one relay of the provider. Leave on the default relay to use the first configured one.",
|
|
90615
|
+
descriptionKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.description",
|
|
90616
|
+
options: [],
|
|
90617
|
+
discoverOptions: {
|
|
90618
|
+
kind: EMAIL_KIND,
|
|
90619
|
+
dependsOn: ["smtpAddonId"],
|
|
90620
|
+
noneLabel: "Default relay",
|
|
90621
|
+
missingLabel: "missing relay"
|
|
90622
|
+
}
|
|
90519
90623
|
},
|
|
90520
90624
|
{
|
|
90521
90625
|
type: "text",
|
|
@@ -90588,6 +90692,15 @@ function createEmailAdapter(smtp) {
|
|
|
90588
90692
|
"smtpAddonId",
|
|
90589
90693
|
"smtpInstanceId"
|
|
90590
90694
|
],
|
|
90695
|
+
async discover(config) {
|
|
90696
|
+
const addonId = config["smtpAddonId"];
|
|
90697
|
+
if (typeof addonId !== "string" || addonId.trim() === "" || smtp.listRelays === void 0) return [];
|
|
90698
|
+
return (await smtp.listRelays(addonId.trim())).map((relay) => ({
|
|
90699
|
+
kind: EMAIL_KIND,
|
|
90700
|
+
suggestedName: relay.name.length > 0 ? relay.name : relay.id,
|
|
90701
|
+
config: { smtpInstanceId: relay.id }
|
|
90702
|
+
}));
|
|
90703
|
+
},
|
|
90591
90704
|
async sendDirect(config, prepared) {
|
|
90592
90705
|
try {
|
|
90593
90706
|
const to = requireTo(config);
|
|
@@ -94078,6 +94191,13 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
94078
94191
|
})).messageId };
|
|
94079
94192
|
},
|
|
94080
94193
|
listProviders,
|
|
94194
|
+
listRelays: async (addonId) => {
|
|
94195
|
+
if (!(await api.addons.listCapabilityProviders.query({ capName: "integration-instances" })).some((holder) => holder.addonId === addonId)) return [];
|
|
94196
|
+
return (await api.integrationInstances.listInstances.query({ addonId })).map((instance) => ({
|
|
94197
|
+
id: instance.id,
|
|
94198
|
+
name: instance.name
|
|
94199
|
+
}));
|
|
94200
|
+
},
|
|
94081
94201
|
resolveDefaultAddonId: async () => {
|
|
94082
94202
|
const providers = await listProviders();
|
|
94083
94203
|
return providers.find((p) => p.ready === true)?.value ?? providers[0]?.value;
|
package/dist/addon.mjs
CHANGED
|
@@ -788,7 +788,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
788
788
|
return EventCategory;
|
|
789
789
|
}({});
|
|
790
790
|
//#endregion
|
|
791
|
-
//#region ../types/dist/device-type-
|
|
791
|
+
//#region ../types/dist/device-type-CfHw_quR.mjs
|
|
792
792
|
/**
|
|
793
793
|
import { errMsg } from '@camstack/types'
|
|
794
794
|
* Extract a human-readable message from an unknown error value.
|
|
@@ -977,6 +977,9 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
|
977
977
|
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
978
978
|
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
979
979
|
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
980
|
+
/** Cover has a real stop: `stop` halts the travel in place. Gates the stop
|
|
981
|
+
* control in exporters; a provider whose `stop` is a no-op never declares it. */
|
|
982
|
+
DeviceFeature["CoverStoppable"] = "cover-stoppable";
|
|
980
983
|
/** Valve exposes intermediate position control (0..100). Gates the
|
|
981
984
|
* position slider / drag surface UI. */
|
|
982
985
|
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
@@ -5975,7 +5978,7 @@ var ZodIssueCode = {
|
|
|
5975
5978
|
var ZodFirstPartyTypeKind;
|
|
5976
5979
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5977
5980
|
//#endregion
|
|
5978
|
-
//#region ../types/dist/sleep-
|
|
5981
|
+
//#region ../types/dist/sleep-QsoHs66J.mjs
|
|
5979
5982
|
/**
|
|
5980
5983
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5981
5984
|
* window to float samples (D455).
|
|
@@ -11642,7 +11645,7 @@ function userError(code, params, englishFallback) {
|
|
|
11642
11645
|
return new CamstackError(code, params, englishFallback);
|
|
11643
11646
|
}
|
|
11644
11647
|
//#endregion
|
|
11645
|
-
//#region ../types/dist/composition-
|
|
11648
|
+
//#region ../types/dist/composition-Dh3RfMx5.mjs
|
|
11646
11649
|
/**
|
|
11647
11650
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11648
11651
|
*
|
|
@@ -12856,6 +12859,73 @@ var NodeColorIdSchema = _enum([
|
|
|
12856
12859
|
"node-g",
|
|
12857
12860
|
"node-h"
|
|
12858
12861
|
]);
|
|
12862
|
+
//#endregion
|
|
12863
|
+
//#region ../types/dist/index.mjs
|
|
12864
|
+
var SMTP_INBOUND_DEFAULT_PORT = 2525;
|
|
12865
|
+
var SMTP_INBOUND_DEFAULT_DOMAIN = "camstack.local";
|
|
12866
|
+
var SMTP_INBOUND_DEFAULT_MAX_MESSAGE_BYTES = 25 * 1024 * 1024;
|
|
12867
|
+
/** The text excerpt a message carries on the bus. */
|
|
12868
|
+
var SMTP_INBOUND_TEXT_MAX_CHARS = 4096;
|
|
12869
|
+
var PortSchema = number().int().min(1).max(65535);
|
|
12870
|
+
/** A recipient local-part: what stands before the `@`. */
|
|
12871
|
+
var SmtpRecipientSchema = string().min(1).max(64).regex(/^[A-Za-z0-9._+-]+$/);
|
|
12872
|
+
object({
|
|
12873
|
+
port: PortSchema.default(SMTP_INBOUND_DEFAULT_PORT),
|
|
12874
|
+
bindHost: string().min(1).default("0.0.0.0"),
|
|
12875
|
+
domain: string().min(1).default(SMTP_INBOUND_DEFAULT_DOMAIN),
|
|
12876
|
+
requireAuth: boolean().default(true),
|
|
12877
|
+
username: string().default(""),
|
|
12878
|
+
password: string().default("").meta({ secret: true }),
|
|
12879
|
+
starttls: boolean().default(false),
|
|
12880
|
+
maxMessageBytes: number().int().positive().default(SMTP_INBOUND_DEFAULT_MAX_MESSAGE_BYTES)
|
|
12881
|
+
});
|
|
12882
|
+
object({
|
|
12883
|
+
host: string().min(1).nullable(),
|
|
12884
|
+
hostReason: string().nullable(),
|
|
12885
|
+
port: PortSchema,
|
|
12886
|
+
domain: string().min(1),
|
|
12887
|
+
requireAuth: boolean(),
|
|
12888
|
+
username: string(),
|
|
12889
|
+
password: string(),
|
|
12890
|
+
starttls: boolean()
|
|
12891
|
+
});
|
|
12892
|
+
object({
|
|
12893
|
+
recipients: array(SmtpRecipientSchema).min(1),
|
|
12894
|
+
/**
|
|
12895
|
+
* Who is subscribing. A second `subscribe` with the same id REPLACES that subscriber's
|
|
12896
|
+
* recipients (the way a consumer that restarted, or lost a device, declares its set again);
|
|
12897
|
+
* a recipient held by another subscriber is refused with `smtp-inbound/recipient-claimed`.
|
|
12898
|
+
* Absent, the subscriber is anonymous and unique.
|
|
12899
|
+
*/
|
|
12900
|
+
subscriberId: string().min(1).max(64).optional()
|
|
12901
|
+
});
|
|
12902
|
+
var SmtpInboundAttachmentSchema = object({
|
|
12903
|
+
filename: string(),
|
|
12904
|
+
contentType: string(),
|
|
12905
|
+
bytes: number().int().nonnegative()
|
|
12906
|
+
});
|
|
12907
|
+
/** The payload of one `broker.message` (the key is the recipient local-part). */
|
|
12908
|
+
var SmtpInboundMessageSchema = object({
|
|
12909
|
+
/** Monotonic per mailbox; a gap tells a consumer it missed an event. */
|
|
12910
|
+
seq: number().int().positive(),
|
|
12911
|
+
messageId: string(),
|
|
12912
|
+
receivedAt: number().int().nonnegative(),
|
|
12913
|
+
from: string(),
|
|
12914
|
+
to: string(),
|
|
12915
|
+
subject: string(),
|
|
12916
|
+
text: string().max(SMTP_INBOUND_TEXT_MAX_CHARS),
|
|
12917
|
+
attachments: array(SmtpInboundAttachmentSchema)
|
|
12918
|
+
});
|
|
12919
|
+
object({
|
|
12920
|
+
/** The newest seq issued so far (0 before any mail). */
|
|
12921
|
+
lastSeq: number().int().nonnegative(),
|
|
12922
|
+
/** The oldest seq still retained; messages below it are gone. */
|
|
12923
|
+
oldestSeq: number().int().nonnegative(),
|
|
12924
|
+
messages: array(object({
|
|
12925
|
+
key: string(),
|
|
12926
|
+
message: SmtpInboundMessageSchema
|
|
12927
|
+
}))
|
|
12928
|
+
});
|
|
12859
12929
|
new Set([
|
|
12860
12930
|
"track",
|
|
12861
12931
|
"face",
|
|
@@ -53229,6 +53299,11 @@ var IntegrationInstanceSchema = object({
|
|
|
53229
53299
|
name: string(),
|
|
53230
53300
|
/** The addon's own rule (an URL is present, a client id is present...). */
|
|
53231
53301
|
configured: boolean(),
|
|
53302
|
+
/**
|
|
53303
|
+
* The instance's own on/off switch (D996): always present, derived from the record body
|
|
53304
|
+
* (`enabled !== false`, so a row written before the field existed is on).
|
|
53305
|
+
*/
|
|
53306
|
+
enabled: boolean(),
|
|
53232
53307
|
/** Values for the instance form; a secret is a `SecretFieldView`, never text. */
|
|
53233
53308
|
formValues: record(string(), unknown()),
|
|
53234
53309
|
status: IntegrationInstanceStatusSchema.optional()
|
|
@@ -53248,6 +53323,12 @@ method(_void(), IntegrationInstanceDescriptionSchema, { auth: "admin" }), method
|
|
|
53248
53323
|
}), method(IntegrationInstancePatchSchema, object({ ok: literal(true) }), {
|
|
53249
53324
|
kind: "mutation",
|
|
53250
53325
|
auth: "admin"
|
|
53326
|
+
}), method(object({
|
|
53327
|
+
id: IntegrationInstanceIdSchema,
|
|
53328
|
+
enabled: boolean()
|
|
53329
|
+
}), object({ ok: literal(true) }), {
|
|
53330
|
+
kind: "mutation",
|
|
53331
|
+
auth: "admin"
|
|
53251
53332
|
}), method(object({ id: IntegrationInstanceIdSchema }), object({ ok: literal(true) }), {
|
|
53252
53333
|
kind: "mutation",
|
|
53253
53334
|
auth: "admin"
|
|
@@ -63291,7 +63372,14 @@ var NcMediaPolicySchema = object({
|
|
|
63291
63372
|
*/
|
|
63292
63373
|
profile: CamProfileSchema.optional(),
|
|
63293
63374
|
/** See {@link NcLinkedCameraModeSchema}. */
|
|
63294
|
-
linkedCameras: NcLinkedCameraModeSchema.optional()
|
|
63375
|
+
linkedCameras: NcLinkedCameraModeSchema.optional(),
|
|
63376
|
+
/**
|
|
63377
|
+
* Sensor rules only: may this rule wake a SLEEPING battery camera to take
|
|
63378
|
+
* the linked still it attaches (D998)? Absent means yes, an explicit `false`
|
|
63379
|
+
* opts out. Deliberately not a Zod default: a rule that never chose keeps
|
|
63380
|
+
* following the hub's. One bounded wake per event; nothing is attached later.
|
|
63381
|
+
*/
|
|
63382
|
+
wakeSleepingCamera: boolean().optional()
|
|
63295
63383
|
});
|
|
63296
63384
|
/**
|
|
63297
63385
|
* Cooldown GRANULARITY over the subject's class — how much a fired
|
|
@@ -71040,10 +71128,12 @@ DeviceType.Camera, method(object({
|
|
|
71040
71128
|
* even when the cache is well within the device's
|
|
71041
71129
|
* `snapshotMaxAgeS` window.
|
|
71042
71130
|
*
|
|
71043
|
-
* **`force` is
|
|
71131
|
+
* **`force` is a demand with a named principal, not a freshness
|
|
71132
|
+
* preference** — an operator button, the scheduled refresh (D847), or a
|
|
71133
|
+
* notification rule that left the camera's wake allowed (D998). On a
|
|
71044
71134
|
* battery camera it is the one thing that walks past the wrapper's
|
|
71045
|
-
* sleep gate and wakes the camera, so a
|
|
71046
|
-
*
|
|
71135
|
+
* sleep gate and wakes the camera, so a poller, a thumbnail or a
|
|
71136
|
+
* prestream must NEVER set it. Every such caller
|
|
71047
71137
|
* gets the cached frame, which on a sleeping battery camera is the
|
|
71048
71138
|
* correct answer: stale but honest beats woken.
|
|
71049
71139
|
*/
|
|
@@ -75001,7 +75091,7 @@ discriminatedUnion("kind", [object({
|
|
|
75001
75091
|
kind: literal("pronto"),
|
|
75002
75092
|
code: string()
|
|
75003
75093
|
})]);
|
|
75004
|
-
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
75094
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
75005
75095
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
75006
75096
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
75007
75097
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
@@ -78663,6 +78753,13 @@ Object.freeze({
|
|
|
78663
78753
|
access: "view",
|
|
78664
78754
|
role: "admin"
|
|
78665
78755
|
},
|
|
78756
|
+
"integrationInstances.setInstanceEnabled": {
|
|
78757
|
+
capName: "integration-instances",
|
|
78758
|
+
capScope: "system",
|
|
78759
|
+
addonId: null,
|
|
78760
|
+
access: "create",
|
|
78761
|
+
role: "admin"
|
|
78762
|
+
},
|
|
78666
78763
|
"integrationInstances.testInstance": {
|
|
78667
78764
|
capName: "integration-instances",
|
|
78668
78765
|
capScope: "system",
|
|
@@ -90483,12 +90580,19 @@ function buildEmailDescriptor(providers = []) {
|
|
|
90483
90580
|
options
|
|
90484
90581
|
},
|
|
90485
90582
|
{
|
|
90486
|
-
type: "
|
|
90583
|
+
type: "select",
|
|
90487
90584
|
key: "smtpInstanceId",
|
|
90488
90585
|
label: "Relay (optional)",
|
|
90489
90586
|
labelKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.label",
|
|
90490
|
-
description: "Pin this target to one relay of the provider
|
|
90491
|
-
descriptionKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.description"
|
|
90587
|
+
description: "Pin this target to one relay of the provider. Leave on the default relay to use the first configured one.",
|
|
90588
|
+
descriptionKey: "notifiers:emailDescriptor.s_email.smtpInstanceId.description",
|
|
90589
|
+
options: [],
|
|
90590
|
+
discoverOptions: {
|
|
90591
|
+
kind: EMAIL_KIND,
|
|
90592
|
+
dependsOn: ["smtpAddonId"],
|
|
90593
|
+
noneLabel: "Default relay",
|
|
90594
|
+
missingLabel: "missing relay"
|
|
90595
|
+
}
|
|
90492
90596
|
},
|
|
90493
90597
|
{
|
|
90494
90598
|
type: "text",
|
|
@@ -90561,6 +90665,15 @@ function createEmailAdapter(smtp) {
|
|
|
90561
90665
|
"smtpAddonId",
|
|
90562
90666
|
"smtpInstanceId"
|
|
90563
90667
|
],
|
|
90668
|
+
async discover(config) {
|
|
90669
|
+
const addonId = config["smtpAddonId"];
|
|
90670
|
+
if (typeof addonId !== "string" || addonId.trim() === "" || smtp.listRelays === void 0) return [];
|
|
90671
|
+
return (await smtp.listRelays(addonId.trim())).map((relay) => ({
|
|
90672
|
+
kind: EMAIL_KIND,
|
|
90673
|
+
suggestedName: relay.name.length > 0 ? relay.name : relay.id,
|
|
90674
|
+
config: { smtpInstanceId: relay.id }
|
|
90675
|
+
}));
|
|
90676
|
+
},
|
|
90564
90677
|
async sendDirect(config, prepared) {
|
|
90565
90678
|
try {
|
|
90566
90679
|
const to = requireTo(config);
|
|
@@ -94051,6 +94164,13 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
94051
94164
|
})).messageId };
|
|
94052
94165
|
},
|
|
94053
94166
|
listProviders,
|
|
94167
|
+
listRelays: async (addonId) => {
|
|
94168
|
+
if (!(await api.addons.listCapabilityProviders.query({ capName: "integration-instances" })).some((holder) => holder.addonId === addonId)) return [];
|
|
94169
|
+
return (await api.integrationInstances.listInstances.query({ addonId })).map((instance) => ({
|
|
94170
|
+
id: instance.id,
|
|
94171
|
+
name: instance.name
|
|
94172
|
+
}));
|
|
94173
|
+
},
|
|
94054
94174
|
resolveDefaultAddonId: async () => {
|
|
94055
94175
|
const providers = await listProviders();
|
|
94056
94176
|
return providers.find((p) => p.ready === true)?.value ?? providers[0]?.value;
|
package/i18n/en.json
CHANGED
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"s_email": {
|
|
127
127
|
"smtpInstanceId": {
|
|
128
128
|
"label": "Relay (optional)",
|
|
129
|
-
"description": "Pin this target to one relay of the provider
|
|
129
|
+
"description": "Pin this target to one relay of the provider. Leave on the default relay to use the first configured one."
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}
|
package/i18n/it.json
CHANGED
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"s_email": {
|
|
127
127
|
"smtpInstanceId": {
|
|
128
128
|
"label": "Relay (facoltativo)",
|
|
129
|
-
"description": "
|
|
129
|
+
"description": "Fissa questo target a un relay del provider. Lascia il relay predefinito per usare il primo configurato."
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-notifiers",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.628",
|
|
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",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
}
|
|
57
57
|
],
|
|
58
58
|
"requires": {
|
|
59
|
-
"server": ">=1.2.
|
|
59
|
+
"server": ">=1.2.741"
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"files": [
|