groundmail-cli 0.33.1 → 0.35.0
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/README.md +1 -0
- package/dist/cli.js +105 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -75,6 +75,7 @@ groundmail domains list
|
|
|
75
75
|
groundmail domains verify example.com
|
|
76
76
|
groundmail webhooks list
|
|
77
77
|
groundmail emails list
|
|
78
|
+
groundmail brand set --logo-url https://cdn.acme.com/logo.png --color '#2f6feb' --company "Acme Inc" # logo, color and footer every template follows
|
|
78
79
|
groundmail senders list # saved senders; send with --sender billing instead of --from
|
|
79
80
|
SENDGRID_API_KEY=… groundmail migrate sendgrid --dry-run # import from SendGrid, Postmark, Mailgun, Resend or Amazon SES (beta)
|
|
80
81
|
```
|
package/dist/cli.js
CHANGED
|
@@ -2055,7 +2055,7 @@ function trimUrl(value) {
|
|
|
2055
2055
|
}
|
|
2056
2056
|
|
|
2057
2057
|
// package.json
|
|
2058
|
-
var version = "0.
|
|
2058
|
+
var version = "0.35.0";
|
|
2059
2059
|
|
|
2060
2060
|
// src/user-agent.ts
|
|
2061
2061
|
function buildUserAgent(own) {
|
|
@@ -3283,8 +3283,8 @@ function extensionOf(filePath) {
|
|
|
3283
3283
|
return match ? match[0].toLowerCase() : "";
|
|
3284
3284
|
}
|
|
3285
3285
|
async function defaultReadFile(filePath) {
|
|
3286
|
-
const { readFile:
|
|
3287
|
-
return
|
|
3286
|
+
const { readFile: readFile4 } = await import("fs/promises");
|
|
3287
|
+
return readFile4(filePath, "utf8");
|
|
3288
3288
|
}
|
|
3289
3289
|
async function defaultImportModule(filePath) {
|
|
3290
3290
|
const { pathToFileURL } = await import("url");
|
|
@@ -3335,14 +3335,14 @@ async function toElement(mod, props) {
|
|
|
3335
3335
|
return exported;
|
|
3336
3336
|
}
|
|
3337
3337
|
async function loadTemplateSource(filePath, options = {}, deps = {}) {
|
|
3338
|
-
const
|
|
3338
|
+
const readFile4 = deps.readFile ?? defaultReadFile;
|
|
3339
3339
|
const importModule = deps.importModule ?? defaultImportModule;
|
|
3340
3340
|
const extension = extensionOf(filePath);
|
|
3341
3341
|
if (HTML_EXTENSIONS.includes(extension)) {
|
|
3342
|
-
return { html: await
|
|
3342
|
+
return { html: await readFile4(filePath) };
|
|
3343
3343
|
}
|
|
3344
3344
|
if (TEXT_EXTENSIONS.includes(extension)) {
|
|
3345
|
-
return { text: await
|
|
3345
|
+
return { text: await readFile4(filePath) };
|
|
3346
3346
|
}
|
|
3347
3347
|
if (!MODULE_EXTENSIONS.includes(extension)) {
|
|
3348
3348
|
throw new Error(
|
|
@@ -4064,6 +4064,95 @@ async function runDeleteCommand6(args, env = process.env) {
|
|
|
4064
4064
|
return withClient2(args, env, (client2) => client2.senders.remove(sender));
|
|
4065
4065
|
}
|
|
4066
4066
|
|
|
4067
|
+
// src/commands/brand/commands.ts
|
|
4068
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
4069
|
+
async function createBrandClient(apiKey, baseUrl) {
|
|
4070
|
+
const { Groundmail } = await import("groundmail");
|
|
4071
|
+
return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
|
|
4072
|
+
}
|
|
4073
|
+
var HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
4074
|
+
function readableText(hex) {
|
|
4075
|
+
const full = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
4076
|
+
const lin = (i) => {
|
|
4077
|
+
const c = parseInt(full.slice(i, i + 2), 16) / 255;
|
|
4078
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
4079
|
+
};
|
|
4080
|
+
const luminance = 0.2126 * lin(1) + 0.7152 * lin(3) + 0.0722 * lin(5);
|
|
4081
|
+
return 1.05 / (luminance + 0.05) >= (luminance + 0.05) / (0.0103 + 0.05) ? "#ffffff" : "#1c1917";
|
|
4082
|
+
}
|
|
4083
|
+
async function withClient3(args, env, run) {
|
|
4084
|
+
const options = parseSendersCommonArgs(args);
|
|
4085
|
+
const apiKey = resolveApiKey10(options, env);
|
|
4086
|
+
if (!apiKey) return { exitCode: 1, error: MISSING_KEY2 };
|
|
4087
|
+
try {
|
|
4088
|
+
const client2 = await createBrandClient(apiKey, options.baseUrl);
|
|
4089
|
+
console.log(JSON.stringify(await run(client2)));
|
|
4090
|
+
return { exitCode: 0 };
|
|
4091
|
+
} catch (error) {
|
|
4092
|
+
return failure2(error);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
async function runGetCommand9(args, env = process.env) {
|
|
4096
|
+
return withClient3(args, env, (client2) => client2.brand.get());
|
|
4097
|
+
}
|
|
4098
|
+
function clearable(value) {
|
|
4099
|
+
if (value === void 0) return void 0;
|
|
4100
|
+
return value === "none" || value === "" ? null : value;
|
|
4101
|
+
}
|
|
4102
|
+
async function runSetCommand(args, env = process.env) {
|
|
4103
|
+
const logoUrl = clearable(readFlag22(args, "--logo-url"));
|
|
4104
|
+
const logoAlign = readFlag22(args, "--logo-align");
|
|
4105
|
+
const logoWidth = readFlag22(args, "--logo-width");
|
|
4106
|
+
const color = readFlag22(args, "--color");
|
|
4107
|
+
const settingsFile = readFlag22(args, "--settings-file");
|
|
4108
|
+
if (logoAlign !== void 0 && logoAlign !== "left" && logoAlign !== "center") {
|
|
4109
|
+
return { exitCode: 1, error: "--logo-align must be left or center" };
|
|
4110
|
+
}
|
|
4111
|
+
if ((logoAlign !== void 0 || logoWidth !== void 0) && !logoUrl) {
|
|
4112
|
+
return { exitCode: 1, error: "--logo-align and --logo-width go with --logo-url" };
|
|
4113
|
+
}
|
|
4114
|
+
if (logoWidth !== void 0 && !/^\d+$/.test(logoWidth)) return { exitCode: 1, error: "--logo-width must be a whole number of px" };
|
|
4115
|
+
if (color !== void 0 && !HEX.test(color)) return { exitCode: 1, error: "--color must be a hex colour such as #2f6feb" };
|
|
4116
|
+
let settingsFromFile;
|
|
4117
|
+
if (settingsFile) {
|
|
4118
|
+
try {
|
|
4119
|
+
settingsFromFile = JSON.parse(await readFile3(settingsFile, "utf8"));
|
|
4120
|
+
} catch {
|
|
4121
|
+
return { exitCode: 1, error: `Could not read JSON from ${settingsFile}` };
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
const params = {};
|
|
4125
|
+
if (logoUrl !== void 0) {
|
|
4126
|
+
params.logo = logoUrl === null ? null : { url: logoUrl, align: logoAlign ?? "left", ...logoWidth ? { width: Number(logoWidth) } : {} };
|
|
4127
|
+
}
|
|
4128
|
+
const company = clearable(readFlag22(args, "--company"));
|
|
4129
|
+
const address = clearable(readFlag22(args, "--address"));
|
|
4130
|
+
const website = clearable(readFlag22(args, "--website"));
|
|
4131
|
+
if (company !== void 0) params.company_name = company;
|
|
4132
|
+
if (address !== void 0) params.address = address;
|
|
4133
|
+
if (website !== void 0) params.website = website;
|
|
4134
|
+
if (settingsFromFile) params.settings = settingsFromFile;
|
|
4135
|
+
if (!Object.keys(params).length && !color) {
|
|
4136
|
+
return {
|
|
4137
|
+
exitCode: 1,
|
|
4138
|
+
error: "Nothing to set. Usage: groundmail brand set [--logo-url \u2026] [--color #2f6feb] [--company \u2026] [--address \u2026] [--website \u2026] [--settings-file brand.json]"
|
|
4139
|
+
};
|
|
4140
|
+
}
|
|
4141
|
+
return withClient3(args, env, async (client2) => {
|
|
4142
|
+
if (color) {
|
|
4143
|
+
const base = params.settings ?? (await client2.brand.get()).brand.settings ?? {};
|
|
4144
|
+
const theme = base.theme ?? {};
|
|
4145
|
+
params.accent_color = color;
|
|
4146
|
+
params.settings = {
|
|
4147
|
+
...base,
|
|
4148
|
+
linkColor: color,
|
|
4149
|
+
theme: { ...theme, buttonBackground: color, buttonTextColor: readableText(color) }
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
return client2.brand.update(params);
|
|
4153
|
+
});
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4067
4156
|
// src/commands/auth.ts
|
|
4068
4157
|
async function runAuthCommand(subcommand, argv, deps = {}) {
|
|
4069
4158
|
const env = deps.env ?? process.env;
|
|
@@ -4651,7 +4740,7 @@ var USAGE_LINES = [
|
|
|
4651
4740
|
` groundmail events send --name user.created --email user@example.com --data '{"name":"Ada"}'`,
|
|
4652
4741
|
" groundmail automations list",
|
|
4653
4742
|
" groundmail automations create --file ./welcome.json",
|
|
4654
|
-
` groundmail automations create --name Welcome --trigger user.created --steps '[{"type":"send_email","email":{
|
|
4743
|
+
` groundmail automations create --name Welcome --trigger user.created --steps '[{"type":"send_email","email":{"from":"you@yourdomain.com","to":"{{event.email}}","template":{"id":"welcome","variables":{"name":"{{event.data.name}}"}}}}]' each email step sends a published template`,
|
|
4655
4744
|
" groundmail automations create --file ./otp-sms.json",
|
|
4656
4745
|
" groundmail automations get --id <automation-id>",
|
|
4657
4746
|
" groundmail automations update --id <automation-id> --file ./welcome.json",
|
|
@@ -4682,7 +4771,7 @@ var USAGE_LINES = [
|
|
|
4682
4771
|
" groundmail templates restore --id tpl_\u2026 --version 2",
|
|
4683
4772
|
" groundmail templates test-send --id tpl_\u2026 --to you@domain.com [--from you@domain.com | --sender billing] neither: the template's sender, else your default sender",
|
|
4684
4773
|
' groundmail templates duplicate --id tpl_\u2026 [--name "Copy"]',
|
|
4685
|
-
" groundmail templates delete --id tpl_\u2026",
|
|
4774
|
+
" groundmail templates delete --id tpl_\u2026 refused while an automation step sends it (the error names them)",
|
|
4686
4775
|
" groundmail tenants list [--status active|paused] [--limit 25] [--cursor \u2026] your customers, each with its own domains, suppressions and limits",
|
|
4687
4776
|
` groundmail tenants create <external-id> [--name \u2026] [--default-from-domain \u2026] [--stream-policy all|transactional_only] [--daily-limit N] [--metadata '{"plan":"pro"}']`,
|
|
4688
4777
|
" groundmail tenants get <tenant>",
|
|
@@ -4694,6 +4783,8 @@ var USAGE_LINES = [
|
|
|
4694
4783
|
" groundmail tenants domains list <tenant>",
|
|
4695
4784
|
" groundmail tenants domains add <tenant> example.com only this tenant can then send from it",
|
|
4696
4785
|
" groundmail tenants domains remove <tenant> example.com gives the domain back to the account",
|
|
4786
|
+
" groundmail brand get your logo, colors and footer, which templates follow",
|
|
4787
|
+
' groundmail brand set [--logo-url <https url>|none] [--logo-align left|center] [--logo-width 120] [--color #2f6feb] [--company "Acme Inc"|none] [--address "\u2026"|none] [--website acme.com|none] [--settings-file brand.json] --color: buttons, links and the line across the top',
|
|
4697
4788
|
" groundmail senders list the names and addresses your email goes out as",
|
|
4698
4789
|
' groundmail senders create --name "Acme Billing" --address billing@mail.acme.com [--reply-to billing@acme.com] [--handle billing] [--default] address on a verified domain',
|
|
4699
4790
|
" groundmail senders get <id|handle>",
|
|
@@ -4742,7 +4833,8 @@ var ALIASES = {
|
|
|
4742
4833
|
suppressions: { create: "add", delete: "remove" },
|
|
4743
4834
|
templates: { add: "create", remove: "delete" },
|
|
4744
4835
|
tenants: { add: "create", remove: "delete" },
|
|
4745
|
-
senders: { add: "create", remove: "delete" }
|
|
4836
|
+
senders: { add: "create", remove: "delete" },
|
|
4837
|
+
brand: { update: "set" }
|
|
4746
4838
|
};
|
|
4747
4839
|
function words(line) {
|
|
4748
4840
|
return line.trim().split(/\s+/);
|
|
@@ -5080,6 +5172,10 @@ async function main() {
|
|
|
5080
5172
|
if (subcommand === "stats") await finish(await runStatsCommand(rest));
|
|
5081
5173
|
if (subcommand === "domains") await finish(await runDomainsCommand(rest));
|
|
5082
5174
|
}
|
|
5175
|
+
if (command === "brand") {
|
|
5176
|
+
if (subcommand === "get") await finish(await runGetCommand9(rest));
|
|
5177
|
+
if (subcommand === "set" || subcommand === "update") await finish(await runSetCommand(rest));
|
|
5178
|
+
}
|
|
5083
5179
|
if (command === "senders") {
|
|
5084
5180
|
if (subcommand === "list") await finish(await runListCommand9(rest));
|
|
5085
5181
|
if (subcommand === "create" || subcommand === "add") await finish(await runCreateCommand5(rest));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groundmail-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Groundmail CLI — send transactional email from the terminal",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"prepublishOnly": "npm run build"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"groundmail": "0.
|
|
41
|
+
"groundmail": "0.37.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"tsup": "^8.5.0",
|