groundmail-cli 0.34.0 → 0.35.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/README.md +1 -0
- package/dist/cli.js +110 -8
- 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.1";
|
|
2059
2059
|
|
|
2060
2060
|
// src/user-agent.ts
|
|
2061
2061
|
function buildUserAgent(own) {
|
|
@@ -2082,6 +2082,12 @@ function fetchWithUserAgent(userAgent) {
|
|
|
2082
2082
|
|
|
2083
2083
|
// src/client-info.ts
|
|
2084
2084
|
var CLI_PACKAGE = { name: "groundmail-cli", version };
|
|
2085
|
+
function sdkOptions(baseUrl) {
|
|
2086
|
+
return {
|
|
2087
|
+
...baseUrl ? { baseUrl } : {},
|
|
2088
|
+
fetch: fetchWithUserAgent(buildUserAgent(CLI_PACKAGE))
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2085
2091
|
|
|
2086
2092
|
// src/session/http.ts
|
|
2087
2093
|
var CliRequestError = class extends Error {
|
|
@@ -3133,7 +3139,7 @@ function resolveApiKey8(options, env) {
|
|
|
3133
3139
|
}
|
|
3134
3140
|
async function createTemplatesClient(apiKey, baseUrl) {
|
|
3135
3141
|
const { Groundmail } = await import("groundmail");
|
|
3136
|
-
return new Groundmail(apiKey, baseUrl
|
|
3142
|
+
return new Groundmail(apiKey, sdkOptions(baseUrl));
|
|
3137
3143
|
}
|
|
3138
3144
|
|
|
3139
3145
|
// src/commands/templates/delete.ts
|
|
@@ -3283,8 +3289,8 @@ function extensionOf(filePath) {
|
|
|
3283
3289
|
return match ? match[0].toLowerCase() : "";
|
|
3284
3290
|
}
|
|
3285
3291
|
async function defaultReadFile(filePath) {
|
|
3286
|
-
const { readFile:
|
|
3287
|
-
return
|
|
3292
|
+
const { readFile: readFile4 } = await import("fs/promises");
|
|
3293
|
+
return readFile4(filePath, "utf8");
|
|
3288
3294
|
}
|
|
3289
3295
|
async function defaultImportModule(filePath) {
|
|
3290
3296
|
const { pathToFileURL } = await import("url");
|
|
@@ -3335,14 +3341,14 @@ async function toElement(mod, props) {
|
|
|
3335
3341
|
return exported;
|
|
3336
3342
|
}
|
|
3337
3343
|
async function loadTemplateSource(filePath, options = {}, deps = {}) {
|
|
3338
|
-
const
|
|
3344
|
+
const readFile4 = deps.readFile ?? defaultReadFile;
|
|
3339
3345
|
const importModule = deps.importModule ?? defaultImportModule;
|
|
3340
3346
|
const extension = extensionOf(filePath);
|
|
3341
3347
|
if (HTML_EXTENSIONS.includes(extension)) {
|
|
3342
|
-
return { html: await
|
|
3348
|
+
return { html: await readFile4(filePath) };
|
|
3343
3349
|
}
|
|
3344
3350
|
if (TEXT_EXTENSIONS.includes(extension)) {
|
|
3345
|
-
return { text: await
|
|
3351
|
+
return { text: await readFile4(filePath) };
|
|
3346
3352
|
}
|
|
3347
3353
|
if (!MODULE_EXTENSIONS.includes(extension)) {
|
|
3348
3354
|
throw new Error(
|
|
@@ -4064,6 +4070,95 @@ async function runDeleteCommand6(args, env = process.env) {
|
|
|
4064
4070
|
return withClient2(args, env, (client2) => client2.senders.remove(sender));
|
|
4065
4071
|
}
|
|
4066
4072
|
|
|
4073
|
+
// src/commands/brand/commands.ts
|
|
4074
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
4075
|
+
async function createBrandClient(apiKey, baseUrl) {
|
|
4076
|
+
const { Groundmail } = await import("groundmail");
|
|
4077
|
+
return new Groundmail(apiKey, baseUrl ? { baseUrl } : void 0);
|
|
4078
|
+
}
|
|
4079
|
+
var HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
4080
|
+
function readableText(hex) {
|
|
4081
|
+
const full = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
4082
|
+
const lin = (i) => {
|
|
4083
|
+
const c = parseInt(full.slice(i, i + 2), 16) / 255;
|
|
4084
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
4085
|
+
};
|
|
4086
|
+
const luminance = 0.2126 * lin(1) + 0.7152 * lin(3) + 0.0722 * lin(5);
|
|
4087
|
+
return 1.05 / (luminance + 0.05) >= (luminance + 0.05) / (0.0103 + 0.05) ? "#ffffff" : "#1c1917";
|
|
4088
|
+
}
|
|
4089
|
+
async function withClient3(args, env, run) {
|
|
4090
|
+
const options = parseSendersCommonArgs(args);
|
|
4091
|
+
const apiKey = resolveApiKey10(options, env);
|
|
4092
|
+
if (!apiKey) return { exitCode: 1, error: MISSING_KEY2 };
|
|
4093
|
+
try {
|
|
4094
|
+
const client2 = await createBrandClient(apiKey, options.baseUrl);
|
|
4095
|
+
console.log(JSON.stringify(await run(client2)));
|
|
4096
|
+
return { exitCode: 0 };
|
|
4097
|
+
} catch (error) {
|
|
4098
|
+
return failure2(error);
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
async function runGetCommand9(args, env = process.env) {
|
|
4102
|
+
return withClient3(args, env, (client2) => client2.brand.get());
|
|
4103
|
+
}
|
|
4104
|
+
function clearable(value) {
|
|
4105
|
+
if (value === void 0) return void 0;
|
|
4106
|
+
return value === "none" || value === "" ? null : value;
|
|
4107
|
+
}
|
|
4108
|
+
async function runSetCommand(args, env = process.env) {
|
|
4109
|
+
const logoUrl = clearable(readFlag22(args, "--logo-url"));
|
|
4110
|
+
const logoAlign = readFlag22(args, "--logo-align");
|
|
4111
|
+
const logoWidth = readFlag22(args, "--logo-width");
|
|
4112
|
+
const color = readFlag22(args, "--color");
|
|
4113
|
+
const settingsFile = readFlag22(args, "--settings-file");
|
|
4114
|
+
if (logoAlign !== void 0 && logoAlign !== "left" && logoAlign !== "center") {
|
|
4115
|
+
return { exitCode: 1, error: "--logo-align must be left or center" };
|
|
4116
|
+
}
|
|
4117
|
+
if ((logoAlign !== void 0 || logoWidth !== void 0) && !logoUrl) {
|
|
4118
|
+
return { exitCode: 1, error: "--logo-align and --logo-width go with --logo-url" };
|
|
4119
|
+
}
|
|
4120
|
+
if (logoWidth !== void 0 && !/^\d+$/.test(logoWidth)) return { exitCode: 1, error: "--logo-width must be a whole number of px" };
|
|
4121
|
+
if (color !== void 0 && !HEX.test(color)) return { exitCode: 1, error: "--color must be a hex colour such as #2f6feb" };
|
|
4122
|
+
let settingsFromFile;
|
|
4123
|
+
if (settingsFile) {
|
|
4124
|
+
try {
|
|
4125
|
+
settingsFromFile = JSON.parse(await readFile3(settingsFile, "utf8"));
|
|
4126
|
+
} catch {
|
|
4127
|
+
return { exitCode: 1, error: `Could not read JSON from ${settingsFile}` };
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
const params = {};
|
|
4131
|
+
if (logoUrl !== void 0) {
|
|
4132
|
+
params.logo = logoUrl === null ? null : { url: logoUrl, align: logoAlign ?? "left", ...logoWidth ? { width: Number(logoWidth) } : {} };
|
|
4133
|
+
}
|
|
4134
|
+
const company = clearable(readFlag22(args, "--company"));
|
|
4135
|
+
const address = clearable(readFlag22(args, "--address"));
|
|
4136
|
+
const website = clearable(readFlag22(args, "--website"));
|
|
4137
|
+
if (company !== void 0) params.company_name = company;
|
|
4138
|
+
if (address !== void 0) params.address = address;
|
|
4139
|
+
if (website !== void 0) params.website = website;
|
|
4140
|
+
if (settingsFromFile) params.settings = settingsFromFile;
|
|
4141
|
+
if (!Object.keys(params).length && !color) {
|
|
4142
|
+
return {
|
|
4143
|
+
exitCode: 1,
|
|
4144
|
+
error: "Nothing to set. Usage: groundmail brand set [--logo-url \u2026] [--color #2f6feb] [--company \u2026] [--address \u2026] [--website \u2026] [--settings-file brand.json]"
|
|
4145
|
+
};
|
|
4146
|
+
}
|
|
4147
|
+
return withClient3(args, env, async (client2) => {
|
|
4148
|
+
if (color) {
|
|
4149
|
+
const base = params.settings ?? (await client2.brand.get()).brand.settings ?? {};
|
|
4150
|
+
const theme = base.theme ?? {};
|
|
4151
|
+
params.accent_color = color;
|
|
4152
|
+
params.settings = {
|
|
4153
|
+
...base,
|
|
4154
|
+
linkColor: color,
|
|
4155
|
+
theme: { ...theme, buttonBackground: color, buttonTextColor: readableText(color) }
|
|
4156
|
+
};
|
|
4157
|
+
}
|
|
4158
|
+
return client2.brand.update(params);
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4067
4162
|
// src/commands/auth.ts
|
|
4068
4163
|
async function runAuthCommand(subcommand, argv, deps = {}) {
|
|
4069
4164
|
const env = deps.env ?? process.env;
|
|
@@ -4694,6 +4789,8 @@ var USAGE_LINES = [
|
|
|
4694
4789
|
" groundmail tenants domains list <tenant>",
|
|
4695
4790
|
" groundmail tenants domains add <tenant> example.com only this tenant can then send from it",
|
|
4696
4791
|
" groundmail tenants domains remove <tenant> example.com gives the domain back to the account",
|
|
4792
|
+
" groundmail brand get your logo, colors and footer, which templates follow",
|
|
4793
|
+
' 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
4794
|
" groundmail senders list the names and addresses your email goes out as",
|
|
4698
4795
|
' 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
4796
|
" groundmail senders get <id|handle>",
|
|
@@ -4742,7 +4839,8 @@ var ALIASES = {
|
|
|
4742
4839
|
suppressions: { create: "add", delete: "remove" },
|
|
4743
4840
|
templates: { add: "create", remove: "delete" },
|
|
4744
4841
|
tenants: { add: "create", remove: "delete" },
|
|
4745
|
-
senders: { add: "create", remove: "delete" }
|
|
4842
|
+
senders: { add: "create", remove: "delete" },
|
|
4843
|
+
brand: { update: "set" }
|
|
4746
4844
|
};
|
|
4747
4845
|
function words(line) {
|
|
4748
4846
|
return line.trim().split(/\s+/);
|
|
@@ -5080,6 +5178,10 @@ async function main() {
|
|
|
5080
5178
|
if (subcommand === "stats") await finish(await runStatsCommand(rest));
|
|
5081
5179
|
if (subcommand === "domains") await finish(await runDomainsCommand(rest));
|
|
5082
5180
|
}
|
|
5181
|
+
if (command === "brand") {
|
|
5182
|
+
if (subcommand === "get") await finish(await runGetCommand9(rest));
|
|
5183
|
+
if (subcommand === "set" || subcommand === "update") await finish(await runSetCommand(rest));
|
|
5184
|
+
}
|
|
5083
5185
|
if (command === "senders") {
|
|
5084
5186
|
if (subcommand === "list") await finish(await runListCommand9(rest));
|
|
5085
5187
|
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.1",
|
|
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",
|