@sendly/cli 3.29.0 → 3.32.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 CHANGED
@@ -14,9 +14,19 @@ Official command-line interface for the [Sendly](https://sendly.live) SMS API.
14
14
  ## Installation
15
15
 
16
16
  ```bash
17
+ # npm
17
18
  npm install -g @sendly/cli
19
+
20
+ # or Homebrew (macOS / Linux)
21
+ brew install SendlyHQ/tap/sendly
18
22
  ```
19
23
 
24
+ ## Staying up to date
25
+
26
+ The CLI checks npm once a day and prints a one-line banner after your command if a newer version is out. Run `sendly upgrade` to update — it auto-detects your install path (Homebrew vs npm) and runs the right command. Use `sendly upgrade --check` to see what it would do without executing.
27
+
28
+ Banner is silent in CI (`CI=true`) and offline-safe.
29
+
20
30
  ## Quick Start
21
31
 
22
32
  ```bash
@@ -0,0 +1,21 @@
1
+ import { BaseCommand } from "../lib/base-command.js";
2
+ /**
3
+ * `sendly countries` — list supported countries with pricing.
4
+ *
5
+ * Backs the public `GET /api/v1/countries` endpoint. No auth required so
6
+ * customers can browse before signing up. Useful for populating country
7
+ * pickers in sign-up forms, validating phone numbers client-side, and
8
+ * checking which tiers require registration (toll-free brand
9
+ * verification in US/CA, for instance).
10
+ */
11
+ export default class Countries extends BaseCommand {
12
+ static description: string;
13
+ static examples: string[];
14
+ static flags: {
15
+ search: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
16
+ tier: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
17
+ json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
18
+ quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
19
+ };
20
+ run(): Promise<void>;
21
+ }
@@ -0,0 +1,96 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../lib/base-command.js";
3
+ import { apiClient } from "../lib/api-client.js";
4
+ import { json, isJsonMode, colors, header } from "../lib/output.js";
5
+ /**
6
+ * `sendly countries` — list supported countries with pricing.
7
+ *
8
+ * Backs the public `GET /api/v1/countries` endpoint. No auth required so
9
+ * customers can browse before signing up. Useful for populating country
10
+ * pickers in sign-up forms, validating phone numbers client-side, and
11
+ * checking which tiers require registration (toll-free brand
12
+ * verification in US/CA, for instance).
13
+ */
14
+ export default class Countries extends BaseCommand {
15
+ static description = "List supported countries with pricing (credits per SMS, USD price, tier). No auth required.";
16
+ static examples = [
17
+ "<%= config.bin %> countries",
18
+ "<%= config.bin %> countries --search UK",
19
+ "<%= config.bin %> countries --tier domestic",
20
+ "<%= config.bin %> countries --json",
21
+ ];
22
+ static flags = {
23
+ ...BaseCommand.baseFlags,
24
+ search: Flags.string({
25
+ description: "Filter by name, country code, or dial code",
26
+ }),
27
+ tier: Flags.string({
28
+ description: "Filter by pricing tier (domestic, international, etc.)",
29
+ }),
30
+ };
31
+ async run() {
32
+ const { flags } = await this.parse(Countries);
33
+ const resp = await apiClient.get("/api/v1/countries");
34
+ const all = Array.isArray(resp)
35
+ ? resp
36
+ : (resp.countries ?? []);
37
+ const filtered = all.filter((c) => {
38
+ if (flags.tier && c.tier !== flags.tier)
39
+ return false;
40
+ if (flags.search) {
41
+ const q = flags.search.toLowerCase();
42
+ return (c.code.toLowerCase().includes(q) ||
43
+ c.name.toLowerCase().includes(q) ||
44
+ c.dial_code.includes(q));
45
+ }
46
+ return true;
47
+ });
48
+ if (isJsonMode()) {
49
+ json(filtered);
50
+ return;
51
+ }
52
+ header(`Supported countries (${filtered.length})`);
53
+ if (filtered.length === 0) {
54
+ console.log(colors.dim(" (no matches)"));
55
+ return;
56
+ }
57
+ // Column widths derived from the data so the table stays compact.
58
+ const codeW = 4;
59
+ const dialW = Math.max(...filtered.map((c) => c.dial_code.length), 5);
60
+ const nameW = Math.max(...filtered.map((c) => c.name.length), 12);
61
+ console.log(" " +
62
+ colors.dim("Code".padEnd(codeW)) +
63
+ " " +
64
+ colors.dim("Dial".padEnd(dialW)) +
65
+ " " +
66
+ colors.dim("Name".padEnd(nameW)) +
67
+ " " +
68
+ colors.dim("Tier".padEnd(14)) +
69
+ " " +
70
+ colors.dim("Credits/SMS".padStart(11)) +
71
+ " " +
72
+ colors.dim("Price (USD)".padStart(11)) +
73
+ " " +
74
+ colors.dim("Registration"));
75
+ for (const c of filtered) {
76
+ const regHint = c.requires_registration
77
+ ? colors.warning("required")
78
+ : colors.dim("not required");
79
+ console.log(" " +
80
+ c.code.padEnd(codeW) +
81
+ " " +
82
+ c.dial_code.padEnd(dialW) +
83
+ " " +
84
+ c.name.padEnd(nameW) +
85
+ " " +
86
+ c.tier.padEnd(14) +
87
+ " " +
88
+ String(c.credits_per_sms).padStart(11) +
89
+ " " +
90
+ c.price_usd.toFixed(4).padStart(11) +
91
+ " " +
92
+ regHint);
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY291bnRyaWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL2NvdW50cmllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBWXBFOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxTQUFVLFNBQVEsV0FBVztJQUNoRCxNQUFNLENBQUMsV0FBVyxHQUNoQiw2RkFBNkYsQ0FBQztJQUVoRyxNQUFNLENBQUMsUUFBUSxHQUFHO1FBQ2hCLDZCQUE2QjtRQUM3Qix5Q0FBeUM7UUFDekMsNkNBQTZDO1FBQzdDLG9DQUFvQztLQUNyQyxDQUFDO0lBRUYsTUFBTSxDQUFDLEtBQUssR0FBRztRQUNiLEdBQUcsV0FBVyxDQUFDLFNBQVM7UUFDeEIsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDbkIsV0FBVyxFQUFFLDRDQUE0QztTQUMxRCxDQUFDO1FBQ0YsSUFBSSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDakIsV0FBVyxFQUFFLHdEQUF3RDtTQUN0RSxDQUFDO0tBQ0gsQ0FBQztJQUVGLEtBQUssQ0FBQyxHQUFHO1FBQ1AsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUU5QyxNQUFNLElBQUksR0FBRyxNQUFNLFNBQVMsQ0FBQyxHQUFHLENBQzlCLG1CQUFtQixDQUNwQixDQUFDO1FBQ0YsTUFBTSxHQUFHLEdBQWMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJ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LENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUMvQixPQUFPLENBQUMsR0FBRyxDQUNULElBQUk7Z0JBQ0YsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO2dCQUNwQixJQUFJO2dCQUNKLENBQUMsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztnQkFDekIsSUFBSTtnQkFDSixDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7Z0JBQ3BCLElBQUk7Z0JBQ0osQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO2dCQUNqQixJQUFJO2dCQUNKLE1BQU0sQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsSUFBSTtnQkFDSixDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUNuQyxJQUFJO2dCQUNKLE9BQU8sQ0FDVixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGbGFncyB9IGZyb20gXCJAb2NsaWYvY29yZVwiO1xuaW1wb3J0IHsgQmFzZUNvbW1hbmQgfSBmcm9tIFwiLi4vbGliL2Jhc2UtY29tbWFuZC5qc1wiO1xuaW1wb3J0IHsgYXBpQ2xpZW50IH0gZnJvbSBcIi4uL2xpYi9hcGktY2xpZW50LmpzXCI7XG5pbXBvcnQgeyBqc29uLCBpc0pzb25Nb2RlLCBjb2xvcnMsIGhlYWRlciB9IGZyb20gXCIuLi9saWIvb3V0cHV0LmpzXCI7XG5cbmludGVyZmFjZSBDb3VudHJ5IHtcbiAgY29kZTogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGRpYWxfY29kZTogc3RyaW5nO1xuICB0aWVyOiBzdHJpbmc7XG4gIGNyZWRpdHNfcGVyX3NtczogbnVtYmVyO1xuICBwcmljZV91c2Q6IG51bWJlcjtcbiAgcmVxdWlyZXNfcmVnaXN0cmF0aW9uOiBib29sZWFuO1xufVxuXG4vKipcbiAqIGBzZW5kbHkgY291bnRyaWVzYCDigJQgbGlzdCBzdXBwb3J0ZWQgY291bnRyaWVzIHdpdGggcHJpY2luZy5cbiAqXG4gKiBCYWNrcyB0aGUgcHVibGljIGBHRVQgL2FwaS92MS9jb3VudHJpZXNgIGVuZHBvaW50LiBObyBhdXRoIHJlcXVpcmVkIHNvXG4gKiBjdXN0b21lcnMgY2FuIGJyb3dzZSBiZWZvcmUgc2lnbmluZyB1cC4gVXNlZnVsIGZvciBwb3B1bGF0aW5nIGNvdW50cnlcbiAqIHBpY2tlcnMgaW4gc2lnbi11cCBmb3JtcywgdmFsaWRhdGluZyBwaG9uZSBudW1iZXJzIGNsaWVudC1zaWRlLCBhbmRcbiAqIGNoZWNraW5nIHdoaWNoIHRpZXJzIHJlcXVpcmUgcmVnaXN0cmF0aW9uICh0b2xsLWZyZWUgYnJhbmRcbiAqIHZlcmlmaWNhdGlvbiBpbiBVUy9DQSwgZm9yIGluc3RhbmNlKS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ291bnRyaWVzIGV4dGVuZHMgQmFzZUNvbW1hbmQge1xuICBzdGF0aWMgZGVzY3JpcHRpb24gPVxuICAgIFwiTGlzdCBzdXBwb3J0ZWQgY291bnRyaWVzIHdpdGggcHJpY2luZyAoY3JlZGl0cyBwZXIgU01TLCBVU0QgcHJpY2UsIHRpZXIpLiBObyBhdXRoIHJlcXVpcmVkLlwiO1xuXG4gIHN0YXRpYyBleGFtcGxlcyA9IFtcbiAgICBcIjwlPSBjb25maWcuYmluICU+IGNvdW50cmllc1wiLFxuICAgIFwiPCU9IGNvbmZpZy5iaW4gJT4gY291bnRyaWVzIC0tc2VhcmNoIFVLXCIsXG4gICAgXCI8JT0gY29uZmlnLmJpbiAlPiBjb3VudHJpZXMgLS10aWVyIGRvbWVzdGljXCIsXG4gICAgXCI8JT0gY29uZmlnLmJpbiAlPiBjb3VudHJpZXMgLS1qc29uXCIsXG4gIF07XG5cbiAgc3RhdGljIGZsYWdzID0ge1xuICAgIC4uLkJhc2VDb21tYW5kLmJhc2VGbGFncyxcbiAgICBzZWFyY2g6IEZsYWdzLnN0cmluZyh7XG4gICAgICBkZXNjcmlwdGlvbjogXCJGaWx0ZXIgYnkgbmFtZSwgY291bnRyeSBjb2RlLCBvciBkaWFsIGNvZGVcIixcbiAgICB9KSxcbiAgICB0aWVyOiBGbGFncy5zdHJpbmcoe1xuICAgICAgZGVzY3JpcHRpb246IFwiRmlsdGVyIGJ5IHByaWNpbmcgdGllciAoZG9tZXN0aWMsIGludGVybmF0aW9uYWwsIGV0Yy4pXCIsXG4gICAgfSksXG4gIH07XG5cbiAgYXN5bmMgcnVuKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgZmxhZ3MgfSA9IGF3YWl0IHRoaXMucGFyc2UoQ291bnRyaWVzKTtcblxuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBhcGlDbGllbnQuZ2V0PHsgY291bnRyaWVzPzogQ291bnRyeVtdIH0gfCBDb3VudHJ5W10+KFxuICAgICAgXCIvYXBpL3YxL2NvdW50cmllc1wiLFxuICAgICk7XG4gICAgY29uc3QgYWxsOiBDb3VudHJ5W10gPSBBcnJheS5pc0FycmF5KHJlc3ApXG4gICAgICA/IHJlc3BcbiAgICAgIDogKHJlc3AuY291bnRyaWVzID8/IFtdKTtcblxuICAgIGNvbnN0IGZpbHRlcmVkID0gYWxsLmZpbHRlcigoYykgPT4ge1xuICAgICAgaWYgKGZsYWdzLnRpZXIgJiYgYy50aWVyICE9PSBmbGFncy50aWVyKSByZXR1cm4gZmFsc2U7XG4gICAgICBpZiAoZmxhZ3Muc2VhcmNoKSB7XG4gICAgICAgIGNvbnN0IHEgPSBmbGFncy5zZWFyY2gudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICBjLmNvZGUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSB8fFxuICAgICAgICAgIGMubmFtZS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHEpIHx8XG4gICAgICAgICAgYy5kaWFsX2NvZGUuaW5jbHVkZXMocSlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0pO1xuXG4gICAgaWYgKGlzSnNvbk1vZGUoKSkge1xuICAgICAganNvbihmaWx0ZXJlZCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaGVhZGVyKGBTdXBwb3J0ZWQgY291bnRyaWVzICgke2ZpbHRlcmVkLmxlbmd0aH0pYCk7XG4gICAgaWYgKGZpbHRlcmVkLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coY29sb3JzLmRpbShcIiAgKG5vIG1hdGNoZXMpXCIpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDb2x1bW4gd2lkdGhzIGRlcml2ZWQgZnJvbSB0aGUgZGF0YSBzbyB0aGUgdGFibGUgc3RheXMgY29tcGFjdC5cbiAgICBjb25zdCBjb2RlVyA9IDQ7XG4gICAgY29uc3QgZGlhbFcgPSBNYXRoLm1heCguLi5maWx0ZXJlZC5tYXAoKGMpID0+IGMuZGlhbF9jb2RlLmxlbmd0aCksIDUpO1xuICAgIGNvbnN0IG5hbWVXID0gTWF0aC5tYXgoLi4uZmlsdGVyZWQubWFwKChjKSA9PiBjLm5hbWUubGVuZ3RoKSwgMTIpO1xuXG4gICAgY29uc29sZS5sb2coXG4gICAgICBcIiAgXCIgK1xuICAgICAgICBjb2xvcnMuZGltKFwiQ29kZVwiLnBhZEVuZChjb2RlVykpICtcbiAgICAgICAgXCIgIFwiICtcbiAgICAgICAgY29sb3JzLmRpbShcIkRpYWxcIi5wYWRFbmQoZGlhbFcpKSArXG4gICAgICAgIFwiICBcIiArXG4gICAgICAgIGNvbG9ycy5kaW0oXCJOYW1lXCIucGFkRW5kKG5hbWVXKSkgK1xuICAgICAgICBcIiAgXCIgK1xuICAgICAgICBjb2xvcnMuZGltKFwiVGllclwiLnBhZEVuZCgxNCkpICtcbiAgICAgICAgXCIgIFwiICtcbiAgICAgICAgY29sb3JzLmRpbShcIkNyZWRpdHMvU01TXCIucGFkU3RhcnQoMTEpKSArXG4gICAgICAgIFwiICBcIiArXG4gICAgICAgIGNvbG9ycy5kaW0oXCJQcmljZSAoVVNEKVwiLnBhZFN0YXJ0KDExKSkgK1xuICAgICAgICBcIiAgXCIgK1xuICAgICAgICBjb2xvcnMuZGltKFwiUmVnaXN0cmF0aW9uXCIpLFxuICAgICk7XG4gICAgZm9yIChjb25zdCBjIG9mIGZpbHRlcmVkKSB7XG4gICAgICBjb25zdCByZWdIaW50ID0gYy5yZXF1aXJlc19yZWdpc3RyYXRpb25cbiAgICAgICAgPyBjb2xvcnMud2FybmluZyhcInJlcXVpcmVkXCIpXG4gICAgICAgIDogY29sb3JzLmRpbShcIm5vdCByZXF1aXJlZFwiKTtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBcIiAgXCIgK1xuICAgICAgICAgIGMuY29kZS5wYWRFbmQoY29kZVcpICtcbiAgICAgICAgICBcIiAgXCIgK1xuICAgICAgICAgIGMuZGlhbF9jb2RlLnBhZEVuZChkaWFsVykgK1xuICAgICAgICAgIFwiICBcIiArXG4gICAgICAgICAgYy5uYW1lLnBhZEVuZChuYW1lVykgK1xuICAgICAgICAgIFwiICBcIiArXG4gICAgICAgICAgYy50aWVyLnBhZEVuZCgxNCkgK1xuICAgICAgICAgIFwiICBcIiArXG4gICAgICAgICAgU3RyaW5nKGMuY3JlZGl0c19wZXJfc21zKS5wYWRTdGFydCgxMSkgK1xuICAgICAgICAgIFwiICBcIiArXG4gICAgICAgICAgYy5wcmljZV91c2QudG9GaXhlZCg0KS5wYWRTdGFydCgxMSkgK1xuICAgICAgICAgIFwiICBcIiArXG4gICAgICAgICAgcmVnSGludCxcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG4iXX0=
@@ -0,0 +1,22 @@
1
+ import { AuthenticatedCommand } from "../../lib/base-command.js";
2
+ /**
3
+ * `sendly sms upload-media <file>` — upload an image for MMS.
4
+ *
5
+ * Wraps `POST /api/v1/media`. Returns a public URL the caller passes as
6
+ * `--media` to `sms send` / `sms batch`. Flag-gated behind `enable_mms`
7
+ * on the server — if your account doesn't have MMS, the server returns
8
+ * 403 and this command surfaces it.
9
+ */
10
+ export default class SmsUploadMedia extends AuthenticatedCommand {
11
+ static description: string;
12
+ static examples: string[];
13
+ static args: {
14
+ file: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
15
+ };
16
+ static flags: {
17
+ "content-type": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
+ json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
19
+ quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
20
+ };
21
+ run(): Promise<void>;
22
+ }
@@ -0,0 +1,82 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { AuthenticatedCommand } from "../../lib/base-command.js";
5
+ import { apiClient } from "../../lib/api-client.js";
6
+ import { success, json, isJsonMode, colors, error, } from "../../lib/output.js";
7
+ const ALLOWED_EXTS = [".jpg", ".jpeg", ".png", ".gif"];
8
+ /**
9
+ * `sendly sms upload-media <file>` — upload an image for MMS.
10
+ *
11
+ * Wraps `POST /api/v1/media`. Returns a public URL the caller passes as
12
+ * `--media` to `sms send` / `sms batch`. Flag-gated behind `enable_mms`
13
+ * on the server — if your account doesn't have MMS, the server returns
14
+ * 403 and this command surfaces it.
15
+ */
16
+ export default class SmsUploadMedia extends AuthenticatedCommand {
17
+ static description = "Upload a JPEG/PNG/GIF image for MMS and get back a public URL to pass to `sms send --media`. Requires MMS to be enabled for your account.";
18
+ static examples = [
19
+ "<%= config.bin %> sms upload-media ./promo.jpg",
20
+ "<%= config.bin %> sms upload-media ./animated.gif --json",
21
+ ];
22
+ static args = {
23
+ file: Args.string({
24
+ description: "Path to the image file (JPEG, PNG, or GIF)",
25
+ required: true,
26
+ }),
27
+ };
28
+ static flags = {
29
+ ...AuthenticatedCommand.baseFlags,
30
+ "content-type": Flags.string({
31
+ description: "Override the detected mime type",
32
+ }),
33
+ };
34
+ async run() {
35
+ const { args, flags } = await this.parse(SmsUploadMedia);
36
+ const filePath = path.resolve(args.file);
37
+ if (!fs.existsSync(filePath)) {
38
+ error(`File not found: ${filePath}`);
39
+ this.exit(1);
40
+ }
41
+ const ext = path.extname(filePath).toLowerCase();
42
+ if (!ALLOWED_EXTS.includes(ext)) {
43
+ error(`Unsupported file extension '${ext}'. MMS supports JPEG, PNG, and GIF.`);
44
+ this.exit(1);
45
+ }
46
+ const buffer = fs.readFileSync(filePath);
47
+ const filename = path.basename(filePath);
48
+ const detected = flags["content-type"] ??
49
+ (ext === ".png"
50
+ ? "image/png"
51
+ : ext === ".gif"
52
+ ? "image/gif"
53
+ : "image/jpeg");
54
+ const resp = await apiClient.uploadFile("/api/v1/media", {
55
+ buffer,
56
+ filename,
57
+ mimetype: detected,
58
+ });
59
+ if (isJsonMode()) {
60
+ json(resp);
61
+ return;
62
+ }
63
+ success("Media uploaded", {
64
+ ID: resp.id,
65
+ URL: resp.url,
66
+ "Content-Type": resp.contentType,
67
+ Size: formatBytes(resp.sizeBytes),
68
+ });
69
+ console.log();
70
+ console.log(colors.dim(" Send an MMS with this image:"));
71
+ console.log(" " +
72
+ colors.code(`sendly sms send --to +15551234567 --text "Hi" --media "${resp.url}"`));
73
+ }
74
+ }
75
+ function formatBytes(n) {
76
+ if (n < 1024)
77
+ return `${n} B`;
78
+ if (n < 1024 * 1024)
79
+ return `${(n / 1024).toFixed(1)} KB`;
80
+ return `${(n / (1024 * 1024)).toFixed(1)} MB`;
81
+ }
82
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBsb2FkLW1lZGlhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL3Ntcy91cGxvYWQtbWVkaWEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDMUMsT0FBTyxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFDTCxPQUFPLEVBQ1AsSUFBSSxFQUNKLFVBQVUsRUFDVixNQUFNLEVBQ04sS0FBSyxHQUVOLE1BQU0scUJBQXFCLENBQUM7QUFTN0IsTUFBTSxZQUFZLEdBQUcsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztBQUV2RDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxjQUFlLFNBQVEsb0JBQW9CO0lBQzlELE1BQU0sQ0FBQyxXQUFXLEdBQ2hCLDJJQUEySSxDQUFDO0lBRTlJLE1BQU0sQ0FBQyxRQUFRLEdBQUc7UUFDaEIsZ0RBQWdEO1FBQ2hELDBEQUEwRDtLQUMzRCxDQUFDO0lBRUYsTUFBTSxDQUFDLElBQUksR0FBRztRQUNaLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQ2hCLFdBQVcsRUFBRSw0Q0FBNEM7WUFDekQsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDO0tBQ0gsQ0FBQztJQUVGLE1BQU0sQ0FBQyxLQUFLLEdBQUc7UUFDYixHQUFHLG9CQUFvQixDQUFDLFNBQVM7UUFDakMsY0FBYyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDM0IsV0FBVyxFQUFFLGlDQUFpQztTQUMvQyxDQUFDO0tBQ0gsQ0FBQztJQUVGLEtBQUssQ0FBQyxHQUFHO1FBQ1AsTUFBTSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFekQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUM3QixLQUFLLENBQUMsbUJBQW1CLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDckMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDaEMsS0FBSyxDQUNILCtCQUErQixHQUFHLHFDQUFxQyxDQUN4RSxDQUFDO1lBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFekMsTUFBTSxRQUFRLEdBQ1osS0FBSyxDQUFDLGNBQWMsQ0FBQztZQUNyQixDQUFDLEdBQUcsS0FBSyxNQUFNO2dCQUNiLENBQUMsQ0FBQyxXQUFXO2dCQUNiLENBQUMsQ0FBQyxHQUFHLEtBQUssTUFBTTtvQkFDZCxDQUFDLENBQUMsV0FBVztvQkFDYixDQUFDLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFdEIsTUFBTSxJQUFJLEdBQUcsTUFBTSxTQUFTLENBQUMsVUFBVSxDQUNyQyxlQUFlLEVBQ2Y7WUFDRSxNQUFNO1lBQ04sUUFBUTtZQUNSLFFBQVEsRUFBRSxRQUFRO1NBQ25CLENBQ0YsQ0FBQztRQUVGLElBQUksVUFBVSxFQUFFLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDWCxPQUFPO1FBQ1QsQ0FBQztRQUVELE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRTtZQUN4QixFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7WUFDWCxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUc7WUFDYixjQUFjLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDaEMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO1NBQ2xDLENBQUMsQ0FBQztRQUNILE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNkLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLENBQUM7UUFDMUQsT0FBTyxDQUFDLEdBQUcsQ0FDVCxNQUFNO1lBQ0osTUFBTSxDQUFDLElBQUksQ0FDVCwwREFBMEQsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUN0RSxDQUNKLENBQUM7SUFDSixDQUFDOztBQUdILFNBQVMsV0FBVyxDQUFDLENBQVM7SUFDNUIsSUFBSSxDQUFDLEdBQUcsSUFBSTtRQUFFLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQztJQUM5QixJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSTtRQUFFLE9BQU8sR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUMxRCxPQUFPLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQXJncywgRmxhZ3MgfSBmcm9tIFwiQG9jbGlmL2NvcmVcIjtcbmltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IEF1dGhlbnRpY2F0ZWRDb21tYW5kIH0gZnJvbSBcIi4uLy4uL2xpYi9iYXNlLWNvbW1hbmQuanNcIjtcbmltcG9ydCB7IGFwaUNsaWVudCB9IGZyb20gXCIuLi8uLi9saWIvYXBpLWNsaWVudC5qc1wiO1xuaW1wb3J0IHtcbiAgc3VjY2VzcyxcbiAganNvbixcbiAgaXNKc29uTW9kZSxcbiAgY29sb3JzLFxuICBlcnJvcixcbiAga2V5VmFsdWUsXG59IGZyb20gXCIuLi8uLi9saWIvb3V0cHV0LmpzXCI7XG5cbmludGVyZmFjZSBNZWRpYVVwbG9hZFJlc3BvbnNlIHtcbiAgaWQ6IHN0cmluZztcbiAgdXJsOiBzdHJpbmc7XG4gIGNvbnRlbnRUeXBlOiBzdHJpbmc7XG4gIHNpemVCeXRlczogbnVtYmVyO1xufVxuXG5jb25zdCBBTExPV0VEX0VYVFMgPSBbXCIuanBnXCIsIFwiLmpwZWdcIiwgXCIucG5nXCIsIFwiLmdpZlwiXTtcblxuLyoqXG4gKiBgc2VuZGx5IHNtcyB1cGxvYWQtbWVkaWEgPGZpbGU+YCDigJQgdXBsb2FkIGFuIGltYWdlIGZvciBNTVMuXG4gKlxuICogV3JhcHMgYFBPU1QgL2FwaS92MS9tZWRpYWAuIFJldHVybnMgYSBwdWJsaWMgVVJMIHRoZSBjYWxsZXIgcGFzc2VzIGFzXG4gKiBgLS1tZWRpYWAgdG8gYHNtcyBzZW5kYCAvIGBzbXMgYmF0Y2hgLiBGbGFnLWdhdGVkIGJlaGluZCBgZW5hYmxlX21tc2BcbiAqIG9uIHRoZSBzZXJ2ZXIg4oCUIGlmIHlvdXIgYWNjb3VudCBkb2Vzbid0IGhhdmUgTU1TLCB0aGUgc2VydmVyIHJldHVybnNcbiAqIDQwMyBhbmQgdGhpcyBjb21tYW5kIHN1cmZhY2VzIGl0LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTbXNVcGxvYWRNZWRpYSBleHRlbmRzIEF1dGhlbnRpY2F0ZWRDb21tYW5kIHtcbiAgc3RhdGljIGRlc2NyaXB0aW9uID1cbiAgICBcIlVwbG9hZCBhIEpQRUcvUE5HL0dJRiBpbWFnZSBmb3IgTU1TIGFuZCBnZXQgYmFjayBhIHB1YmxpYyBVUkwgdG8gcGFzcyB0byBgc21zIHNlbmQgLS1tZWRpYWAuIFJlcXVpcmVzIE1NUyB0byBiZSBlbmFibGVkIGZvciB5b3VyIGFjY291bnQuXCI7XG5cbiAgc3RhdGljIGV4YW1wbGVzID0gW1xuICAgIFwiPCU9IGNvbmZpZy5iaW4gJT4gc21zIHVwbG9hZC1tZWRpYSAuL3Byb21vLmpwZ1wiLFxuICAgIFwiPCU9IGNvbmZpZy5iaW4gJT4gc21zIHVwbG9hZC1tZWRpYSAuL2FuaW1hdGVkLmdpZiAtLWpzb25cIixcbiAgXTtcblxuICBzdGF0aWMgYXJncyA9IHtcbiAgICBmaWxlOiBBcmdzLnN0cmluZyh7XG4gICAgICBkZXNjcmlwdGlvbjogXCJQYXRoIHRvIHRoZSBpbWFnZSBmaWxlIChKUEVHLCBQTkcsIG9yIEdJRilcIixcbiAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgIH0pLFxuICB9O1xuXG4gIHN0YXRpYyBmbGFncyA9IHtcbiAgICAuLi5BdXRoZW50aWNhdGVkQ29tbWFuZC5iYXNlRmxhZ3MsXG4gICAgXCJjb250ZW50LXR5cGVcIjogRmxhZ3Muc3RyaW5nKHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIk92ZXJyaWRlIHRoZSBkZXRlY3RlZCBtaW1lIHR5cGVcIixcbiAgICB9KSxcbiAgfTtcblxuICBhc3luYyBydW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBhcmdzLCBmbGFncyB9ID0gYXdhaXQgdGhpcy5wYXJzZShTbXNVcGxvYWRNZWRpYSk7XG5cbiAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGgucmVzb2x2ZShhcmdzLmZpbGUpO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhmaWxlUGF0aCkpIHtcbiAgICAgIGVycm9yKGBGaWxlIG5vdCBmb3VuZDogJHtmaWxlUGF0aH1gKTtcbiAgICAgIHRoaXMuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBjb25zdCBleHQgPSBwYXRoLmV4dG5hbWUoZmlsZVBhdGgpLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKCFBTExPV0VEX0VYVFMuaW5jbHVkZXMoZXh0KSkge1xuICAgICAgZXJyb3IoXG4gICAgICAgIGBVbnN1cHBvcnRlZCBmaWxlIGV4dGVuc2lvbiAnJHtleHR9Jy4gTU1TIHN1cHBvcnRzIEpQRUcsIFBORywgYW5kIEdJRi5gLFxuICAgICAgKTtcbiAgICAgIHRoaXMuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBjb25zdCBidWZmZXIgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZVBhdGgpO1xuICAgIGNvbnN0IGZpbGVuYW1lID0gcGF0aC5iYXNlbmFtZShmaWxlUGF0aCk7XG5cbiAgICBjb25zdCBkZXRlY3RlZCA9XG4gICAgICBmbGFnc1tcImNvbnRlbnQtdHlwZVwiXSA/P1xuICAgICAgKGV4dCA9PT0gXCIucG5nXCJcbiAgICAgICAgPyBcImltYWdlL3BuZ1wiXG4gICAgICAgIDogZXh0ID09PSBcIi5naWZcIlxuICAgICAgICAgID8gXCJpbWFnZS9naWZcIlxuICAgICAgICAgIDogXCJpbWFnZS9qcGVnXCIpO1xuXG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGFwaUNsaWVudC51cGxvYWRGaWxlPE1lZGlhVXBsb2FkUmVzcG9uc2U+KFxuICAgICAgXCIvYXBpL3YxL21lZGlhXCIsXG4gICAgICB7XG4gICAgICAgIGJ1ZmZlcixcbiAgICAgICAgZmlsZW5hbWUsXG4gICAgICAgIG1pbWV0eXBlOiBkZXRlY3RlZCxcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIGlmIChpc0pzb25Nb2RlKCkpIHtcbiAgICAgIGpzb24ocmVzcCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc3VjY2VzcyhcIk1lZGlhIHVwbG9hZGVkXCIsIHtcbiAgICAgIElEOiByZXNwLmlkLFxuICAgICAgVVJMOiByZXNwLnVybCxcbiAgICAgIFwiQ29udGVudC1UeXBlXCI6IHJlc3AuY29udGVudFR5cGUsXG4gICAgICBTaXplOiBmb3JtYXRCeXRlcyhyZXNwLnNpemVCeXRlcyksXG4gICAgfSk7XG4gICAgY29uc29sZS5sb2coKTtcbiAgICBjb25zb2xlLmxvZyhjb2xvcnMuZGltKFwiICBTZW5kIGFuIE1NUyB3aXRoIHRoaXMgaW1hZ2U6XCIpKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIFwiICAgIFwiICtcbiAgICAgICAgY29sb3JzLmNvZGUoXG4gICAgICAgICAgYHNlbmRseSBzbXMgc2VuZCAtLXRvICsxNTU1MTIzNDU2NyAtLXRleHQgXCJIaVwiIC0tbWVkaWEgXCIke3Jlc3AudXJsfVwiYCxcbiAgICAgICAgKSxcbiAgICApO1xuICB9XG59XG5cbmZ1bmN0aW9uIGZvcm1hdEJ5dGVzKG46IG51bWJlcik6IHN0cmluZyB7XG4gIGlmIChuIDwgMTAyNCkgcmV0dXJuIGAke259IEJgO1xuICBpZiAobiA8IDEwMjQgKiAxMDI0KSByZXR1cm4gYCR7KG4gLyAxMDI0KS50b0ZpeGVkKDEpfSBLQmA7XG4gIHJldHVybiBgJHsobiAvICgxMDI0ICogMTAyNCkpLnRvRml4ZWQoMSl9IE1CYDtcbn1cbiJdfQ==
@@ -0,0 +1,25 @@
1
+ import { AuthenticatedCommand } from "../../lib/base-command.js";
2
+ /**
3
+ * `sendly templates enhance` — AI rewrite a message template for
4
+ * compliance/clarity/conversions.
5
+ *
6
+ * Wraps `POST /api/v1/ai/enhance` (flag-gated behind `ai_classification`
7
+ * on the server — if your account doesn't have the flag, the server
8
+ * returns 404 and this command surfaces it). Accepts text directly via
9
+ * `--text`, from a file via `--file`, or piped on stdin.
10
+ */
11
+ export default class TemplatesEnhance extends AuthenticatedCommand {
12
+ static description: string;
13
+ static examples: string[];
14
+ static args: {
15
+ text: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
16
+ };
17
+ static flags: {
18
+ text: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
19
+ file: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
20
+ "message-type": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
21
+ json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
22
+ quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
23
+ };
24
+ run(): Promise<void>;
25
+ }
@@ -0,0 +1,77 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import * as fs from "node:fs";
3
+ import { AuthenticatedCommand } from "../../lib/base-command.js";
4
+ import { apiClient } from "../../lib/api-client.js";
5
+ import { success, json, isJsonMode, colors, header, info, error, } from "../../lib/output.js";
6
+ /**
7
+ * `sendly templates enhance` — AI rewrite a message template for
8
+ * compliance/clarity/conversions.
9
+ *
10
+ * Wraps `POST /api/v1/ai/enhance` (flag-gated behind `ai_classification`
11
+ * on the server — if your account doesn't have the flag, the server
12
+ * returns 404 and this command surfaces it). Accepts text directly via
13
+ * `--text`, from a file via `--file`, or piped on stdin.
14
+ */
15
+ export default class TemplatesEnhance extends AuthenticatedCommand {
16
+ static description = "AI-enhance a message template for clarity, compliance, and send-readiness. Returns the rewritten text + an explanation.";
17
+ static examples = [
18
+ '<%= config.bin %> templates enhance --text "hey come check out our sale"',
19
+ '<%= config.bin %> templates enhance --file ./draft.txt --message-type marketing',
20
+ '<%= config.bin %> echo "your sale msg" | sendly templates enhance --message-type promotional',
21
+ ];
22
+ static args = {
23
+ text: Args.string({
24
+ description: "Message text to enhance (alternative to --text / --file)",
25
+ required: false,
26
+ }),
27
+ };
28
+ static flags = {
29
+ ...AuthenticatedCommand.baseFlags,
30
+ text: Flags.string({
31
+ description: "Message text to enhance",
32
+ }),
33
+ file: Flags.string({
34
+ description: "Read message text from a file path",
35
+ }),
36
+ "message-type": Flags.string({
37
+ description: "Hint the kind of message (e.g. marketing, transactional, notification) for targeted enhancements",
38
+ }),
39
+ };
40
+ async run() {
41
+ const { args, flags } = await this.parse(TemplatesEnhance);
42
+ let text = flags.text ?? args.text;
43
+ if (!text && flags.file) {
44
+ text = fs.readFileSync(flags.file, "utf8").trim();
45
+ }
46
+ if (!text && !process.stdin.isTTY) {
47
+ text = await new Promise((resolve) => {
48
+ let buf = "";
49
+ process.stdin.setEncoding("utf8");
50
+ process.stdin.on("data", (c) => (buf += c));
51
+ process.stdin.on("end", () => resolve(buf.trim()));
52
+ });
53
+ }
54
+ if (!text && !flags["message-type"]) {
55
+ error("Provide text via --text, --file, positional arg, or stdin (or at least --message-type for a template suggestion).");
56
+ this.exit(1);
57
+ }
58
+ const resp = await apiClient.post("/api/v1/ai/enhance", {
59
+ text: text ?? "",
60
+ messageType: flags["message-type"],
61
+ });
62
+ if (isJsonMode()) {
63
+ json(resp);
64
+ return;
65
+ }
66
+ header("Enhanced text");
67
+ console.log(" " + (resp.enhanced || colors.dim("(no change)")));
68
+ if (resp.explanation) {
69
+ console.log();
70
+ info(resp.explanation);
71
+ }
72
+ if (!resp.enhanced || resp.enhanced === text) {
73
+ success("No enhancement suggested — original text looks good.");
74
+ }
75
+ }
76
+ }
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5oYW5jZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy90ZW1wbGF0ZXMvZW5oYW5jZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxQyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUNMLE9BQU8sRUFDUCxJQUFJLEVBQ0osVUFBVSxFQUNWLE1BQU0sRUFDTixNQUFNLEVBQ04sSUFBSSxFQUNKLEtBQUssR0FDTixNQUFNLHFCQUFxQixDQUFDO0FBTzdCOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxnQkFBaUIsU0FBUSxvQkFBb0I7SUFDaEUsTUFBTSxDQUFDLFdBQVcsR0FDaEIseUhBQXlILENBQUM7SUFFNUgsTUFBTSxDQUFDLFFBQVEsR0FBRztRQUNoQiwwRUFBMEU7UUFDMUUsaUZBQWlGO1FBQ2pGLDhGQUE4RjtLQUMvRixDQUFDO0lBRUYsTUFBTSxDQUFDLElBQUksR0FBRztRQUNaLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQ2hCLFdBQVcsRUFBRSwwREFBMEQ7WUFDdkUsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQztLQUNILENBQUM7SUFFRixNQUFNLENBQUMsS0FBSyxHQUFHO1FBQ2IsR0FBRyxvQkFBb0IsQ0FBQyxTQUFTO1FBQ2pDLElBQUksRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDO1lBQ2pCLFdBQVcsRUFBRSx5QkFBeUI7U0FDdkMsQ0FBQztRQUNGLElBQUksRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDO1lBQ2pCLFdBQVcsRUFBRSxvQ0FBb0M7U0FDbEQsQ0FBQztRQUNGLGNBQWMsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDO1lBQzNCLFdBQVcsRUFDVCxrR0FBa0c7U0FDckcsQ0FBQztLQUNILENBQUM7SUFFRixLQUFLLENBQUMsR0FBRztRQUNQLE1BQU0sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFFM0QsSUFBSSxJQUFJLEdBQXVCLEtBQUssQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQztRQUN2RCxJQUFJLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN4QixJQUFJLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3BELENBQUM7UUFDRCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNsQyxJQUFJLEdBQUcsTUFBTSxJQUFJLE9BQU8sQ0FBUyxDQUFDLE9BQU8sRUFBRSxFQUFFO2dCQUMzQyxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUM7Z0JBQ2IsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDNUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3JELENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxLQUFLLENBQ0gsbUhBQW1ILENBQ3BILENBQUM7WUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2YsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLE1BQU0sU0FBUyxDQUFDLElBQUksQ0FDL0Isb0JBQW9CLEVBQ3BCO1lBQ0UsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFO1lBQ2hCLFdBQVcsRUFBRSxLQUFLLENBQUMsY0FBYyxDQUFDO1NBQ25DLENBQ0YsQ0FBQztRQUVGLElBQUksVUFBVSxFQUFFLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDWCxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN6QixDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUM3QyxPQUFPLENBQUMsc0RBQXNELENBQUMsQ0FBQztRQUNsRSxDQUFDO0lBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFyZ3MsIEZsYWdzIH0gZnJvbSBcIkBvY2xpZi9jb3JlXCI7XG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgQXV0aGVudGljYXRlZENvbW1hbmQgfSBmcm9tIFwiLi4vLi4vbGliL2Jhc2UtY29tbWFuZC5qc1wiO1xuaW1wb3J0IHsgYXBpQ2xpZW50IH0gZnJvbSBcIi4uLy4uL2xpYi9hcGktY2xpZW50LmpzXCI7XG5pbXBvcnQge1xuICBzdWNjZXNzLFxuICBqc29uLFxuICBpc0pzb25Nb2RlLFxuICBjb2xvcnMsXG4gIGhlYWRlcixcbiAgaW5mbyxcbiAgZXJyb3IsXG59IGZyb20gXCIuLi8uLi9saWIvb3V0cHV0LmpzXCI7XG5cbmludGVyZmFjZSBFbmhhbmNlUmVzcG9uc2Uge1xuICBlbmhhbmNlZDogc3RyaW5nO1xuICBleHBsYW5hdGlvbjogc3RyaW5nO1xufVxuXG4vKipcbiAqIGBzZW5kbHkgdGVtcGxhdGVzIGVuaGFuY2VgIOKAlCBBSSByZXdyaXRlIGEgbWVzc2FnZSB0ZW1wbGF0ZSBmb3JcbiAqIGNvbXBsaWFuY2UvY2xhcml0eS9jb252ZXJzaW9ucy5cbiAqXG4gKiBXcmFwcyBgUE9TVCAvYXBpL3YxL2FpL2VuaGFuY2VgIChmbGFnLWdhdGVkIGJlaGluZCBgYWlfY2xhc3NpZmljYXRpb25gXG4gKiBvbiB0aGUgc2VydmVyIOKAlCBpZiB5b3VyIGFjY291bnQgZG9lc24ndCBoYXZlIHRoZSBmbGFnLCB0aGUgc2VydmVyXG4gKiByZXR1cm5zIDQwNCBhbmQgdGhpcyBjb21tYW5kIHN1cmZhY2VzIGl0KS4gQWNjZXB0cyB0ZXh0IGRpcmVjdGx5IHZpYVxuICogYC0tdGV4dGAsIGZyb20gYSBmaWxlIHZpYSBgLS1maWxlYCwgb3IgcGlwZWQgb24gc3RkaW4uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlbXBsYXRlc0VuaGFuY2UgZXh0ZW5kcyBBdXRoZW50aWNhdGVkQ29tbWFuZCB7XG4gIHN0YXRpYyBkZXNjcmlwdGlvbiA9XG4gICAgXCJBSS1lbmhhbmNlIGEgbWVzc2FnZSB0ZW1wbGF0ZSBmb3IgY2xhcml0eSwgY29tcGxpYW5jZSwgYW5kIHNlbmQtcmVhZGluZXNzLiBSZXR1cm5zIHRoZSByZXdyaXR0ZW4gdGV4dCArIGFuIGV4cGxhbmF0aW9uLlwiO1xuXG4gIHN0YXRpYyBleGFtcGxlcyA9IFtcbiAgICAnPCU9IGNvbmZpZy5iaW4gJT4gdGVtcGxhdGVzIGVuaGFuY2UgLS10ZXh0IFwiaGV5IGNvbWUgY2hlY2sgb3V0IG91ciBzYWxlXCInLFxuICAgICc8JT0gY29uZmlnLmJpbiAlPiB0ZW1wbGF0ZXMgZW5oYW5jZSAtLWZpbGUgLi9kcmFmdC50eHQgLS1tZXNzYWdlLXR5cGUgbWFya2V0aW5nJyxcbiAgICAnPCU9IGNvbmZpZy5iaW4gJT4gZWNobyBcInlvdXIgc2FsZSBtc2dcIiB8IHNlbmRseSB0ZW1wbGF0ZXMgZW5oYW5jZSAtLW1lc3NhZ2UtdHlwZSBwcm9tb3Rpb25hbCcsXG4gIF07XG5cbiAgc3RhdGljIGFyZ3MgPSB7XG4gICAgdGV4dDogQXJncy5zdHJpbmcoe1xuICAgICAgZGVzY3JpcHRpb246IFwiTWVzc2FnZSB0ZXh0IHRvIGVuaGFuY2UgKGFsdGVybmF0aXZlIHRvIC0tdGV4dCAvIC0tZmlsZSlcIixcbiAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICB9KSxcbiAgfTtcblxuICBzdGF0aWMgZmxhZ3MgPSB7XG4gICAgLi4uQXV0aGVudGljYXRlZENvbW1hbmQuYmFzZUZsYWdzLFxuICAgIHRleHQ6IEZsYWdzLnN0cmluZyh7XG4gICAgICBkZXNjcmlwdGlvbjogXCJNZXNzYWdlIHRleHQgdG8gZW5oYW5jZVwiLFxuICAgIH0pLFxuICAgIGZpbGU6IEZsYWdzLnN0cmluZyh7XG4gICAgICBkZXNjcmlwdGlvbjogXCJSZWFkIG1lc3NhZ2UgdGV4dCBmcm9tIGEgZmlsZSBwYXRoXCIsXG4gICAgfSksXG4gICAgXCJtZXNzYWdlLXR5cGVcIjogRmxhZ3Muc3RyaW5nKHtcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkhpbnQgdGhlIGtpbmQgb2YgbWVzc2FnZSAoZS5nLiBtYXJrZXRpbmcsIHRyYW5zYWN0aW9uYWwsIG5vdGlmaWNhdGlvbikgZm9yIHRhcmdldGVkIGVuaGFuY2VtZW50c1wiLFxuICAgIH0pLFxuICB9O1xuXG4gIGFzeW5jIHJ1bigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGFyZ3MsIGZsYWdzIH0gPSBhd2FpdCB0aGlzLnBhcnNlKFRlbXBsYXRlc0VuaGFuY2UpO1xuXG4gICAgbGV0IHRleHQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IGZsYWdzLnRleHQgPz8gYXJncy50ZXh0O1xuICAgIGlmICghdGV4dCAmJiBmbGFncy5maWxlKSB7XG4gICAgICB0ZXh0ID0gZnMucmVhZEZpbGVTeW5jKGZsYWdzLmZpbGUsIFwidXRmOFwiKS50cmltKCk7XG4gICAgfVxuICAgIGlmICghdGV4dCAmJiAhcHJvY2Vzcy5zdGRpbi5pc1RUWSkge1xuICAgICAgdGV4dCA9IGF3YWl0IG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgbGV0IGJ1ZiA9IFwiXCI7XG4gICAgICAgIHByb2Nlc3Muc3RkaW4uc2V0RW5jb2RpbmcoXCJ1dGY4XCIpO1xuICAgICAgICBwcm9jZXNzLnN0ZGluLm9uKFwiZGF0YVwiLCAoYykgPT4gKGJ1ZiArPSBjKSk7XG4gICAgICAgIHByb2Nlc3Muc3RkaW4ub24oXCJlbmRcIiwgKCkgPT4gcmVzb2x2ZShidWYudHJpbSgpKSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoIXRleHQgJiYgIWZsYWdzW1wibWVzc2FnZS10eXBlXCJdKSB7XG4gICAgICBlcnJvcihcbiAgICAgICAgXCJQcm92aWRlIHRleHQgdmlhIC0tdGV4dCwgLS1maWxlLCBwb3NpdGlvbmFsIGFyZywgb3Igc3RkaW4gKG9yIGF0IGxlYXN0IC0tbWVzc2FnZS10eXBlIGZvciBhIHRlbXBsYXRlIHN1Z2dlc3Rpb24pLlwiLFxuICAgICAgKTtcbiAgICAgIHRoaXMuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwID0gYXdhaXQgYXBpQ2xpZW50LnBvc3Q8RW5oYW5jZVJlc3BvbnNlPihcbiAgICAgIFwiL2FwaS92MS9haS9lbmhhbmNlXCIsXG4gICAgICB7XG4gICAgICAgIHRleHQ6IHRleHQgPz8gXCJcIixcbiAgICAgICAgbWVzc2FnZVR5cGU6IGZsYWdzW1wibWVzc2FnZS10eXBlXCJdLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgaWYgKGlzSnNvbk1vZGUoKSkge1xuICAgICAganNvbihyZXNwKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBoZWFkZXIoXCJFbmhhbmNlZCB0ZXh0XCIpO1xuICAgIGNvbnNvbGUubG9nKFwiICBcIiArIChyZXNwLmVuaGFuY2VkIHx8IGNvbG9ycy5kaW0oXCIobm8gY2hhbmdlKVwiKSkpO1xuICAgIGlmIChyZXNwLmV4cGxhbmF0aW9uKSB7XG4gICAgICBjb25zb2xlLmxvZygpO1xuICAgICAgaW5mbyhyZXNwLmV4cGxhbmF0aW9uKTtcbiAgICB9XG4gICAgaWYgKCFyZXNwLmVuaGFuY2VkIHx8IHJlc3AuZW5oYW5jZWQgPT09IHRleHQpIHtcbiAgICAgIHN1Y2Nlc3MoXCJObyBlbmhhbmNlbWVudCBzdWdnZXN0ZWQg4oCUIG9yaWdpbmFsIHRleHQgbG9va3MgZ29vZC5cIik7XG4gICAgfVxuICB9XG59XG4iXX0=
@@ -0,0 +1,25 @@
1
+ import { Command } from "@oclif/core";
2
+ /**
3
+ * `sendly upgrade` — bring the CLI up to the latest version.
4
+ *
5
+ * Detects the install path (Homebrew vs npm-global vs unknown) and
6
+ * executes the matching package-manager upgrade command. If the install
7
+ * path is unknown we print both options for the user to pick.
8
+ *
9
+ * The `--check` flag does a dry-run: prints what would happen without
10
+ * executing anything. Useful in restricted shells where we don't want
11
+ * to trigger a brew/npm run accidentally.
12
+ *
13
+ * The unattended in-band update banner that prompts users to run this
14
+ * comes from the `@oclif/plugin-warn-if-update-available` plugin wired
15
+ * in package.json; this command is the companion action for that
16
+ * banner.
17
+ */
18
+ export default class Upgrade extends Command {
19
+ static description: string;
20
+ static examples: string[];
21
+ static flags: {
22
+ check: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
23
+ };
24
+ run(): Promise<void>;
25
+ }
@@ -0,0 +1,67 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { spawn } from "node:child_process";
3
+ import { detectInstallPath, upgradeCommandFor, } from "../lib/detect-install-path.js";
4
+ import { success, error, info } from "../lib/output.js";
5
+ /**
6
+ * `sendly upgrade` — bring the CLI up to the latest version.
7
+ *
8
+ * Detects the install path (Homebrew vs npm-global vs unknown) and
9
+ * executes the matching package-manager upgrade command. If the install
10
+ * path is unknown we print both options for the user to pick.
11
+ *
12
+ * The `--check` flag does a dry-run: prints what would happen without
13
+ * executing anything. Useful in restricted shells where we don't want
14
+ * to trigger a brew/npm run accidentally.
15
+ *
16
+ * The unattended in-band update banner that prompts users to run this
17
+ * comes from the `@oclif/plugin-warn-if-update-available` plugin wired
18
+ * in package.json; this command is the companion action for that
19
+ * banner.
20
+ */
21
+ export default class Upgrade extends Command {
22
+ static description = "Upgrade Sendly CLI to the latest version using the package manager that installed it (Homebrew or npm).";
23
+ static examples = [
24
+ "<%= config.bin %> upgrade",
25
+ "<%= config.bin %> upgrade --check",
26
+ ];
27
+ static flags = {
28
+ check: Flags.boolean({
29
+ description: "Print the upgrade command for your install path without executing it",
30
+ default: false,
31
+ }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(Upgrade);
35
+ const installPath = detectInstallPath();
36
+ const command = upgradeCommandFor(installPath);
37
+ if (installPath === "unknown") {
38
+ info("Can't detect how you installed the Sendly CLI. Pick the matching command:\n" +
39
+ " • Homebrew: brew upgrade sendly\n" +
40
+ " • npm: npm install -g @sendly/cli@latest");
41
+ return;
42
+ }
43
+ if (flags.check) {
44
+ info(`Detected install path: ${installPath}\nWould run: ${command}`);
45
+ return;
46
+ }
47
+ info(`Upgrading via ${installPath}: ${command}`);
48
+ const [bin, ...args] = command.split(" ");
49
+ const child = spawn(bin, args, { stdio: "inherit" });
50
+ await new Promise((resolve) => {
51
+ child.on("exit", (code) => {
52
+ if (code === 0) {
53
+ success("Upgrade complete. Run `sendly --version` to confirm the new version.");
54
+ }
55
+ else {
56
+ error(`Upgrade command exited with code ${code}. Try running \`${command}\` manually.`);
57
+ }
58
+ resolve();
59
+ });
60
+ child.on("error", (err) => {
61
+ error(`Failed to execute upgrade command: ${err.message}. Try running \`${command}\` manually.`);
62
+ resolve();
63
+ });
64
+ });
65
+ }
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBncmFkZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21tYW5kcy91cGdyYWRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGlCQUFpQixHQUNsQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXhEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sT0FBUSxTQUFRLE9BQU87SUFDMUMsTUFBTSxDQUFDLFdBQVcsR0FDaEIseUdBQXlHLENBQUM7SUFFNUcsTUFBTSxDQUFDLFFBQVEsR0FBRztRQUNoQiwyQkFBMkI7UUFDM0IsbUNBQW1DO0tBQ3BDLENBQUM7SUFFRixNQUFNLENBQUMsS0FBSyxHQUFHO1FBQ2IsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDbkIsV0FBVyxFQUNULHNFQUFzRTtZQUN4RSxPQUFPLEVBQUUsS0FBSztTQUNmLENBQUM7S0FDSCxDQUFDO0lBRUYsS0FBSyxDQUFDLEdBQUc7UUFDUCxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTVDLE1BQU0sV0FBVyxHQUFHLGlCQUFpQixFQUFFLENBQUM7UUFDeEMsTUFBTSxPQUFPLEdBQUcsaUJBQWlCLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFL0MsSUFBSSxXQUFXLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUNGLDZFQUE2RTtnQkFDM0UscUNBQXFDO2dCQUNyQyxpREFBaUQsQ0FDcEQsQ0FBQztZQUNGLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUNGLDBCQUEwQixXQUFXLGdCQUFnQixPQUFPLEVBQUUsQ0FDL0QsQ0FBQztZQUNGLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLGlCQUFpQixXQUFXLEtBQUssT0FBTyxFQUFFLENBQUMsQ0FBQztRQUVqRCxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMxQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBRXJELE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNsQyxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUN4QixJQUFJLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDZixPQUFPLENBQ0wsc0VBQXNFLENBQ3ZFLENBQUM7Z0JBQ0osQ0FBQztxQkFBTSxDQUFDO29CQUNOLEtBQUssQ0FDSCxvQ0FBb0MsSUFBSSxtQkFBbUIsT0FBTyxjQUFjLENBQ2pGLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUMsQ0FBQyxDQUFDO1lBQ0gsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDeEIsS0FBSyxDQUNILHNDQUFzQyxHQUFHLENBQUMsT0FBTyxtQkFBbUIsT0FBTyxjQUFjLENBQzFGLENBQUM7Z0JBQ0YsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1hbmQsIEZsYWdzIH0gZnJvbSBcIkBvY2xpZi9jb3JlXCI7XG5pbXBvcnQgeyBzcGF3biB9IGZyb20gXCJub2RlOmNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7XG4gIGRldGVjdEluc3RhbGxQYXRoLFxuICB1cGdyYWRlQ29tbWFuZEZvcixcbn0gZnJvbSBcIi4uL2xpYi9kZXRlY3QtaW5zdGFsbC1wYXRoLmpzXCI7XG5pbXBvcnQgeyBzdWNjZXNzLCBlcnJvciwgaW5mbyB9IGZyb20gXCIuLi9saWIvb3V0cHV0LmpzXCI7XG5cbi8qKlxuICogYHNlbmRseSB1cGdyYWRlYCDigJQgYnJpbmcgdGhlIENMSSB1cCB0byB0aGUgbGF0ZXN0IHZlcnNpb24uXG4gKlxuICogRGV0ZWN0cyB0aGUgaW5zdGFsbCBwYXRoIChIb21lYnJldyB2cyBucG0tZ2xvYmFsIHZzIHVua25vd24pIGFuZFxuICogZXhlY3V0ZXMgdGhlIG1hdGNoaW5nIHBhY2thZ2UtbWFuYWdlciB1cGdyYWRlIGNvbW1hbmQuIElmIHRoZSBpbnN0YWxsXG4gKiBwYXRoIGlzIHVua25vd24gd2UgcHJpbnQgYm90aCBvcHRpb25zIGZvciB0aGUgdXNlciB0byBwaWNrLlxuICpcbiAqIFRoZSBgLS1jaGVja2AgZmxhZyBkb2VzIGEgZHJ5LXJ1bjogcHJpbnRzIHdoYXQgd291bGQgaGFwcGVuIHdpdGhvdXRcbiAqIGV4ZWN1dGluZyBhbnl0aGluZy4gVXNlZnVsIGluIHJlc3RyaWN0ZWQgc2hlbGxzIHdoZXJlIHdlIGRvbid0IHdhbnRcbiAqIHRvIHRyaWdnZXIgYSBicmV3L25wbSBydW4gYWNjaWRlbnRhbGx5LlxuICpcbiAqIFRoZSB1bmF0dGVuZGVkIGluLWJhbmQgdXBkYXRlIGJhbm5lciB0aGF0IHByb21wdHMgdXNlcnMgdG8gcnVuIHRoaXNcbiAqIGNvbWVzIGZyb20gdGhlIGBAb2NsaWYvcGx1Z2luLXdhcm4taWYtdXBkYXRlLWF2YWlsYWJsZWAgcGx1Z2luIHdpcmVkXG4gKiBpbiBwYWNrYWdlLmpzb247IHRoaXMgY29tbWFuZCBpcyB0aGUgY29tcGFuaW9uIGFjdGlvbiBmb3IgdGhhdFxuICogYmFubmVyLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBVcGdyYWRlIGV4dGVuZHMgQ29tbWFuZCB7XG4gIHN0YXRpYyBkZXNjcmlwdGlvbiA9XG4gICAgXCJVcGdyYWRlIFNlbmRseSBDTEkgdG8gdGhlIGxhdGVzdCB2ZXJzaW9uIHVzaW5nIHRoZSBwYWNrYWdlIG1hbmFnZXIgdGhhdCBpbnN0YWxsZWQgaXQgKEhvbWVicmV3IG9yIG5wbSkuXCI7XG5cbiAgc3RhdGljIGV4YW1wbGVzID0gW1xuICAgIFwiPCU9IGNvbmZpZy5iaW4gJT4gdXBncmFkZVwiLFxuICAgIFwiPCU9IGNvbmZpZy5iaW4gJT4gdXBncmFkZSAtLWNoZWNrXCIsXG4gIF07XG5cbiAgc3RhdGljIGZsYWdzID0ge1xuICAgIGNoZWNrOiBGbGFncy5ib29sZWFuKHtcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIlByaW50IHRoZSB1cGdyYWRlIGNvbW1hbmQgZm9yIHlvdXIgaW5zdGFsbCBwYXRoIHdpdGhvdXQgZXhlY3V0aW5nIGl0XCIsXG4gICAgICBkZWZhdWx0OiBmYWxzZSxcbiAgICB9KSxcbiAgfTtcblxuICBhc3luYyBydW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBmbGFncyB9ID0gYXdhaXQgdGhpcy5wYXJzZShVcGdyYWRlKTtcblxuICAgIGNvbnN0IGluc3RhbGxQYXRoID0gZGV0ZWN0SW5zdGFsbFBhdGgoKTtcbiAgICBjb25zdCBjb21tYW5kID0gdXBncmFkZUNvbW1hbmRGb3IoaW5zdGFsbFBhdGgpO1xuXG4gICAgaWYgKGluc3RhbGxQYXRoID09PSBcInVua25vd25cIikge1xuICAgICAgaW5mbyhcbiAgICAgICAgXCJDYW4ndCBkZXRlY3QgaG93IHlvdSBpbnN0YWxsZWQgdGhlIFNlbmRseSBDTEkuIFBpY2sgdGhlIG1hdGNoaW5nIGNvbW1hbmQ6XFxuXCIgK1xuICAgICAgICAgIFwiICDigKIgSG9tZWJyZXc6IGJyZXcgdXBncmFkZSBzZW5kbHlcXG5cIiArXG4gICAgICAgICAgXCIgIOKAoiBucG06ICAgICAgbnBtIGluc3RhbGwgLWcgQHNlbmRseS9jbGlAbGF0ZXN0XCIsXG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChmbGFncy5jaGVjaykge1xuICAgICAgaW5mbyhcbiAgICAgICAgYERldGVjdGVkIGluc3RhbGwgcGF0aDogJHtpbnN0YWxsUGF0aH1cXG5Xb3VsZCBydW46ICR7Y29tbWFuZH1gLFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpbmZvKGBVcGdyYWRpbmcgdmlhICR7aW5zdGFsbFBhdGh9OiAke2NvbW1hbmR9YCk7XG5cbiAgICBjb25zdCBbYmluLCAuLi5hcmdzXSA9IGNvbW1hbmQuc3BsaXQoXCIgXCIpO1xuICAgIGNvbnN0IGNoaWxkID0gc3Bhd24oYmluLCBhcmdzLCB7IHN0ZGlvOiBcImluaGVyaXRcIiB9KTtcblxuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBjaGlsZC5vbihcImV4aXRcIiwgKGNvZGUpID0+IHtcbiAgICAgICAgaWYgKGNvZGUgPT09IDApIHtcbiAgICAgICAgICBzdWNjZXNzKFxuICAgICAgICAgICAgXCJVcGdyYWRlIGNvbXBsZXRlLiBSdW4gYHNlbmRseSAtLXZlcnNpb25gIHRvIGNvbmZpcm0gdGhlIG5ldyB2ZXJzaW9uLlwiLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXJyb3IoXG4gICAgICAgICAgICBgVXBncmFkZSBjb21tYW5kIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS4gVHJ5IHJ1bm5pbmcgXFxgJHtjb21tYW5kfVxcYCBtYW51YWxseS5gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gICAgICBjaGlsZC5vbihcImVycm9yXCIsIChlcnIpID0+IHtcbiAgICAgICAgZXJyb3IoXG4gICAgICAgICAgYEZhaWxlZCB0byBleGVjdXRlIHVwZ3JhZGUgY29tbWFuZDogJHtlcnIubWVzc2FnZX0uIFRyeSBydW5uaW5nIFxcYCR7Y29tbWFuZH1cXGAgbWFudWFsbHkuYCxcbiAgICAgICAgKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==