@travetto/email-compiler 3.1.21 → 3.1.22
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/package.json +1 -1
- package/src/compiler.ts +1 -0
- package/support/bin/config.ts +17 -14
- package/support/bin/editor.ts +12 -8
- package/support/bin/send.ts +12 -9
- package/support/cli.email_editor.ts +3 -12
- package/support/cli.email_test.ts +3 -4
package/package.json
CHANGED
package/src/compiler.ts
CHANGED
|
@@ -128,6 +128,7 @@ export class EmailCompiler {
|
|
|
128
128
|
try {
|
|
129
129
|
if (EmailCompileUtil.isTemplateFile(file)) {
|
|
130
130
|
await this.compile(file, true);
|
|
131
|
+
console.log(`Successfully compiled ${1} templates`, { changed: [file] });
|
|
131
132
|
yield file;
|
|
132
133
|
} else if (VALID_FILE(file)) {
|
|
133
134
|
const rootFile = file.replace(/\/resources.*/, '/package.json');
|
package/support/bin/config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
|
|
3
|
-
import { path } from '@travetto/manifest';
|
|
3
|
+
import { RootIndex, path } from '@travetto/manifest';
|
|
4
4
|
import { YamlUtil } from '@travetto/yaml';
|
|
5
5
|
|
|
6
6
|
interface ConfigType {
|
|
@@ -22,7 +22,7 @@ interface ConfigType {
|
|
|
22
22
|
*/
|
|
23
23
|
export class $EditorConfig {
|
|
24
24
|
|
|
25
|
-
#configFile =
|
|
25
|
+
#configFile: Record<string, string> = {};
|
|
26
26
|
#defaultConfig = {
|
|
27
27
|
to: 'my-email@gmail.com',
|
|
28
28
|
from: 'from-email@gmail.com',
|
|
@@ -42,9 +42,10 @@ export class $EditorConfig {
|
|
|
42
42
|
/**
|
|
43
43
|
*
|
|
44
44
|
*/
|
|
45
|
-
async get(): Promise<ConfigType> {
|
|
45
|
+
async get(file: string): Promise<ConfigType> {
|
|
46
46
|
try {
|
|
47
|
-
const
|
|
47
|
+
const mod = RootIndex.getModuleFromSource(file)!.name;
|
|
48
|
+
const content = await fs.readFile(this.#configFile[mod], 'utf8');
|
|
48
49
|
return YamlUtil.parse<ConfigType>(content);
|
|
49
50
|
} catch {
|
|
50
51
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -52,13 +53,13 @@ export class $EditorConfig {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
async getContext(): Promise<Exclude<ConfigType['context'], undefined>> {
|
|
56
|
-
const conf = await this.get();
|
|
56
|
+
async getContext(file: string): Promise<Exclude<ConfigType['context'], undefined>> {
|
|
57
|
+
const conf = await this.get(file);
|
|
57
58
|
return conf.context ?? {};
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
async getSenderConfig(): Promise<Exclude<ConfigType['sender'], undefined>> {
|
|
61
|
-
const conf = await this.get();
|
|
61
|
+
async getSenderConfig(file: string): Promise<Exclude<ConfigType['sender'], undefined>> {
|
|
62
|
+
const conf = await this.get(file);
|
|
62
63
|
return conf.sender ?? {};
|
|
63
64
|
}
|
|
64
65
|
|
|
@@ -66,13 +67,15 @@ export class $EditorConfig {
|
|
|
66
67
|
return YamlUtil.serialize(this.#defaultConfig);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
async ensureConfig(): Promise<string> {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
async ensureConfig(file: string): Promise<string> {
|
|
71
|
+
console.log('Ensuring config', file);
|
|
72
|
+
const mod = RootIndex.getModuleFromSource(file)!;
|
|
73
|
+
const resolved = this.#configFile[mod.name] ??= path.resolve(mod.sourcePath, 'resources/email/dev.yml');
|
|
74
|
+
if (!(await fs.stat(resolved).catch(() => { }))) {
|
|
75
|
+
await fs.mkdir(path.dirname(resolved), { recursive: true });
|
|
76
|
+
await fs.writeFile(resolved, this.getDefaultConfig(), { encoding: 'utf8' });
|
|
74
77
|
}
|
|
75
|
-
return
|
|
78
|
+
return resolved;
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
|
package/support/bin/editor.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ShutdownManager } from '@travetto/base';
|
|
2
|
+
|
|
1
3
|
import { EmailCompilationManager } from './manager';
|
|
2
4
|
import { EditorSendService } from './send';
|
|
3
5
|
import { EditorConfig } from './config';
|
|
@@ -6,7 +8,7 @@ import { EmailCompiler } from '../../src/compiler';
|
|
|
6
8
|
import { EmailCompileUtil } from '../../src/util';
|
|
7
9
|
|
|
8
10
|
type InboundMessage =
|
|
9
|
-
{ type: 'configure' } |
|
|
11
|
+
{ type: 'configure', file: string } |
|
|
10
12
|
{ type: 'redraw', file: string } |
|
|
11
13
|
{ type: 'send', file: string, from?: string, to?: string };
|
|
12
14
|
|
|
@@ -23,12 +25,10 @@ type OutboundMessage =
|
|
|
23
25
|
export class EditorState {
|
|
24
26
|
|
|
25
27
|
#lastFile = '';
|
|
26
|
-
#sender: EditorSendService;
|
|
27
28
|
#template: EmailCompilationManager;
|
|
28
29
|
|
|
29
30
|
constructor(template: EmailCompilationManager) {
|
|
30
31
|
this.#template = template;
|
|
31
|
-
this.#sender = new EditorSendService();
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async renderFile(file: string): Promise<void> {
|
|
@@ -36,7 +36,7 @@ export class EditorState {
|
|
|
36
36
|
if (file) {
|
|
37
37
|
try {
|
|
38
38
|
const content = await this.#template.resolveCompiledTemplate(
|
|
39
|
-
file, await EditorConfig.getContext()
|
|
39
|
+
file, await EditorConfig.getContext(file)
|
|
40
40
|
);
|
|
41
41
|
this.response({
|
|
42
42
|
type: 'changed',
|
|
@@ -60,7 +60,7 @@ export class EditorState {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
async onConfigure(msg: InboundMessage & { type: 'configure' }): Promise<void> {
|
|
63
|
-
this.response({ type: 'configured', file: await EditorConfig.ensureConfig() });
|
|
63
|
+
this.response({ type: 'configured', file: await EditorConfig.ensureConfig(msg.file) });
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
async #onRedraw(msg: InboundMessage & { type: 'redraw' }): Promise<void> {
|
|
@@ -77,15 +77,15 @@ export class EditorState {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
async onSend(msg: InboundMessage & { type: 'send' }): Promise<void> {
|
|
80
|
-
const cfg = await EditorConfig.get();
|
|
80
|
+
const cfg = await EditorConfig.get(msg.file);
|
|
81
81
|
const to = msg.to || cfg.to;
|
|
82
82
|
const from = msg.from || cfg.from;
|
|
83
83
|
const content = await this.#template.resolveCompiledTemplate(
|
|
84
|
-
msg.file
|
|
84
|
+
msg.file, await EditorConfig.getContext(msg.file)
|
|
85
85
|
);
|
|
86
86
|
|
|
87
87
|
try {
|
|
88
|
-
const url = await
|
|
88
|
+
const url = await EditorSendService.sendEmail(msg.file, { from, to, ...content, });
|
|
89
89
|
this.response({ type: 'sent', to, file: msg.file, ...url });
|
|
90
90
|
} catch (err) {
|
|
91
91
|
if (err && err instanceof Error) {
|
|
@@ -107,6 +107,10 @@ export class EditorState {
|
|
|
107
107
|
case 'send': this.onSend(msg); break;
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
|
+
|
|
111
|
+
process.on('disconnect', () => ShutdownManager.execute());
|
|
112
|
+
process.send?.('ready');
|
|
113
|
+
|
|
110
114
|
for await (const f of EmailCompiler.watchCompile()) {
|
|
111
115
|
await this.renderFile(f);
|
|
112
116
|
}
|
package/support/bin/send.ts
CHANGED
|
@@ -3,20 +3,23 @@ import { MailTransportTarget } from '@travetto/email/src/internal/types';
|
|
|
3
3
|
import { DependencyRegistry } from '@travetto/di';
|
|
4
4
|
|
|
5
5
|
import { EditorConfig } from './config';
|
|
6
|
+
import { RootIndex } from '@travetto/manifest';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Util for sending emails
|
|
9
10
|
*/
|
|
10
11
|
export class EditorSendService {
|
|
11
12
|
|
|
12
|
-
#svc: MailService;
|
|
13
|
+
static #svc: Record<string, MailService> = {};
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Get mail service
|
|
16
17
|
*/
|
|
17
|
-
async getMailService(): Promise<MailService> {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
static async getMailService(file: string): Promise<MailService> {
|
|
19
|
+
const mod = RootIndex.getModuleFromSource(file)!.name;
|
|
20
|
+
|
|
21
|
+
if (!this.#svc[mod]) {
|
|
22
|
+
const senderConfig = await EditorConfig.getSenderConfig(file);
|
|
20
23
|
|
|
21
24
|
if (senderConfig?.host?.includes('ethereal.email')) {
|
|
22
25
|
const cls = class { };
|
|
@@ -39,22 +42,22 @@ ${EditorConfig.getDefaultConfig()}`.trim();
|
|
|
39
42
|
throw new Error(errorMessage);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
this.#svc = await DependencyRegistry.getInstance(MailService);
|
|
45
|
+
this.#svc[mod] = await DependencyRegistry.getInstance(MailService);
|
|
43
46
|
}
|
|
44
|
-
return this.#svc;
|
|
47
|
+
return this.#svc[mod];
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
/**
|
|
48
51
|
* Resolve template
|
|
49
52
|
*/
|
|
50
|
-
async sendEmail(message: MessageOptions): Promise<{
|
|
53
|
+
static async sendEmail(file: string, message: MessageOptions): Promise<{
|
|
51
54
|
url?: string | false;
|
|
52
55
|
}> {
|
|
53
56
|
const to = message.to!;
|
|
54
57
|
try {
|
|
55
58
|
console.log('Sending email', { to });
|
|
56
59
|
// Let the engine template
|
|
57
|
-
const svc = await this.getMailService();
|
|
60
|
+
const svc = await this.getMailService(file);
|
|
58
61
|
if (!svc) {
|
|
59
62
|
throw new Error('Node mailer support is missing');
|
|
60
63
|
}
|
|
@@ -62,7 +65,7 @@ ${EditorConfig.getDefaultConfig()}`.trim();
|
|
|
62
65
|
const info = await svc.send<{ host?: string } & SentMessage>(message);
|
|
63
66
|
console.log('Sent email', { to });
|
|
64
67
|
|
|
65
|
-
const senderConfig = await EditorConfig.getSenderConfig();
|
|
68
|
+
const senderConfig = await EditorConfig.getSenderConfig(file);
|
|
66
69
|
return senderConfig.host?.includes('ethereal.email') ? {
|
|
67
70
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
|
68
71
|
url: (await import('nodemailer')).getTestMessageUrl(info as any)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { GlobalEnvConfig
|
|
1
|
+
import { GlobalEnvConfig } from '@travetto/base';
|
|
2
2
|
import { CliCommand } from '@travetto/cli';
|
|
3
|
-
import { RootIndex } from '@travetto/manifest';
|
|
4
3
|
import { RootRegistry } from '@travetto/registry';
|
|
5
4
|
|
|
6
5
|
import { EditorState } from './bin/editor';
|
|
@@ -11,19 +10,11 @@ import { EmailCompilationManager } from './bin/manager';
|
|
|
11
10
|
export class EmailEditorCommand {
|
|
12
11
|
|
|
13
12
|
envInit(): GlobalEnvConfig {
|
|
14
|
-
return {
|
|
15
|
-
envName: 'dev',
|
|
16
|
-
resourcePaths: [`${RootIndex.getModule('@travetto/email-compiler')!.sourcePath}/resources`]
|
|
17
|
-
};
|
|
13
|
+
return { envName: 'dev', dynamic: true };
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
async main(): Promise<void> {
|
|
21
17
|
await RootRegistry.init();
|
|
22
|
-
|
|
23
|
-
await editor.init();
|
|
24
|
-
if (process.send) {
|
|
25
|
-
process.on('disconnect', () => ShutdownManager.execute());
|
|
26
|
-
process.send('ready');
|
|
27
|
-
}
|
|
18
|
+
await new EditorState(await EmailCompilationManager.createInstance()).init();
|
|
28
19
|
}
|
|
29
20
|
}
|
|
@@ -25,10 +25,9 @@ export class EmailTestCommand implements CliCommandShape {
|
|
|
25
25
|
await EmailCompiler.compile(file, true);
|
|
26
26
|
|
|
27
27
|
const mgr = await EmailCompilationManager.createInstance();
|
|
28
|
-
const
|
|
29
|
-
const
|
|
28
|
+
const cfg = await EditorConfig.get(file);
|
|
29
|
+
const content = await mgr.resolveCompiledTemplate(file, await EditorConfig.getContext(file));
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
await send.sendEmail({ from: cfg.from, to, ...content, });
|
|
31
|
+
await EditorSendService.sendEmail(file, { from: cfg.from, to, ...content, });
|
|
33
32
|
}
|
|
34
33
|
}
|