@technomoron/mail-magic-client 1.0.30 → 1.0.32
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/CHANGES +22 -0
- package/README.md +2 -65
- package/dist/cjs/mail-magic-client.d.ts +24 -18
- package/dist/cjs/mail-magic-client.js +6 -5
- package/dist/esm/mail-magic-client.js +6 -5
- package/dist/mail-magic-client.js +322 -325
- package/package.json +46 -51
- package/dist/cli-env.js +0 -55
- package/dist/cli-helpers.js +0 -405
- package/dist/cli-version.js +0 -33
- package/dist/cli.js +0 -325
- package/dist/preprocess.js +0 -308
package/CHANGES
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
CHANGES
|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
Unreleased (2026-02-22)
|
|
5
|
+
|
|
6
|
+
- chore(release): add package-level `release:check` script and wire `release` to shared publish script.
|
|
7
|
+
- chore(scripts): replace `rm -rf` cleanup scripts with `rimraf`.
|
|
8
|
+
- test(logging): quiet package test output by default (silent Vitest with compact dot reporter).
|
|
9
|
+
- (Changes generated/assisted by Codex (profile: chatgpt-5.3-codex/medium).)
|
|
10
|
+
|
|
11
|
+
Version 1.0.32 (2026-02-22)
|
|
12
|
+
|
|
13
|
+
- chore(changes): normalize this package changelog to required CHANGES format.
|
|
14
|
+
- (Changes generated/assisted by Codex (profile: chatgpt-5.3-codex/medium).)
|
|
15
|
+
|
|
16
|
+
Version 1.0.31 (2026-02-19)
|
|
17
|
+
|
|
18
|
+
- Extract CLI implementation to dedicated `@technomoron/mail-magic-cli`
|
|
19
|
+
package; remove CLI build/bin and CLI-only dependencies from this package.
|
|
20
|
+
- Replace `forEach` with `for...of` and use separate `const` declarations in
|
|
21
|
+
`validateEmails` for consistency with server-side style.
|
|
22
|
+
|
|
1
23
|
Version 1.0.30 (2026-02-17)
|
|
2
24
|
|
|
3
25
|
- Refactor template preprocess compilation to use per-invocation configuration
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @technomoron/mail-magic-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed client library for the mail-magic server.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -95,73 +95,10 @@ await client.sendFormMessage({
|
|
|
95
95
|
|
|
96
96
|
## CLI
|
|
97
97
|
|
|
98
|
-
The package
|
|
99
|
-
|
|
100
|
-
### .mmcli-env
|
|
101
|
-
|
|
102
|
-
Create `.mmcli-env` in your working directory to set defaults:
|
|
103
|
-
|
|
104
|
-
```ini
|
|
105
|
-
MMCLI_API=http://127.0.0.1:3776
|
|
106
|
-
MMCLI_TOKEN=example-token
|
|
107
|
-
MMCLI_DOMAIN=example.test
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
`MMCLI_TOKEN` is treated as the server token string. As a convenience, `MMCLI_USERNAME` + `MMCLI_PASSWORD` can be used
|
|
111
|
-
to build a combined token string (for legacy setups).
|
|
112
|
-
|
|
113
|
-
### Template Commands
|
|
114
|
-
|
|
115
|
-
Compile a template locally:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
mm-cli compile --input ./templates --output ./templates-dist
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Push a single transactional template (compile + upload):
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
mm-cli push --template tx-template/en/welcome --domain example.test --input ./templates
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Dry-run a single template upload:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
mm-cli push --template tx-template/en/welcome --domain example.test --input ./templates --dry-run
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Push an entire config-style directory:
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
mm-cli push-dir --input ./data --domain example.test
|
|
137
|
-
mm-cli push-dir --input ./data --domain example.test --dry-run
|
|
138
|
-
mm-cli push-dir --input ./data --domain example.test --skip-assets
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Asset Uploads
|
|
142
|
-
|
|
143
|
-
Upload stand-alone domain assets:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
mm-cli assets --file ./logo.png --domain example.test
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Dry-run an asset upload:
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
mm-cli assets --file ./logo.png --domain example.test --dry-run
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Upload assets scoped to a template:
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
mm-cli assets --file ./hero.png --domain example.test --template-type tx --template welcome --locale en --path images
|
|
159
|
-
```
|
|
98
|
+
The CLI is now a separate package: `@technomoron/mail-magic-cli`.
|
|
160
99
|
|
|
161
100
|
## Notes
|
|
162
101
|
|
|
163
|
-
- `push-dir` expects a `init-data.json` and domain folders that match the server config layout.
|
|
164
|
-
- Asset uploads use the server endpoint `POST /api/v1/assets`.
|
|
165
102
|
- OpenAPI spec (when enabled): `await client.getSwaggerSpec()`
|
|
166
103
|
- Public asset fetch helpers:
|
|
167
104
|
- `await client.fetchPublicAsset('example.test', 'images/logo.png')` -> `/asset/{domain}/{path}`
|
|
@@ -3,7 +3,13 @@ type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
|
3
3
|
[key: string]: JsonValue;
|
|
4
4
|
};
|
|
5
5
|
type RequestBody = JsonValue | object;
|
|
6
|
-
|
|
6
|
+
export type ApiResponse<T = unknown> = {
|
|
7
|
+
Status?: string;
|
|
8
|
+
data?: T;
|
|
9
|
+
message?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
export interface StoreTxTemplateInput {
|
|
7
13
|
template: string;
|
|
8
14
|
domain: string;
|
|
9
15
|
sender?: string;
|
|
@@ -12,7 +18,7 @@ interface templateData {
|
|
|
12
18
|
locale?: string;
|
|
13
19
|
part?: boolean;
|
|
14
20
|
}
|
|
15
|
-
interface
|
|
21
|
+
export interface StoreFormTemplateInput {
|
|
16
22
|
idname: string;
|
|
17
23
|
domain: string;
|
|
18
24
|
template: string;
|
|
@@ -26,7 +32,7 @@ interface formTemplateData {
|
|
|
26
32
|
allowed_fields?: string[] | string;
|
|
27
33
|
captcha_required?: boolean;
|
|
28
34
|
}
|
|
29
|
-
interface
|
|
35
|
+
export interface StoreFormRecipientInput {
|
|
30
36
|
domain: string;
|
|
31
37
|
idname: string;
|
|
32
38
|
email: string;
|
|
@@ -35,7 +41,7 @@ interface formRecipientData {
|
|
|
35
41
|
formid?: string;
|
|
36
42
|
locale?: string;
|
|
37
43
|
}
|
|
38
|
-
interface
|
|
44
|
+
export interface SendTxMessageInput {
|
|
39
45
|
name: string;
|
|
40
46
|
rcpt: string;
|
|
41
47
|
domain: string;
|
|
@@ -45,21 +51,21 @@ interface sendTemplateData {
|
|
|
45
51
|
headers?: Record<string, string>;
|
|
46
52
|
attachments?: AttachmentInput[];
|
|
47
53
|
}
|
|
48
|
-
interface
|
|
54
|
+
export interface SendFormMessageInput {
|
|
49
55
|
_mm_form_key: string;
|
|
50
56
|
_mm_locale?: string;
|
|
51
57
|
_mm_recipients?: string[] | string;
|
|
52
58
|
fields?: Record<string, unknown>;
|
|
53
59
|
attachments?: AttachmentInput[];
|
|
54
60
|
}
|
|
55
|
-
type AttachmentInput = {
|
|
61
|
+
export type AttachmentInput = {
|
|
56
62
|
path: string;
|
|
57
63
|
filename?: string;
|
|
58
64
|
contentType?: string;
|
|
59
65
|
field?: string;
|
|
60
66
|
};
|
|
61
67
|
type UploadAssetInput = string | AttachmentInput;
|
|
62
|
-
interface
|
|
68
|
+
export interface UploadAssetsInput {
|
|
63
69
|
domain: string;
|
|
64
70
|
files: UploadAssetInput[];
|
|
65
71
|
templateType?: 'tx' | 'form';
|
|
@@ -67,7 +73,7 @@ interface uploadAssetsData {
|
|
|
67
73
|
locale?: string;
|
|
68
74
|
path?: string;
|
|
69
75
|
}
|
|
70
|
-
declare class
|
|
76
|
+
declare class TemplateClient {
|
|
71
77
|
private baseURL;
|
|
72
78
|
private apiKey;
|
|
73
79
|
constructor(baseURL: string, apiKey: string);
|
|
@@ -85,15 +91,15 @@ declare class templateClient {
|
|
|
85
91
|
private createAttachmentPayload;
|
|
86
92
|
private appendFields;
|
|
87
93
|
private postFormData;
|
|
88
|
-
storeTemplate(td:
|
|
89
|
-
sendTemplate(std:
|
|
90
|
-
storeTxTemplate(td:
|
|
91
|
-
sendTxMessage(std:
|
|
92
|
-
storeFormTemplate(data:
|
|
93
|
-
storeFormRecipient(data:
|
|
94
|
-
sendFormMessage(data:
|
|
95
|
-
uploadAssets(data:
|
|
96
|
-
getSwaggerSpec(): Promise<
|
|
94
|
+
storeTemplate(td: StoreTxTemplateInput): Promise<ApiResponse>;
|
|
95
|
+
sendTemplate(std: SendTxMessageInput): Promise<ApiResponse>;
|
|
96
|
+
storeTxTemplate(td: StoreTxTemplateInput): Promise<ApiResponse>;
|
|
97
|
+
sendTxMessage(std: SendTxMessageInput): Promise<ApiResponse>;
|
|
98
|
+
storeFormTemplate(data: StoreFormTemplateInput): Promise<ApiResponse>;
|
|
99
|
+
storeFormRecipient(data: StoreFormRecipientInput): Promise<ApiResponse>;
|
|
100
|
+
sendFormMessage(data: SendFormMessageInput): Promise<ApiResponse>;
|
|
101
|
+
uploadAssets(data: UploadAssetsInput): Promise<ApiResponse>;
|
|
102
|
+
getSwaggerSpec(): Promise<ApiResponse>;
|
|
97
103
|
fetchPublicAsset(domain: string, assetPath: string, viaApiBase?: boolean): Promise<ArrayBuffer>;
|
|
98
104
|
}
|
|
99
|
-
export default
|
|
105
|
+
export default TemplateClient;
|
|
@@ -7,7 +7,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const email_addresses_1 = __importDefault(require("email-addresses"));
|
|
9
9
|
const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
10
|
-
class
|
|
10
|
+
class TemplateClient {
|
|
11
11
|
constructor(baseURL, apiKey) {
|
|
12
12
|
this.baseURL = baseURL;
|
|
13
13
|
this.apiKey = apiKey;
|
|
@@ -55,12 +55,13 @@ class templateClient {
|
|
|
55
55
|
return this.request('DELETE', command, body);
|
|
56
56
|
}
|
|
57
57
|
validateEmails(list) {
|
|
58
|
-
const valid = []
|
|
58
|
+
const valid = [];
|
|
59
|
+
const invalid = [];
|
|
59
60
|
const emails = list
|
|
60
61
|
.split(',')
|
|
61
62
|
.map((email) => email.trim())
|
|
62
63
|
.filter((email) => email !== '');
|
|
63
|
-
|
|
64
|
+
for (const email of emails) {
|
|
64
65
|
const parsed = email_addresses_1.default.parseOneAddress(email);
|
|
65
66
|
if (parsed && parsed.address) {
|
|
66
67
|
valid.push(parsed.address);
|
|
@@ -68,7 +69,7 @@ class templateClient {
|
|
|
68
69
|
else {
|
|
69
70
|
invalid.push(email);
|
|
70
71
|
}
|
|
71
|
-
}
|
|
72
|
+
}
|
|
72
73
|
return { valid, invalid };
|
|
73
74
|
}
|
|
74
75
|
validateTemplate(template) {
|
|
@@ -325,4 +326,4 @@ class templateClient {
|
|
|
325
326
|
return response.arrayBuffer();
|
|
326
327
|
}
|
|
327
328
|
}
|
|
328
|
-
exports.default =
|
|
329
|
+
exports.default = TemplateClient;
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import emailAddresses from 'email-addresses';
|
|
4
4
|
import nunjucks from 'nunjucks';
|
|
5
|
-
class
|
|
5
|
+
class TemplateClient {
|
|
6
6
|
constructor(baseURL, apiKey) {
|
|
7
7
|
this.baseURL = baseURL;
|
|
8
8
|
this.apiKey = apiKey;
|
|
@@ -50,12 +50,13 @@ class templateClient {
|
|
|
50
50
|
return this.request('DELETE', command, body);
|
|
51
51
|
}
|
|
52
52
|
validateEmails(list) {
|
|
53
|
-
const valid = []
|
|
53
|
+
const valid = [];
|
|
54
|
+
const invalid = [];
|
|
54
55
|
const emails = list
|
|
55
56
|
.split(',')
|
|
56
57
|
.map((email) => email.trim())
|
|
57
58
|
.filter((email) => email !== '');
|
|
58
|
-
|
|
59
|
+
for (const email of emails) {
|
|
59
60
|
const parsed = emailAddresses.parseOneAddress(email);
|
|
60
61
|
if (parsed && parsed.address) {
|
|
61
62
|
valid.push(parsed.address);
|
|
@@ -63,7 +64,7 @@ class templateClient {
|
|
|
63
64
|
else {
|
|
64
65
|
invalid.push(email);
|
|
65
66
|
}
|
|
66
|
-
}
|
|
67
|
+
}
|
|
67
68
|
return { valid, invalid };
|
|
68
69
|
}
|
|
69
70
|
validateTemplate(template) {
|
|
@@ -320,4 +321,4 @@ class templateClient {
|
|
|
320
321
|
return response.arrayBuffer();
|
|
321
322
|
}
|
|
322
323
|
}
|
|
323
|
-
export default
|
|
324
|
+
export default TemplateClient;
|