@serve.zone/platformclient 1.2.0 → 2.0.1
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.platformclient.d.ts +1 -0
- package/dist_ts/classes.platformclient.js +7 -1
- package/dist_ts/email/classes.emailconnector.d.ts +35 -0
- package/dist_ts/email/classes.emailconnector.js +282 -38
- package/dist_ts/plugins.d.ts +0 -1
- package/dist_ts/plugins.js +1 -2
- package/package.json +3 -4
- package/readme.md +42 -4
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.platformclient.ts +7 -0
- package/ts/email/classes.emailconnector.ts +335 -44
- package/ts/plugins.ts +0 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/platformclient',
|
|
6
|
-
version: '
|
|
6
|
+
version: '2.0.1',
|
|
7
7
|
description: 'a module that makes it really easy to use the serve.zone platform inside your app'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSw0QkFBNEI7SUFDbEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1GQUFtRjtDQUNqRyxDQUFBIn0=
|
|
@@ -35,6 +35,7 @@ export declare class SzPlatformClient {
|
|
|
35
35
|
private getConfiguredAuthorizationString;
|
|
36
36
|
private getAuthorizationStringFromBindings;
|
|
37
37
|
private setAuthorizationTag;
|
|
38
|
+
stop(): Promise<void>;
|
|
38
39
|
private discoverPlatformBindings;
|
|
39
40
|
private parsePlatformBindingsEnv;
|
|
40
41
|
private mergePlatformBindings;
|
|
@@ -128,6 +128,12 @@ export class SzPlatformClient {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
+
async stop() {
|
|
132
|
+
await this.emailConnector.stop();
|
|
133
|
+
if (this.typedsocket) {
|
|
134
|
+
await this.typedsocket.stop();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
131
137
|
async discoverPlatformBindings() {
|
|
132
138
|
const bindings = [];
|
|
133
139
|
const envBindings = await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_BINDINGS');
|
|
@@ -175,4 +181,4 @@ export class SzPlatformClient {
|
|
|
175
181
|
return processEnv?.[envNameArg];
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
184
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5wbGF0Zm9ybWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMucGxhdGZvcm1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDckUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBQzNGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3ZFLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBWXhDLE1BQU0sT0FBTyxnQkFBZ0I7SUFjM0IsWUFBWSxzQkFBMEQ7UUFiL0QsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUdsQixxQkFBZ0IsR0FBNEQsRUFBRSxDQUFDO1FBQy9FLGdCQUFXLEdBQXFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUV0RixpQkFBWSxHQUFHLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUV4QyxtQkFBYyxHQUFHLElBQUksZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsaUJBQVksR0FBRyxJQUFJLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4Qyw4QkFBeUIsR0FBRyxJQUFJLDJCQUEyQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xFLG9CQUFlLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUduRCxJQUFJLENBQUMsWUFBWSxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVNLEtBQUssQ0FBQyxJQUFJLENBQUMsc0JBQTBEO1FBQzFFLElBQUksQ0FBQyxZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsSUFB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
|
|
@@ -10,14 +10,25 @@ export interface IServiceMailSmtpCredentials {
|
|
|
10
10
|
password: string;
|
|
11
11
|
addressToken?: string;
|
|
12
12
|
}
|
|
13
|
+
export interface IServiceMailTypedCredentials {
|
|
14
|
+
from: string;
|
|
15
|
+
typedUrl: string;
|
|
16
|
+
credentialId: string;
|
|
17
|
+
credentialSecret: string;
|
|
18
|
+
addressToken?: string;
|
|
19
|
+
}
|
|
13
20
|
export interface IServiceMailStatus {
|
|
14
21
|
ready: boolean;
|
|
15
22
|
from?: string;
|
|
16
23
|
host?: string;
|
|
17
24
|
port?: number;
|
|
18
25
|
tlsMode?: TServiceMailTlsMode;
|
|
26
|
+
typedUrl?: string;
|
|
27
|
+
transport?: 'typedsocket' | 'smtp' | 'none';
|
|
19
28
|
usernameConfigured: boolean;
|
|
20
29
|
passwordConfigured: boolean;
|
|
30
|
+
typedCredentialConfigured?: boolean;
|
|
31
|
+
smtpReady?: boolean;
|
|
21
32
|
missing: string[];
|
|
22
33
|
}
|
|
23
34
|
export interface IServiceMailAttachment {
|
|
@@ -56,6 +67,16 @@ export type IServiceMailInboundHandleResult = plugins.servezoneInterfaces.reques
|
|
|
56
67
|
export type TServiceMailInboundHandler = (messageArg: IServiceMailInboundMessage) => Promise<IServiceMailInboundHandlerResult | void> | IServiceMailInboundHandlerResult | void;
|
|
57
68
|
export declare class SzEmailConnector {
|
|
58
69
|
platformClientRef: SzPlatformClient;
|
|
70
|
+
private mailTypedSocket?;
|
|
71
|
+
private mailTypedSocketUrl?;
|
|
72
|
+
private mailTypedSocketPromise?;
|
|
73
|
+
private mailTypedSocketAbortController?;
|
|
74
|
+
private mailTypedSocketStatusSubscription?;
|
|
75
|
+
private inboundHandler?;
|
|
76
|
+
private inboundTypedHandlerRegistered;
|
|
77
|
+
private inboundEndpointRegistrations;
|
|
78
|
+
private inboundEndpointReplayPromise?;
|
|
79
|
+
private readonly inboundEndpointReplayRetryDelaysMs;
|
|
59
80
|
constructor(platformClientRefArg: SzPlatformClient);
|
|
60
81
|
/**
|
|
61
82
|
* Legacy platform-service email path. New service-mail code should use sendMail().
|
|
@@ -70,6 +91,8 @@ export declare class SzEmailConnector {
|
|
|
70
91
|
html: string;
|
|
71
92
|
}): Promise<IServiceMailSendResult>;
|
|
72
93
|
sendMail(optionsArg: IServiceMailSendOptions): Promise<IServiceMailSendResult>;
|
|
94
|
+
registerInboundHandler(handlerArg: TServiceMailInboundHandler, addressArg?: string): Promise<plugins.servezoneInterfaces.requests.mail.IReq_RegisterServiceMailEndpoint['response']>;
|
|
95
|
+
stop(): Promise<void>;
|
|
73
96
|
normalizeInboundMessage(payloadArg: unknown): IServiceMailInboundMessage;
|
|
74
97
|
handleInboundPayload(payloadArg: unknown, handlerArg: TServiceMailInboundHandler): Promise<IServiceMailInboundHandleResult>;
|
|
75
98
|
createInboundHandler(handlerArg: TServiceMailInboundHandler): (payloadArg: unknown) => Promise<{
|
|
@@ -77,6 +100,7 @@ export declare class SzEmailConnector {
|
|
|
77
100
|
workAppMessageId?: string;
|
|
78
101
|
message?: string;
|
|
79
102
|
}>;
|
|
103
|
+
private ensureInboundTypedHandler;
|
|
80
104
|
sendNotification(optionsArg: {
|
|
81
105
|
toArg: string;
|
|
82
106
|
subject: string;
|
|
@@ -91,6 +115,17 @@ export declare class SzEmailConnector {
|
|
|
91
115
|
private readMailEnvVar;
|
|
92
116
|
private getCredentialEnvVarFromBindings;
|
|
93
117
|
private hasAnyMailEnvValue;
|
|
118
|
+
private getServiceMailTypedCredentials;
|
|
119
|
+
private getMailTypedSocket;
|
|
120
|
+
private stopMailTypedSocket;
|
|
121
|
+
private watchMailTypedSocketStatus;
|
|
122
|
+
private handleMailTypedSocketStatus;
|
|
123
|
+
private replayInboundEndpointRegistrationsWithRetry;
|
|
124
|
+
private replayInboundEndpointRegistrationsWithRetryInner;
|
|
125
|
+
private replayInboundEndpointRegistrationsOnce;
|
|
126
|
+
private waitForInboundEndpointReplayRetry;
|
|
127
|
+
private registerServiceMailEndpoint;
|
|
128
|
+
private normalizeTypedSocketUrl;
|
|
94
129
|
private normalizeTlsMode;
|
|
95
130
|
private getMailEnvToken;
|
|
96
131
|
private listToArray;
|
|
@@ -2,6 +2,9 @@ import * as plugins from '../plugins.js';
|
|
|
2
2
|
import { logger } from '../logger.js';
|
|
3
3
|
export class SzEmailConnector {
|
|
4
4
|
constructor(platformClientRefArg) {
|
|
5
|
+
this.inboundTypedHandlerRegistered = false;
|
|
6
|
+
this.inboundEndpointRegistrations = new Set();
|
|
7
|
+
this.inboundEndpointReplayRetryDelaysMs = [500, 1000, 2000, 5000];
|
|
5
8
|
this.platformClientRef = platformClientRefArg;
|
|
6
9
|
}
|
|
7
10
|
/**
|
|
@@ -34,27 +37,39 @@ export class SzEmailConnector {
|
|
|
34
37
|
const missingPrefix = useDefaultEnv || !token ? undefined : token;
|
|
35
38
|
const port = env.smtpPort ? Number(env.smtpPort) : undefined;
|
|
36
39
|
const tlsMode = this.normalizeTlsMode(env.smtpTlsMode || 'starttls');
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
const typedMissing = [];
|
|
41
|
+
const smtpMissing = [];
|
|
42
|
+
if (!env.typedUrl)
|
|
43
|
+
typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_TYPED_URL` : 'MAIL_TYPED_URL');
|
|
44
|
+
if (!env.apiCredentialId)
|
|
45
|
+
typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_API_CREDENTIAL_ID` : 'MAIL_API_CREDENTIAL_ID');
|
|
46
|
+
if (!env.apiCredentialSecret)
|
|
47
|
+
typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_API_CREDENTIAL_SECRET` : 'MAIL_API_CREDENTIAL_SECRET');
|
|
40
48
|
if (!env.smtpHost)
|
|
41
|
-
|
|
49
|
+
smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_HOST` : 'SMTP_HOST');
|
|
42
50
|
if (!env.smtpPort || !Number.isInteger(port) || port < 1 || port > 65535) {
|
|
43
|
-
|
|
51
|
+
smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_PORT` : 'SMTP_PORT');
|
|
44
52
|
}
|
|
45
53
|
if (!env.smtpUsername)
|
|
46
|
-
|
|
54
|
+
smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_USERNAME` : 'SMTP_USERNAME');
|
|
47
55
|
if (!env.smtpPassword)
|
|
48
|
-
|
|
56
|
+
smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_PASSWORD` : 'SMTP_PASSWORD');
|
|
57
|
+
const fromMissing = env.from ? [] : [missingPrefix ? `MAIL_${missingPrefix}_FROM` : 'MAIL_FROM'];
|
|
58
|
+
const typedReady = fromMissing.length === 0 && typedMissing.length === 0;
|
|
59
|
+
const smtpReady = fromMissing.length === 0 && smtpMissing.length === 0;
|
|
49
60
|
return {
|
|
50
|
-
ready:
|
|
61
|
+
ready: typedReady,
|
|
51
62
|
from: env.from,
|
|
52
63
|
host: env.smtpHost,
|
|
53
64
|
port,
|
|
54
65
|
tlsMode,
|
|
66
|
+
typedUrl: env.typedUrl,
|
|
67
|
+
transport: typedReady ? 'typedsocket' : smtpReady ? 'smtp' : 'none',
|
|
55
68
|
usernameConfigured: Boolean(env.smtpUsername),
|
|
56
69
|
passwordConfigured: Boolean(env.smtpPassword),
|
|
57
|
-
|
|
70
|
+
typedCredentialConfigured: Boolean(env.apiCredentialId && env.apiCredentialSecret),
|
|
71
|
+
smtpReady,
|
|
72
|
+
missing: typedReady ? [] : [...fromMissing, ...typedMissing],
|
|
58
73
|
};
|
|
59
74
|
}
|
|
60
75
|
async getServiceMailCredentials(addressArg) {
|
|
@@ -103,37 +118,56 @@ export class SzEmailConnector {
|
|
|
103
118
|
logger.log('info', `service mail debug send: ${optionsArg.subject} to ${this.listToArray(optionsArg.to).join(', ')}`);
|
|
104
119
|
return { messageId: 'debug' };
|
|
105
120
|
}
|
|
106
|
-
const credentials = await this.
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
const credentials = await this.getServiceMailTypedCredentials(optionsArg.from);
|
|
122
|
+
const typedSocket = await this.getMailTypedSocket(credentials.typedUrl);
|
|
123
|
+
const request = typedSocket.createTypedRequest('enqueueMail');
|
|
124
|
+
const result = await request.fire({
|
|
125
|
+
auth: {
|
|
126
|
+
credentialId: credentials.credentialId,
|
|
127
|
+
credentialSecret: credentials.credentialSecret,
|
|
128
|
+
},
|
|
129
|
+
outboundIdentityId: credentials.credentialId,
|
|
130
|
+
message: {
|
|
131
|
+
from: credentials.from,
|
|
132
|
+
to: this.listToArray(optionsArg.to),
|
|
133
|
+
cc: optionsArg.cc ? this.listToArray(optionsArg.cc) : undefined,
|
|
134
|
+
bcc: optionsArg.bcc ? this.listToArray(optionsArg.bcc) : undefined,
|
|
135
|
+
subject: optionsArg.subject,
|
|
136
|
+
text: optionsArg.text,
|
|
137
|
+
html: optionsArg.html,
|
|
138
|
+
headers: optionsArg.headers,
|
|
139
|
+
attachments: optionsArg.attachments?.map((attachmentArg) => ({
|
|
140
|
+
filename: attachmentArg.filename,
|
|
141
|
+
contentType: attachmentArg.contentType,
|
|
142
|
+
binaryAttachmentString: this.normalizeAttachmentContent(attachmentArg.content),
|
|
143
|
+
})),
|
|
144
|
+
},
|
|
114
145
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
cc: optionsArg.cc ? this.listToArray(optionsArg.cc) : undefined,
|
|
119
|
-
bcc: optionsArg.bcc ? this.listToArray(optionsArg.bcc) : undefined,
|
|
120
|
-
subject: optionsArg.subject,
|
|
121
|
-
text: optionsArg.text,
|
|
122
|
-
html: optionsArg.html,
|
|
123
|
-
headers: optionsArg.headers,
|
|
124
|
-
attachments: optionsArg.attachments?.map((attachmentArg) => ({
|
|
125
|
-
filename: attachmentArg.filename,
|
|
126
|
-
contentType: attachmentArg.contentType,
|
|
127
|
-
content: this.normalizeAttachmentContent(attachmentArg.content),
|
|
128
|
-
})),
|
|
129
|
-
}));
|
|
146
|
+
if (!result.accepted) {
|
|
147
|
+
throw new Error(result.message || 'service mail was not accepted by dcrouter');
|
|
148
|
+
}
|
|
130
149
|
return {
|
|
131
|
-
messageId: result.
|
|
132
|
-
accepted:
|
|
133
|
-
rejected:
|
|
134
|
-
response: result.
|
|
150
|
+
messageId: result.spoolItemId,
|
|
151
|
+
accepted: this.listToArray(optionsArg.to),
|
|
152
|
+
rejected: [],
|
|
153
|
+
response: result.message,
|
|
135
154
|
};
|
|
136
155
|
}
|
|
156
|
+
async registerInboundHandler(handlerArg, addressArg) {
|
|
157
|
+
this.inboundHandler = handlerArg;
|
|
158
|
+
this.ensureInboundTypedHandler();
|
|
159
|
+
const credentials = await this.getServiceMailTypedCredentials(addressArg);
|
|
160
|
+
const typedSocket = await this.getMailTypedSocket(credentials.typedUrl);
|
|
161
|
+
const result = await this.registerServiceMailEndpoint(typedSocket, credentials);
|
|
162
|
+
const registeredAddresses = result.addresses?.length ? result.addresses : [credentials.from];
|
|
163
|
+
for (const address of registeredAddresses) {
|
|
164
|
+
this.inboundEndpointRegistrations.add(address.trim().toLowerCase());
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
async stop() {
|
|
169
|
+
await this.stopMailTypedSocket();
|
|
170
|
+
}
|
|
137
171
|
normalizeInboundMessage(payloadArg) {
|
|
138
172
|
const payload = this.asRecord(payloadArg);
|
|
139
173
|
const deliveryCandidate = this.asRecord(payload.delivery || payload.message || payload);
|
|
@@ -172,6 +206,17 @@ export class SzEmailConnector {
|
|
|
172
206
|
createInboundHandler(handlerArg) {
|
|
173
207
|
return async (payloadArg) => await this.handleInboundPayload(payloadArg, handlerArg);
|
|
174
208
|
}
|
|
209
|
+
ensureInboundTypedHandler() {
|
|
210
|
+
if (this.inboundTypedHandlerRegistered)
|
|
211
|
+
return;
|
|
212
|
+
this.inboundTypedHandlerRegistered = true;
|
|
213
|
+
this.platformClientRef.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('deliverInboundMail', async (dataArg) => {
|
|
214
|
+
if (!this.inboundHandler) {
|
|
215
|
+
return { accepted: false, message: 'No service mail inbound handler registered' };
|
|
216
|
+
}
|
|
217
|
+
return await this.handleInboundPayload(dataArg.delivery, this.inboundHandler);
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
175
220
|
async sendNotification(optionsArg) { }
|
|
176
221
|
async sendActionLink(optionsArg) { }
|
|
177
222
|
async readMailEnv(tokenArg) {
|
|
@@ -183,6 +228,9 @@ export class SzEmailConnector {
|
|
|
183
228
|
smtpTlsMode: await this.readMailEnvVar(`${prefix}SMTP_TLS_MODE`),
|
|
184
229
|
smtpUsername: await this.readMailEnvVar(`${prefix}SMTP_USERNAME`),
|
|
185
230
|
smtpPassword: await this.readMailEnvVar(`${prefix}SMTP_PASSWORD`),
|
|
231
|
+
typedUrl: await this.readMailEnvVar(tokenArg ? `${prefix}TYPED_URL` : 'MAIL_TYPED_URL'),
|
|
232
|
+
apiCredentialId: await this.readMailEnvVar(tokenArg ? `${prefix}API_CREDENTIAL_ID` : 'MAIL_API_CREDENTIAL_ID'),
|
|
233
|
+
apiCredentialSecret: await this.readMailEnvVar(tokenArg ? `${prefix}API_CREDENTIAL_SECRET` : 'MAIL_API_CREDENTIAL_SECRET'),
|
|
186
234
|
};
|
|
187
235
|
}
|
|
188
236
|
async readMailEnvVar(envNameArg) {
|
|
@@ -205,6 +253,202 @@ export class SzEmailConnector {
|
|
|
205
253
|
hasAnyMailEnvValue(envArg) {
|
|
206
254
|
return Boolean(envArg && Object.values(envArg).some(Boolean));
|
|
207
255
|
}
|
|
256
|
+
async getServiceMailTypedCredentials(addressArg) {
|
|
257
|
+
const requestedAddress = addressArg?.trim().toLowerCase();
|
|
258
|
+
const requestedToken = requestedAddress ? this.getMailEnvToken(requestedAddress) : undefined;
|
|
259
|
+
const scopedEnv = requestedToken ? await this.readMailEnv(requestedToken) : undefined;
|
|
260
|
+
const hasScopedConfig = scopedEnv && Object.values(scopedEnv).some(Boolean);
|
|
261
|
+
const env = hasScopedConfig ? scopedEnv : await this.readMailEnv();
|
|
262
|
+
const from = env.from?.trim().toLowerCase();
|
|
263
|
+
if (!from)
|
|
264
|
+
throw new Error('MAIL_FROM is required for typed service mail');
|
|
265
|
+
if (requestedAddress && from !== requestedAddress) {
|
|
266
|
+
throw new Error(`No typed service mail credentials are configured for ${requestedAddress}`);
|
|
267
|
+
}
|
|
268
|
+
if (!env.typedUrl)
|
|
269
|
+
throw new Error('MAIL_TYPED_URL is required for typed service mail');
|
|
270
|
+
if (!env.apiCredentialId)
|
|
271
|
+
throw new Error('MAIL_API_CREDENTIAL_ID is required for typed service mail');
|
|
272
|
+
if (!env.apiCredentialSecret)
|
|
273
|
+
throw new Error('MAIL_API_CREDENTIAL_SECRET is required for typed service mail');
|
|
274
|
+
return {
|
|
275
|
+
from,
|
|
276
|
+
typedUrl: this.normalizeTypedSocketUrl(env.typedUrl),
|
|
277
|
+
credentialId: env.apiCredentialId,
|
|
278
|
+
credentialSecret: env.apiCredentialSecret,
|
|
279
|
+
addressToken: hasScopedConfig ? requestedToken : undefined,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
async getMailTypedSocket(urlArg) {
|
|
283
|
+
const normalizedUrl = this.normalizeTypedSocketUrl(urlArg);
|
|
284
|
+
if (this.mailTypedSocket && this.mailTypedSocketUrl === normalizedUrl) {
|
|
285
|
+
return this.mailTypedSocket;
|
|
286
|
+
}
|
|
287
|
+
if (this.mailTypedSocketPromise && this.mailTypedSocketUrl === normalizedUrl) {
|
|
288
|
+
return await this.mailTypedSocketPromise;
|
|
289
|
+
}
|
|
290
|
+
if (this.mailTypedSocket || this.mailTypedSocketPromise) {
|
|
291
|
+
await this.stopMailTypedSocket();
|
|
292
|
+
}
|
|
293
|
+
this.mailTypedSocketUrl = normalizedUrl;
|
|
294
|
+
const abortController = new AbortController();
|
|
295
|
+
this.mailTypedSocketAbortController = abortController;
|
|
296
|
+
const socketPromise = plugins.typedsocket.TypedSocket.createClient(this.platformClientRef.typedrouter, normalizedUrl, { autoReconnect: true, abortSignal: abortController.signal });
|
|
297
|
+
this.mailTypedSocketPromise = socketPromise;
|
|
298
|
+
try {
|
|
299
|
+
const socket = await socketPromise;
|
|
300
|
+
if (this.mailTypedSocketPromise === socketPromise && this.mailTypedSocketUrl === normalizedUrl) {
|
|
301
|
+
this.mailTypedSocket = socket;
|
|
302
|
+
this.watchMailTypedSocketStatus(socket);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
await socket.stop();
|
|
306
|
+
}
|
|
307
|
+
return socket;
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
if (this.mailTypedSocketPromise === socketPromise) {
|
|
311
|
+
this.mailTypedSocketPromise = undefined;
|
|
312
|
+
this.mailTypedSocketUrl = undefined;
|
|
313
|
+
this.mailTypedSocketAbortController = undefined;
|
|
314
|
+
}
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async stopMailTypedSocket() {
|
|
319
|
+
const socket = this.mailTypedSocket;
|
|
320
|
+
const socketPromise = this.mailTypedSocketPromise;
|
|
321
|
+
const abortController = this.mailTypedSocketAbortController;
|
|
322
|
+
const statusSubscription = this.mailTypedSocketStatusSubscription;
|
|
323
|
+
this.mailTypedSocket = undefined;
|
|
324
|
+
this.mailTypedSocketPromise = undefined;
|
|
325
|
+
this.mailTypedSocketUrl = undefined;
|
|
326
|
+
this.mailTypedSocketAbortController = undefined;
|
|
327
|
+
this.mailTypedSocketStatusSubscription = undefined;
|
|
328
|
+
statusSubscription?.unsubscribe();
|
|
329
|
+
abortController?.abort();
|
|
330
|
+
if (socket) {
|
|
331
|
+
await socket.stop();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (socketPromise) {
|
|
335
|
+
try {
|
|
336
|
+
const pendingSocket = await socketPromise;
|
|
337
|
+
await pendingSocket.stop();
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// The pending connection already failed; there is no socket to stop.
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
watchMailTypedSocketStatus(socketArg) {
|
|
345
|
+
this.mailTypedSocketStatusSubscription?.unsubscribe();
|
|
346
|
+
this.mailTypedSocketStatusSubscription = socketArg.statusSubject.subscribe((statusArg) => {
|
|
347
|
+
void this.handleMailTypedSocketStatus(socketArg, statusArg);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async handleMailTypedSocketStatus(socketArg, statusArg) {
|
|
351
|
+
if (statusArg !== 'connected' || this.mailTypedSocket !== socketArg) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
await this.replayInboundEndpointRegistrationsWithRetry(socketArg);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.warn('Could not re-register service mail endpoint after reconnect:', error.message);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async replayInboundEndpointRegistrationsWithRetry(socketArg) {
|
|
362
|
+
if (!this.inboundEndpointRegistrations.size) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (this.inboundEndpointReplayPromise) {
|
|
366
|
+
return await this.inboundEndpointReplayPromise;
|
|
367
|
+
}
|
|
368
|
+
const replayPromise = this.replayInboundEndpointRegistrationsWithRetryInner(socketArg);
|
|
369
|
+
this.inboundEndpointReplayPromise = replayPromise;
|
|
370
|
+
try {
|
|
371
|
+
await replayPromise;
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
if (this.inboundEndpointReplayPromise === replayPromise) {
|
|
375
|
+
this.inboundEndpointReplayPromise = undefined;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async replayInboundEndpointRegistrationsWithRetryInner(socketArg) {
|
|
380
|
+
let lastError;
|
|
381
|
+
const delays = [0, ...this.inboundEndpointReplayRetryDelaysMs];
|
|
382
|
+
for (let attemptIndex = 0; attemptIndex < delays.length; attemptIndex++) {
|
|
383
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (attemptIndex > 0) {
|
|
387
|
+
const shouldContinue = await this.waitForInboundEndpointReplayRetry(socketArg, delays[attemptIndex]);
|
|
388
|
+
if (!shouldContinue) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
try {
|
|
393
|
+
await this.replayInboundEndpointRegistrationsOnce(socketArg);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
lastError = error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
throw lastError instanceof Error
|
|
401
|
+
? lastError
|
|
402
|
+
: new Error('Could not re-register service mail endpoint after reconnect');
|
|
403
|
+
}
|
|
404
|
+
async replayInboundEndpointRegistrationsOnce(socketArg) {
|
|
405
|
+
for (const address of this.inboundEndpointRegistrations.values()) {
|
|
406
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const credentials = await this.getServiceMailTypedCredentials(address);
|
|
410
|
+
if (this.normalizeTypedSocketUrl(credentials.typedUrl) !== this.mailTypedSocketUrl) {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
await this.registerServiceMailEndpoint(socketArg, credentials);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
async waitForInboundEndpointReplayRetry(socketArg, delayMsArg) {
|
|
417
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const abortSignal = this.mailTypedSocketAbortController?.signal;
|
|
421
|
+
if (abortSignal?.aborted) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
return await new Promise((resolve) => {
|
|
425
|
+
const resolveOnce = (resultArg) => {
|
|
426
|
+
clearTimeout(timeout);
|
|
427
|
+
abortSignal?.removeEventListener('abort', abortHandler);
|
|
428
|
+
resolve(resultArg && this.mailTypedSocket === socketArg);
|
|
429
|
+
};
|
|
430
|
+
const abortHandler = () => resolveOnce(false);
|
|
431
|
+
const timeout = setTimeout(() => resolveOnce(true), delayMsArg);
|
|
432
|
+
abortSignal?.addEventListener('abort', abortHandler, { once: true });
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
async registerServiceMailEndpoint(typedSocketArg, credentialsArg) {
|
|
436
|
+
const request = typedSocketArg.createTypedRequest('registerServiceMailEndpoint');
|
|
437
|
+
const result = await request.fire({
|
|
438
|
+
auth: {
|
|
439
|
+
credentialId: credentialsArg.credentialId,
|
|
440
|
+
credentialSecret: credentialsArg.credentialSecret,
|
|
441
|
+
},
|
|
442
|
+
addresses: [credentialsArg.from],
|
|
443
|
+
});
|
|
444
|
+
if (!result.success) {
|
|
445
|
+
throw new Error(result.message || 'Could not register service mail endpoint');
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
normalizeTypedSocketUrl(urlArg) {
|
|
450
|
+
return urlArg.trim().replace(/\/typedrequest\/?$/, '').replace(/\/+$/, '');
|
|
451
|
+
}
|
|
208
452
|
normalizeTlsMode(valueArg) {
|
|
209
453
|
if (valueArg === 'plain' || valueArg === 'starttls' || valueArg === 'implicitTls')
|
|
210
454
|
return valueArg;
|
|
@@ -218,7 +462,7 @@ export class SzEmailConnector {
|
|
|
218
462
|
return Array.isArray(valueArg) ? valueArg : [valueArg];
|
|
219
463
|
}
|
|
220
464
|
normalizeAttachmentContent(contentArg) {
|
|
221
|
-
return
|
|
465
|
+
return Buffer.from(contentArg).toString('base64');
|
|
222
466
|
}
|
|
223
467
|
asRecord(valueArg) {
|
|
224
468
|
return valueArg && typeof valueArg === 'object' ? valueArg : {};
|
|
@@ -248,4 +492,4 @@ export class SzEmailConnector {
|
|
|
248
492
|
}
|
|
249
493
|
}
|
|
250
494
|
}
|
|
251
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lbWFpbGNvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuZW1haWxjb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFFekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQTRFdEMsTUFBTSxPQUFPLGdCQUFnQjtJQUczQixZQUFZLG9CQUFzQztRQUNoRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsb0JBQW9CLENBQUM7SUFDaEQsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFNBQVMsQ0FDcEIsVUFBZ0Y7UUFFaEYsSUFBSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDckMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsMkJBQTJCLFVBQVUsQ0FBQyxLQUFLLE9BQU8sVUFBVSxDQUFDLEVBQUU7O1VBRTlFLFVBQVUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDOztTQUVyRSxDQUFDLENBQUM7UUFDUCxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDckMsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLFlBQVksR0FDaEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FDbkQsV0FBVyxDQUNaLENBQUM7UUFDSixNQUFNLFFBQVEsR0FBRyxNQUFNLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDckQsT0FBTyxRQUFRLENBQUMsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFFTSxLQUFLLENBQUMs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
|
|
495
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5lbWFpbGNvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2VtYWlsL2NsYXNzZXMuZW1haWxjb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFFekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQWlGdEMsTUFBTSxPQUFPLGdCQUFnQjtJQWEzQixZQUFZLG9CQUFzQztRQUwxQyxrQ0FBNkIsR0FBRyxLQUFLLENBQUM7UUFDdEMsaUNBQTRCLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUV4Qyx1Q0FBa0MsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBRzVFLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxvQkFBb0IsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsU0FBUyxDQUNwQixVQUFnRjtRQUVoRixJQUFJLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNyQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSwyQkFBMkIsVUFBVSxDQUFDLEtBQUssT0FBTyxVQUFVLENBQUMsRUFBRTs7VUFFOUUsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7O1NBRXJFLENBQUMsQ0FBQztRQUNQLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNyQyxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sWUFBWSxHQUNoQixJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLGtCQUFrQixDQUNu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
|
package/dist_ts/plugins.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export { servezoneInterfaces, };
|
|
|
3
3
|
import * as qenv from '@push.rocks/qenv';
|
|
4
4
|
import * as smartlog from '@push.rocks/smartlog';
|
|
5
5
|
export { qenv, smartlog, };
|
|
6
|
-
export declare const getSmartsmtp: () => Promise<typeof import("@push.rocks/smartsmtp")>;
|
|
7
6
|
import * as typedrequest from '@api.global/typedrequest';
|
|
8
7
|
import * as typedserver from '@api.global/typedserver';
|
|
9
8
|
import * as typedsocket from '@api.global/typedsocket';
|
package/dist_ts/plugins.js
CHANGED
|
@@ -5,10 +5,9 @@ export { servezoneInterfaces, };
|
|
|
5
5
|
import * as qenv from '@push.rocks/qenv';
|
|
6
6
|
import * as smartlog from '@push.rocks/smartlog';
|
|
7
7
|
export { qenv, smartlog, };
|
|
8
|
-
export const getSmartsmtp = async () => await import('@push.rocks/smartsmtp');
|
|
9
8
|
// @api.global scope
|
|
10
9
|
import * as typedrequest from '@api.global/typedrequest';
|
|
11
10
|
import * as typedserver from '@api.global/typedserver';
|
|
12
11
|
import * as typedsocket from '@api.global/typedsocket';
|
|
13
12
|
export { typedrequest, typedserver, typedsocket, };
|
|
14
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxtQkFBbUIsTUFBTSx3QkFBd0IsQ0FBQztBQUU5RCxPQUFPLEVBQ0wsbUJBQW1CLEdBQ3BCLENBQUE7QUFFRCxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLElBQUksTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEtBQUssUUFBUSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELE9BQU8sRUFDTCxJQUFJLEVBQ0osUUFBUSxHQUNULENBQUE7QUFHRCxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLFlBQVksTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEtBQUssV0FBVyxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUNMLFlBQVksRUFDWixXQUFXLEVBQ1gsV0FBVyxHQUNaLENBQUEifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serve.zone/platformclient",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "a module that makes it really easy to use the serve.zone platform inside your app",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@git.zone/tsbundle": "^2.11.0",
|
|
14
14
|
"@git.zone/tsrun": "^2.0.4",
|
|
15
15
|
"@git.zone/tstest": "^3.6.6",
|
|
16
|
-
"@types/node": "^25.9.
|
|
16
|
+
"@types/node": "^25.9.3"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@api.global/typedrequest": "^3.3.0",
|
|
@@ -22,8 +22,7 @@
|
|
|
22
22
|
"@push.rocks/qenv": "^6.1.4",
|
|
23
23
|
"@push.rocks/smartlog": "^3.2.2",
|
|
24
24
|
"@push.rocks/smartntml": "^2.0.9",
|
|
25
|
-
"@
|
|
26
|
-
"@serve.zone/interfaces": "^7.27.0"
|
|
25
|
+
"@serve.zone/interfaces": "^7.28.0"
|
|
27
26
|
},
|
|
28
27
|
"repository": {
|
|
29
28
|
"type": "git",
|
package/readme.md
CHANGED
|
@@ -38,7 +38,7 @@ await platformClient.emailConnector.sendEmail({
|
|
|
38
38
|
|
|
39
39
|
| Connector | Main methods | Platform capability |
|
|
40
40
|
| --- | --- | --- |
|
|
41
|
-
| `emailConnector` | `getServiceMailStatus()`, `getServiceMailCredentials()`, `sendMail()`, `sendText()`, `sendHtml()`, `normalizeInboundMessage()`, `handleInboundPayload()`, `createInboundHandler()`, `sendEmail()` | `email` |
|
|
41
|
+
| `emailConnector` | `getServiceMailStatus()`, `getServiceMailCredentials()`, `sendMail()`, `sendText()`, `sendHtml()`, `registerInboundHandler()`, `normalizeInboundMessage()`, `handleInboundPayload()`, `createInboundHandler()`, `sendEmail()` | `email` |
|
|
42
42
|
| `smsConnector` | `sendSms()`, `sendSmsVerifcation()` | `sms` |
|
|
43
43
|
| `pushNotificationConnector` | `sendPushNotification()` | `pushnotification` |
|
|
44
44
|
| `letterConnector` | `sendLetter()` | `letter` |
|
|
@@ -57,7 +57,9 @@ The client needs an authorization string and a platform endpoint. You can provid
|
|
|
57
57
|
|
|
58
58
|
Binding environment variables must contain JSON encoded `IPlatformBinding` objects from `@serve.zone/interfaces`.
|
|
59
59
|
|
|
60
|
-
Service mail credentials can be provided directly as environment variables or through `email` platform binding credentials. The default sender uses `MAIL_FROM`, `
|
|
60
|
+
Service mail credentials can be provided directly as environment variables or through `email` platform binding credentials. Standard platformclient mail uses dcrouter TypedSocket/TypedRequest service credentials. The default sender uses `MAIL_FROM`, `MAIL_TYPED_URL`, `MAIL_API_CREDENTIAL_ID`, and `MAIL_API_CREDENTIAL_SECRET`. Additional configured sender addresses use scoped variables such as `MAIL_TEST_SERVICE_GATED_ONE_FROM`, `MAIL_TEST_SERVICE_GATED_ONE_TYPED_URL`, `MAIL_TEST_SERVICE_GATED_ONE_API_CREDENTIAL_ID`, and `MAIL_TEST_SERVICE_GATED_ONE_API_CREDENTIAL_SECRET`.
|
|
61
|
+
|
|
62
|
+
SMTP compatibility credentials are still discoverable with `getServiceMailCredentials()` for applications that explicitly implement SMTP themselves. Those compatibility variables are `SMTP_HOST`, `SMTP_PORT`, `SMTP_TLS_MODE`, `SMTP_USERNAME`, and `SMTP_PASSWORD`, plus scoped `MAIL_<TOKEN>_SMTP_*` variants. They are not used by `sendMail()`, `sendText()`, `sendHtml()`, or `registerInboundHandler()`.
|
|
61
63
|
|
|
62
64
|
```typescript
|
|
63
65
|
import { SzPlatformClient } from '@serve.zone/platformclient';
|
|
@@ -102,9 +104,32 @@ console.log(verificationCode); // 123456
|
|
|
102
104
|
|
|
103
105
|
The current SMS verification method is spelled `sendSmsVerifcation()` in code. Use that exact method name until the public API changes.
|
|
104
106
|
|
|
107
|
+
## Lifecycle
|
|
108
|
+
|
|
109
|
+
`SzPlatformClient` keeps TypedSocket connections open for platform requests and typed service-mail delivery. Call `stop()` when a short-lived process, worker, or test is done with the client.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const client = new SzPlatformClient({
|
|
113
|
+
token: process.env.SERVEZONE_PLATFORM_TOKEN,
|
|
114
|
+
platformUrl: process.env.SERVEZONE_PLATFORM_URL,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await client.init();
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await client.emailConnector.sendText({
|
|
121
|
+
to: 'user@example.com',
|
|
122
|
+
subject: 'Done',
|
|
123
|
+
text: 'The job has finished.',
|
|
124
|
+
});
|
|
125
|
+
} finally {
|
|
126
|
+
await client.stop();
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
105
130
|
## Connector Examples
|
|
106
131
|
|
|
107
|
-
Service mail over managed
|
|
132
|
+
Service mail over managed TypedSocket credentials:
|
|
108
133
|
|
|
109
134
|
```typescript
|
|
110
135
|
const status = await client.emailConnector.getServiceMailStatus();
|
|
@@ -118,6 +143,8 @@ if (status.ready) {
|
|
|
118
143
|
}
|
|
119
144
|
```
|
|
120
145
|
|
|
146
|
+
`getServiceMailStatus().ready` means the typed service-mail path is configured. The status also exposes `transport`, `typedUrl`, `typedCredentialConfigured`, and `smtpReady` so applications can distinguish standard TypedSocket mail from explicit SMTP compatibility configuration.
|
|
147
|
+
|
|
121
148
|
Specific sender address:
|
|
122
149
|
|
|
123
150
|
```typescript
|
|
@@ -129,7 +156,18 @@ await client.emailConnector.sendHtml({
|
|
|
129
156
|
});
|
|
130
157
|
```
|
|
131
158
|
|
|
132
|
-
|
|
159
|
+
Typed inbound mail registration:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
await client.emailConnector.registerInboundHandler(async (message) => {
|
|
163
|
+
console.log(message.from, message.to, message.subject);
|
|
164
|
+
return { accepted: true, workAppMessageId: message.messageId };
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`registerInboundHandler()` registers this client connection as the typed endpoint for the configured service mail address. dcrouter then delivers inbound messages through the shared `deliverInboundMail` TypedRequest contract.
|
|
169
|
+
|
|
170
|
+
Inbound message normalization for webhook or direct TypedRequest-style delivery:
|
|
133
171
|
|
|
134
172
|
```typescript
|
|
135
173
|
const inboundHandler = client.emailConnector.createInboundHandler(async (message) => {
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -174,6 +174,13 @@ export class SzPlatformClient {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
public async stop(): Promise<void> {
|
|
178
|
+
await this.emailConnector.stop();
|
|
179
|
+
if (this.typedsocket) {
|
|
180
|
+
await this.typedsocket.stop();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
177
184
|
private async discoverPlatformBindings() {
|
|
178
185
|
const bindings: plugins.servezoneInterfaces.platform.IPlatformBinding[] = [];
|
|
179
186
|
const envBindings = await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_BINDINGS');
|
|
@@ -15,14 +15,26 @@ export interface IServiceMailSmtpCredentials {
|
|
|
15
15
|
addressToken?: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export interface IServiceMailTypedCredentials {
|
|
19
|
+
from: string;
|
|
20
|
+
typedUrl: string;
|
|
21
|
+
credentialId: string;
|
|
22
|
+
credentialSecret: string;
|
|
23
|
+
addressToken?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
export interface IServiceMailStatus {
|
|
19
27
|
ready: boolean;
|
|
20
28
|
from?: string;
|
|
21
29
|
host?: string;
|
|
22
30
|
port?: number;
|
|
23
31
|
tlsMode?: TServiceMailTlsMode;
|
|
32
|
+
typedUrl?: string;
|
|
33
|
+
transport?: 'typedsocket' | 'smtp' | 'none';
|
|
24
34
|
usernameConfigured: boolean;
|
|
25
35
|
passwordConfigured: boolean;
|
|
36
|
+
typedCredentialConfigured?: boolean;
|
|
37
|
+
smtpReady?: boolean;
|
|
26
38
|
missing: string[];
|
|
27
39
|
}
|
|
28
40
|
|
|
@@ -66,19 +78,22 @@ export interface IServiceMailInboundHandlerResult {
|
|
|
66
78
|
export type IServiceMailInboundHandleResult =
|
|
67
79
|
plugins.servezoneInterfaces.requests.mail.IReq_DeliverInboundMail['response'];
|
|
68
80
|
|
|
69
|
-
interface INodemailerSendResult {
|
|
70
|
-
messageId?: string;
|
|
71
|
-
accepted?: unknown[];
|
|
72
|
-
rejected?: unknown[];
|
|
73
|
-
response?: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
81
|
export type TServiceMailInboundHandler = (
|
|
77
82
|
messageArg: IServiceMailInboundMessage,
|
|
78
83
|
) => Promise<IServiceMailInboundHandlerResult | void> | IServiceMailInboundHandlerResult | void;
|
|
79
84
|
|
|
80
85
|
export class SzEmailConnector {
|
|
81
86
|
public platformClientRef: SzPlatformClient;
|
|
87
|
+
private mailTypedSocket?: plugins.typedsocket.TypedSocket;
|
|
88
|
+
private mailTypedSocketUrl?: string;
|
|
89
|
+
private mailTypedSocketPromise?: Promise<plugins.typedsocket.TypedSocket>;
|
|
90
|
+
private mailTypedSocketAbortController?: AbortController;
|
|
91
|
+
private mailTypedSocketStatusSubscription?: { unsubscribe: () => void };
|
|
92
|
+
private inboundHandler?: TServiceMailInboundHandler;
|
|
93
|
+
private inboundTypedHandlerRegistered = false;
|
|
94
|
+
private inboundEndpointRegistrations = new Set<string>();
|
|
95
|
+
private inboundEndpointReplayPromise?: Promise<void>;
|
|
96
|
+
private readonly inboundEndpointReplayRetryDelaysMs = [500, 1000, 2000, 5000];
|
|
82
97
|
|
|
83
98
|
constructor(platformClientRefArg: SzPlatformClient) {
|
|
84
99
|
this.platformClientRef = platformClientRefArg;
|
|
@@ -122,23 +137,33 @@ export class SzEmailConnector {
|
|
|
122
137
|
const missingPrefix = useDefaultEnv || !token ? undefined : token;
|
|
123
138
|
const port = env.smtpPort ? Number(env.smtpPort) : undefined;
|
|
124
139
|
const tlsMode = this.normalizeTlsMode(env.smtpTlsMode || 'starttls');
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
if (!env.
|
|
140
|
+
const typedMissing: string[] = [];
|
|
141
|
+
const smtpMissing: string[] = [];
|
|
142
|
+
if (!env.typedUrl) typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_TYPED_URL` : 'MAIL_TYPED_URL');
|
|
143
|
+
if (!env.apiCredentialId) typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_API_CREDENTIAL_ID` : 'MAIL_API_CREDENTIAL_ID');
|
|
144
|
+
if (!env.apiCredentialSecret) typedMissing.push(missingPrefix ? `MAIL_${missingPrefix}_API_CREDENTIAL_SECRET` : 'MAIL_API_CREDENTIAL_SECRET');
|
|
145
|
+
if (!env.smtpHost) smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_HOST` : 'SMTP_HOST');
|
|
128
146
|
if (!env.smtpPort || !Number.isInteger(port) || port! < 1 || port! > 65535) {
|
|
129
|
-
|
|
147
|
+
smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_PORT` : 'SMTP_PORT');
|
|
130
148
|
}
|
|
131
|
-
if (!env.smtpUsername)
|
|
132
|
-
if (!env.smtpPassword)
|
|
149
|
+
if (!env.smtpUsername) smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_USERNAME` : 'SMTP_USERNAME');
|
|
150
|
+
if (!env.smtpPassword) smtpMissing.push(missingPrefix ? `MAIL_${missingPrefix}_SMTP_PASSWORD` : 'SMTP_PASSWORD');
|
|
151
|
+
const fromMissing = env.from ? [] : [missingPrefix ? `MAIL_${missingPrefix}_FROM` : 'MAIL_FROM'];
|
|
152
|
+
const typedReady = fromMissing.length === 0 && typedMissing.length === 0;
|
|
153
|
+
const smtpReady = fromMissing.length === 0 && smtpMissing.length === 0;
|
|
133
154
|
return {
|
|
134
|
-
ready:
|
|
155
|
+
ready: typedReady,
|
|
135
156
|
from: env.from,
|
|
136
157
|
host: env.smtpHost,
|
|
137
158
|
port,
|
|
138
159
|
tlsMode,
|
|
160
|
+
typedUrl: env.typedUrl,
|
|
161
|
+
transport: typedReady ? 'typedsocket' : smtpReady ? 'smtp' : 'none',
|
|
139
162
|
usernameConfigured: Boolean(env.smtpUsername),
|
|
140
163
|
passwordConfigured: Boolean(env.smtpPassword),
|
|
141
|
-
|
|
164
|
+
typedCredentialConfigured: Boolean(env.apiCredentialId && env.apiCredentialSecret),
|
|
165
|
+
smtpReady,
|
|
166
|
+
missing: typedReady ? [] : [...fromMissing, ...typedMissing],
|
|
142
167
|
};
|
|
143
168
|
}
|
|
144
169
|
|
|
@@ -188,38 +213,62 @@ export class SzEmailConnector {
|
|
|
188
213
|
return { messageId: 'debug' };
|
|
189
214
|
}
|
|
190
215
|
|
|
191
|
-
const credentials = await this.
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
216
|
+
const credentials = await this.getServiceMailTypedCredentials(optionsArg.from);
|
|
217
|
+
const typedSocket = await this.getMailTypedSocket(credentials.typedUrl);
|
|
218
|
+
const request = typedSocket.createTypedRequest<plugins.servezoneInterfaces.requests.mail.IReq_EnqueueMail>('enqueueMail');
|
|
219
|
+
const result = await request.fire({
|
|
220
|
+
auth: {
|
|
221
|
+
credentialId: credentials.credentialId,
|
|
222
|
+
credentialSecret: credentials.credentialSecret,
|
|
223
|
+
},
|
|
224
|
+
outboundIdentityId: credentials.credentialId,
|
|
225
|
+
message: {
|
|
226
|
+
from: credentials.from,
|
|
227
|
+
to: this.listToArray(optionsArg.to),
|
|
228
|
+
cc: optionsArg.cc ? this.listToArray(optionsArg.cc) : undefined,
|
|
229
|
+
bcc: optionsArg.bcc ? this.listToArray(optionsArg.bcc) : undefined,
|
|
230
|
+
subject: optionsArg.subject,
|
|
231
|
+
text: optionsArg.text,
|
|
232
|
+
html: optionsArg.html,
|
|
233
|
+
headers: optionsArg.headers,
|
|
234
|
+
attachments: optionsArg.attachments?.map((attachmentArg) => ({
|
|
235
|
+
filename: attachmentArg.filename,
|
|
236
|
+
contentType: attachmentArg.contentType,
|
|
237
|
+
binaryAttachmentString: this.normalizeAttachmentContent(attachmentArg.content),
|
|
238
|
+
})),
|
|
239
|
+
},
|
|
199
240
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
cc: optionsArg.cc ? this.listToArray(optionsArg.cc) : undefined,
|
|
204
|
-
bcc: optionsArg.bcc ? this.listToArray(optionsArg.bcc) : undefined,
|
|
205
|
-
subject: optionsArg.subject,
|
|
206
|
-
text: optionsArg.text,
|
|
207
|
-
html: optionsArg.html,
|
|
208
|
-
headers: optionsArg.headers,
|
|
209
|
-
attachments: optionsArg.attachments?.map((attachmentArg) => ({
|
|
210
|
-
filename: attachmentArg.filename,
|
|
211
|
-
contentType: attachmentArg.contentType,
|
|
212
|
-
content: this.normalizeAttachmentContent(attachmentArg.content),
|
|
213
|
-
})),
|
|
214
|
-
})) as INodemailerSendResult;
|
|
241
|
+
if (!result.accepted) {
|
|
242
|
+
throw new Error(result.message || 'service mail was not accepted by dcrouter');
|
|
243
|
+
}
|
|
215
244
|
return {
|
|
216
|
-
messageId: result.
|
|
217
|
-
accepted:
|
|
218
|
-
rejected:
|
|
219
|
-
response: result.
|
|
245
|
+
messageId: result.spoolItemId,
|
|
246
|
+
accepted: this.listToArray(optionsArg.to),
|
|
247
|
+
rejected: [],
|
|
248
|
+
response: result.message,
|
|
220
249
|
};
|
|
221
250
|
}
|
|
222
251
|
|
|
252
|
+
public async registerInboundHandler(
|
|
253
|
+
handlerArg: TServiceMailInboundHandler,
|
|
254
|
+
addressArg?: string,
|
|
255
|
+
): Promise<plugins.servezoneInterfaces.requests.mail.IReq_RegisterServiceMailEndpoint['response']> {
|
|
256
|
+
this.inboundHandler = handlerArg;
|
|
257
|
+
this.ensureInboundTypedHandler();
|
|
258
|
+
const credentials = await this.getServiceMailTypedCredentials(addressArg);
|
|
259
|
+
const typedSocket = await this.getMailTypedSocket(credentials.typedUrl);
|
|
260
|
+
const result = await this.registerServiceMailEndpoint(typedSocket, credentials);
|
|
261
|
+
const registeredAddresses = result.addresses?.length ? result.addresses : [credentials.from];
|
|
262
|
+
for (const address of registeredAddresses) {
|
|
263
|
+
this.inboundEndpointRegistrations.add(address.trim().toLowerCase());
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
public async stop(): Promise<void> {
|
|
269
|
+
await this.stopMailTypedSocket();
|
|
270
|
+
}
|
|
271
|
+
|
|
223
272
|
public normalizeInboundMessage(payloadArg: unknown): IServiceMailInboundMessage {
|
|
224
273
|
const payload = this.asRecord(payloadArg);
|
|
225
274
|
const deliveryCandidate = this.asRecord(payload.delivery || payload.message || payload);
|
|
@@ -264,6 +313,22 @@ export class SzEmailConnector {
|
|
|
264
313
|
return async (payloadArg: unknown) => await this.handleInboundPayload(payloadArg, handlerArg);
|
|
265
314
|
}
|
|
266
315
|
|
|
316
|
+
private ensureInboundTypedHandler(): void {
|
|
317
|
+
if (this.inboundTypedHandlerRegistered) return;
|
|
318
|
+
this.inboundTypedHandlerRegistered = true;
|
|
319
|
+
this.platformClientRef.typedrouter.addTypedHandler(
|
|
320
|
+
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.mail.IReq_DeliverInboundMail>(
|
|
321
|
+
'deliverInboundMail',
|
|
322
|
+
async (dataArg) => {
|
|
323
|
+
if (!this.inboundHandler) {
|
|
324
|
+
return { accepted: false, message: 'No service mail inbound handler registered' };
|
|
325
|
+
}
|
|
326
|
+
return await this.handleInboundPayload(dataArg.delivery, this.inboundHandler);
|
|
327
|
+
},
|
|
328
|
+
),
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
267
332
|
public async sendNotification(optionsArg: { toArg: string; subject: string; text: string }) {}
|
|
268
333
|
|
|
269
334
|
public async sendActionLink(optionsArg: { toArg: string; subject: string; text: string }) {}
|
|
@@ -275,6 +340,9 @@ export class SzEmailConnector {
|
|
|
275
340
|
smtpTlsMode?: string;
|
|
276
341
|
smtpUsername?: string;
|
|
277
342
|
smtpPassword?: string;
|
|
343
|
+
typedUrl?: string;
|
|
344
|
+
apiCredentialId?: string;
|
|
345
|
+
apiCredentialSecret?: string;
|
|
278
346
|
}> {
|
|
279
347
|
const prefix = tokenArg ? `MAIL_${tokenArg}_` : '';
|
|
280
348
|
return {
|
|
@@ -284,6 +352,9 @@ export class SzEmailConnector {
|
|
|
284
352
|
smtpTlsMode: await this.readMailEnvVar(`${prefix}SMTP_TLS_MODE`),
|
|
285
353
|
smtpUsername: await this.readMailEnvVar(`${prefix}SMTP_USERNAME`),
|
|
286
354
|
smtpPassword: await this.readMailEnvVar(`${prefix}SMTP_PASSWORD`),
|
|
355
|
+
typedUrl: await this.readMailEnvVar(tokenArg ? `${prefix}TYPED_URL` : 'MAIL_TYPED_URL'),
|
|
356
|
+
apiCredentialId: await this.readMailEnvVar(tokenArg ? `${prefix}API_CREDENTIAL_ID` : 'MAIL_API_CREDENTIAL_ID'),
|
|
357
|
+
apiCredentialSecret: await this.readMailEnvVar(tokenArg ? `${prefix}API_CREDENTIAL_SECRET` : 'MAIL_API_CREDENTIAL_SECRET'),
|
|
287
358
|
};
|
|
288
359
|
}
|
|
289
360
|
|
|
@@ -310,10 +381,230 @@ export class SzEmailConnector {
|
|
|
310
381
|
smtpTlsMode?: string;
|
|
311
382
|
smtpUsername?: string;
|
|
312
383
|
smtpPassword?: string;
|
|
384
|
+
typedUrl?: string;
|
|
385
|
+
apiCredentialId?: string;
|
|
386
|
+
apiCredentialSecret?: string;
|
|
313
387
|
}): boolean {
|
|
314
388
|
return Boolean(envArg && Object.values(envArg).some(Boolean));
|
|
315
389
|
}
|
|
316
390
|
|
|
391
|
+
private async getServiceMailTypedCredentials(addressArg?: string): Promise<IServiceMailTypedCredentials> {
|
|
392
|
+
const requestedAddress = addressArg?.trim().toLowerCase();
|
|
393
|
+
const requestedToken = requestedAddress ? this.getMailEnvToken(requestedAddress) : undefined;
|
|
394
|
+
const scopedEnv = requestedToken ? await this.readMailEnv(requestedToken) : undefined;
|
|
395
|
+
const hasScopedConfig = scopedEnv && Object.values(scopedEnv).some(Boolean);
|
|
396
|
+
const env = hasScopedConfig ? scopedEnv! : await this.readMailEnv();
|
|
397
|
+
const from = env.from?.trim().toLowerCase();
|
|
398
|
+
if (!from) throw new Error('MAIL_FROM is required for typed service mail');
|
|
399
|
+
if (requestedAddress && from !== requestedAddress) {
|
|
400
|
+
throw new Error(`No typed service mail credentials are configured for ${requestedAddress}`);
|
|
401
|
+
}
|
|
402
|
+
if (!env.typedUrl) throw new Error('MAIL_TYPED_URL is required for typed service mail');
|
|
403
|
+
if (!env.apiCredentialId) throw new Error('MAIL_API_CREDENTIAL_ID is required for typed service mail');
|
|
404
|
+
if (!env.apiCredentialSecret) throw new Error('MAIL_API_CREDENTIAL_SECRET is required for typed service mail');
|
|
405
|
+
return {
|
|
406
|
+
from,
|
|
407
|
+
typedUrl: this.normalizeTypedSocketUrl(env.typedUrl),
|
|
408
|
+
credentialId: env.apiCredentialId,
|
|
409
|
+
credentialSecret: env.apiCredentialSecret,
|
|
410
|
+
addressToken: hasScopedConfig ? requestedToken : undefined,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private async getMailTypedSocket(urlArg: string): Promise<plugins.typedsocket.TypedSocket> {
|
|
415
|
+
const normalizedUrl = this.normalizeTypedSocketUrl(urlArg);
|
|
416
|
+
if (this.mailTypedSocket && this.mailTypedSocketUrl === normalizedUrl) {
|
|
417
|
+
return this.mailTypedSocket;
|
|
418
|
+
}
|
|
419
|
+
if (this.mailTypedSocketPromise && this.mailTypedSocketUrl === normalizedUrl) {
|
|
420
|
+
return await this.mailTypedSocketPromise;
|
|
421
|
+
}
|
|
422
|
+
if (this.mailTypedSocket || this.mailTypedSocketPromise) {
|
|
423
|
+
await this.stopMailTypedSocket();
|
|
424
|
+
}
|
|
425
|
+
this.mailTypedSocketUrl = normalizedUrl;
|
|
426
|
+
const abortController = new AbortController();
|
|
427
|
+
this.mailTypedSocketAbortController = abortController;
|
|
428
|
+
const socketPromise = plugins.typedsocket.TypedSocket.createClient(
|
|
429
|
+
this.platformClientRef.typedrouter,
|
|
430
|
+
normalizedUrl,
|
|
431
|
+
{ autoReconnect: true, abortSignal: abortController.signal },
|
|
432
|
+
);
|
|
433
|
+
this.mailTypedSocketPromise = socketPromise;
|
|
434
|
+
try {
|
|
435
|
+
const socket = await socketPromise;
|
|
436
|
+
if (this.mailTypedSocketPromise === socketPromise && this.mailTypedSocketUrl === normalizedUrl) {
|
|
437
|
+
this.mailTypedSocket = socket;
|
|
438
|
+
this.watchMailTypedSocketStatus(socket);
|
|
439
|
+
} else {
|
|
440
|
+
await socket.stop();
|
|
441
|
+
}
|
|
442
|
+
return socket;
|
|
443
|
+
} catch (error) {
|
|
444
|
+
if (this.mailTypedSocketPromise === socketPromise) {
|
|
445
|
+
this.mailTypedSocketPromise = undefined;
|
|
446
|
+
this.mailTypedSocketUrl = undefined;
|
|
447
|
+
this.mailTypedSocketAbortController = undefined;
|
|
448
|
+
}
|
|
449
|
+
throw error;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
private async stopMailTypedSocket(): Promise<void> {
|
|
454
|
+
const socket = this.mailTypedSocket;
|
|
455
|
+
const socketPromise = this.mailTypedSocketPromise;
|
|
456
|
+
const abortController = this.mailTypedSocketAbortController;
|
|
457
|
+
const statusSubscription = this.mailTypedSocketStatusSubscription;
|
|
458
|
+
this.mailTypedSocket = undefined;
|
|
459
|
+
this.mailTypedSocketPromise = undefined;
|
|
460
|
+
this.mailTypedSocketUrl = undefined;
|
|
461
|
+
this.mailTypedSocketAbortController = undefined;
|
|
462
|
+
this.mailTypedSocketStatusSubscription = undefined;
|
|
463
|
+
statusSubscription?.unsubscribe();
|
|
464
|
+
abortController?.abort();
|
|
465
|
+
if (socket) {
|
|
466
|
+
await socket.stop();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (socketPromise) {
|
|
470
|
+
try {
|
|
471
|
+
const pendingSocket = await socketPromise;
|
|
472
|
+
await pendingSocket.stop();
|
|
473
|
+
} catch {
|
|
474
|
+
// The pending connection already failed; there is no socket to stop.
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private watchMailTypedSocketStatus(socketArg: plugins.typedsocket.TypedSocket): void {
|
|
480
|
+
this.mailTypedSocketStatusSubscription?.unsubscribe();
|
|
481
|
+
this.mailTypedSocketStatusSubscription = socketArg.statusSubject.subscribe((statusArg) => {
|
|
482
|
+
void this.handleMailTypedSocketStatus(socketArg, statusArg);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private async handleMailTypedSocketStatus(
|
|
487
|
+
socketArg: plugins.typedsocket.TypedSocket,
|
|
488
|
+
statusArg: plugins.typedsocket.TConnectionStatus,
|
|
489
|
+
): Promise<void> {
|
|
490
|
+
if (statusArg !== 'connected' || this.mailTypedSocket !== socketArg) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
await this.replayInboundEndpointRegistrationsWithRetry(socketArg);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
console.warn('Could not re-register service mail endpoint after reconnect:', (error as Error).message);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
private async replayInboundEndpointRegistrationsWithRetry(
|
|
501
|
+
socketArg: plugins.typedsocket.TypedSocket,
|
|
502
|
+
): Promise<void> {
|
|
503
|
+
if (!this.inboundEndpointRegistrations.size) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (this.inboundEndpointReplayPromise) {
|
|
507
|
+
return await this.inboundEndpointReplayPromise;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const replayPromise = this.replayInboundEndpointRegistrationsWithRetryInner(socketArg);
|
|
511
|
+
this.inboundEndpointReplayPromise = replayPromise;
|
|
512
|
+
try {
|
|
513
|
+
await replayPromise;
|
|
514
|
+
} finally {
|
|
515
|
+
if (this.inboundEndpointReplayPromise === replayPromise) {
|
|
516
|
+
this.inboundEndpointReplayPromise = undefined;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private async replayInboundEndpointRegistrationsWithRetryInner(
|
|
522
|
+
socketArg: plugins.typedsocket.TypedSocket,
|
|
523
|
+
): Promise<void> {
|
|
524
|
+
let lastError: unknown;
|
|
525
|
+
const delays = [0, ...this.inboundEndpointReplayRetryDelaysMs];
|
|
526
|
+
for (let attemptIndex = 0; attemptIndex < delays.length; attemptIndex++) {
|
|
527
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (attemptIndex > 0) {
|
|
531
|
+
const shouldContinue = await this.waitForInboundEndpointReplayRetry(socketArg, delays[attemptIndex]);
|
|
532
|
+
if (!shouldContinue) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
await this.replayInboundEndpointRegistrationsOnce(socketArg);
|
|
538
|
+
return;
|
|
539
|
+
} catch (error) {
|
|
540
|
+
lastError = error;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
throw lastError instanceof Error
|
|
544
|
+
? lastError
|
|
545
|
+
: new Error('Could not re-register service mail endpoint after reconnect');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
private async replayInboundEndpointRegistrationsOnce(
|
|
549
|
+
socketArg: plugins.typedsocket.TypedSocket,
|
|
550
|
+
): Promise<void> {
|
|
551
|
+
for (const address of this.inboundEndpointRegistrations.values()) {
|
|
552
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const credentials = await this.getServiceMailTypedCredentials(address);
|
|
556
|
+
if (this.normalizeTypedSocketUrl(credentials.typedUrl) !== this.mailTypedSocketUrl) {
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
await this.registerServiceMailEndpoint(socketArg, credentials);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private async waitForInboundEndpointReplayRetry(
|
|
564
|
+
socketArg: plugins.typedsocket.TypedSocket,
|
|
565
|
+
delayMsArg: number,
|
|
566
|
+
): Promise<boolean> {
|
|
567
|
+
if (this.mailTypedSocket !== socketArg) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
const abortSignal = this.mailTypedSocketAbortController?.signal;
|
|
571
|
+
if (abortSignal?.aborted) {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
return await new Promise<boolean>((resolve) => {
|
|
575
|
+
const resolveOnce = (resultArg: boolean) => {
|
|
576
|
+
clearTimeout(timeout);
|
|
577
|
+
abortSignal?.removeEventListener('abort', abortHandler);
|
|
578
|
+
resolve(resultArg && this.mailTypedSocket === socketArg);
|
|
579
|
+
};
|
|
580
|
+
const abortHandler = () => resolveOnce(false);
|
|
581
|
+
const timeout = setTimeout(() => resolveOnce(true), delayMsArg);
|
|
582
|
+
abortSignal?.addEventListener('abort', abortHandler, { once: true });
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
private async registerServiceMailEndpoint(
|
|
587
|
+
typedSocketArg: plugins.typedsocket.TypedSocket,
|
|
588
|
+
credentialsArg: IServiceMailTypedCredentials,
|
|
589
|
+
): Promise<plugins.servezoneInterfaces.requests.mail.IReq_RegisterServiceMailEndpoint['response']> {
|
|
590
|
+
const request = typedSocketArg.createTypedRequest<plugins.servezoneInterfaces.requests.mail.IReq_RegisterServiceMailEndpoint>('registerServiceMailEndpoint');
|
|
591
|
+
const result = await request.fire({
|
|
592
|
+
auth: {
|
|
593
|
+
credentialId: credentialsArg.credentialId,
|
|
594
|
+
credentialSecret: credentialsArg.credentialSecret,
|
|
595
|
+
},
|
|
596
|
+
addresses: [credentialsArg.from],
|
|
597
|
+
});
|
|
598
|
+
if (!result.success) {
|
|
599
|
+
throw new Error(result.message || 'Could not register service mail endpoint');
|
|
600
|
+
}
|
|
601
|
+
return result;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private normalizeTypedSocketUrl(urlArg: string): string {
|
|
605
|
+
return urlArg.trim().replace(/\/typedrequest\/?$/, '').replace(/\/+$/, '');
|
|
606
|
+
}
|
|
607
|
+
|
|
317
608
|
private normalizeTlsMode(valueArg: string): TServiceMailTlsMode {
|
|
318
609
|
if (valueArg === 'plain' || valueArg === 'starttls' || valueArg === 'implicitTls') return valueArg;
|
|
319
610
|
throw new Error(`Invalid SMTP_TLS_MODE: ${valueArg}`);
|
|
@@ -328,8 +619,8 @@ export class SzEmailConnector {
|
|
|
328
619
|
return Array.isArray(valueArg) ? valueArg : [valueArg];
|
|
329
620
|
}
|
|
330
621
|
|
|
331
|
-
private normalizeAttachmentContent(contentArg: string | Uint8Array): string
|
|
332
|
-
return
|
|
622
|
+
private normalizeAttachmentContent(contentArg: string | Uint8Array): string {
|
|
623
|
+
return Buffer.from(contentArg).toString('base64');
|
|
333
624
|
}
|
|
334
625
|
|
|
335
626
|
private asRecord(valueArg: unknown): Record<string, unknown> {
|