@letterstory/cli 0.61.0 → 0.61.2
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/lib/cli.mjs +9 -4
- package/lib/commands/outbound.mjs +30 -2
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
} from "./commands.mjs";
|
|
56
56
|
|
|
57
57
|
// Keep in sync with cli/package.json.
|
|
58
|
-
export const VERSION = "0.61.
|
|
58
|
+
export const VERSION = "0.61.2";
|
|
59
59
|
|
|
60
60
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
61
61
|
// can't accidentally swallow the id as --json's value.
|
|
@@ -123,8 +123,9 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
123
123
|
"no-enrich",
|
|
124
124
|
// `offerings set-collection <id> --none` (the org itself is the subject again).
|
|
125
125
|
"none",
|
|
126
|
-
// `prospects import|source --one-per-company`.
|
|
126
|
+
// `prospects import|source --one-per-company`, `prospects source --enrich`.
|
|
127
127
|
"one-per-company",
|
|
128
|
+
"enrich",
|
|
128
129
|
// `targets update <id> --clear-framing`.
|
|
129
130
|
"clear-framing",
|
|
130
131
|
]);
|
|
@@ -807,10 +808,13 @@ Sequences (multi-step cold email sent from your mailers; approving or enrolling
|
|
|
807
808
|
sequences get <sequence-id> Flow, enrollments, who replied at each step
|
|
808
809
|
sequences create --name <n> (--flow '<json>'|--flow-file <path>) [--mailer <mailer-id>]...
|
|
809
810
|
[--[no-]opt-out-footer] [--[no-]postal-address-footer] [--[no-]unsubscribe-links] [--[no-]detect-reply-opt-outs]
|
|
810
|
-
|
|
811
|
+
[--send-window-start <HH:MM>] [--send-window-end <HH:MM>] [--send-window-timezone <IANA tz>]
|
|
812
|
+
New draft sequence (nothing sends yet; rails default on, opt-out line off;
|
|
813
|
+
sends 9:00-17:00 in each recipient's inferred timezone, else the sender's)
|
|
811
814
|
sequences update <sequence-id> [--name <n>] [--flow '<json>'|--flow-file <path>]
|
|
812
815
|
[--status draft|active|paused|archived] [--mailer <mailer-id>]...
|
|
813
816
|
[--[no-]opt-out-footer] [--[no-]postal-address-footer] [--[no-]unsubscribe-links] [--[no-]detect-reply-opt-outs]
|
|
817
|
+
[--send-window-start <HH:MM>] [--send-window-end <HH:MM>] [--send-window-timezone <IANA tz>]
|
|
814
818
|
sequences pause|resume <sequence-id> Stop / restart sending
|
|
815
819
|
sequences enroll <sequence-id> (--list <list-id> | --email <addr>... | --recipients '<json>'|--recipients-file <path>)
|
|
816
820
|
sequences stop <sequence-id> <enrollment-id> Stop one recipient
|
|
@@ -829,7 +833,8 @@ Prospects (who you write to):
|
|
|
829
833
|
prospects create-list --name <n>
|
|
830
834
|
prospects import --csv-file <path|-> [--list <list-id>|--list-name <n>] [--one-per-company]
|
|
831
835
|
prospects source --description <who you want> [--list <list-id>|--list-name <n>] [--limit <1..100>]
|
|
832
|
-
[--one-per-company]
|
|
836
|
+
[--one-per-company] [--enrich] Fill a list from paid data providers (background);
|
|
837
|
+
--enrich starts enrichment as soon as the pull lands
|
|
833
838
|
prospects enrich [--list <list-id>] [--status <s>] [--q <search>]
|
|
834
839
|
Funding + competitors for un-enriched rows
|
|
835
840
|
prospects update <prospect-id> [--status new|contacted|replied|unsubscribed|archived] [--name <n>]
|
|
@@ -60,6 +60,31 @@ const SEQUENCE_RAIL_ARGS = {
|
|
|
60
60
|
unsubscribe_links: { flag: "unsubscribe-links", type: "bool", negate: "no-unsubscribe-links" },
|
|
61
61
|
detect_reply_opt_outs: { flag: "detect-reply-opt-outs", type: "bool", negate: "no-detect-reply-opt-outs" },
|
|
62
62
|
};
|
|
63
|
+
|
|
64
|
+
// A send-window edge from --<flag> HH:MM (or a raw minute of day) → the
|
|
65
|
+
// schema's minute-of-day number.
|
|
66
|
+
function windowMinute(flag) {
|
|
67
|
+
return (flags) => {
|
|
68
|
+
const raw = flagStr(flags[flag]);
|
|
69
|
+
if (raw === undefined) return undefined;
|
|
70
|
+
if (/^\d+$/.test(raw)) return Number(raw);
|
|
71
|
+
const match = /^(\d{1,2}):(\d{2})$/.exec(raw);
|
|
72
|
+
if (!match || Number(match[1]) > 23 || Number(match[2]) > 59) {
|
|
73
|
+
throw new CliError(`--${flag} takes HH:MM or a minute of day 0–1439 (got ${raw})`);
|
|
74
|
+
}
|
|
75
|
+
return Number(match[1]) * 60 + Number(match[2]);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The send window, shared by create and update: when emails may go out
|
|
80
|
+
// (default 9:00–17:00), in each recipient's inferred timezone, falling back to
|
|
81
|
+
// the sender's --send-window-timezone when the location is unknown. Equal
|
|
82
|
+
// start and end turns the window off.
|
|
83
|
+
const SEQUENCE_WINDOW_ARGS = {
|
|
84
|
+
send_window_start_minute: { value: windowMinute("send-window-start") },
|
|
85
|
+
send_window_end_minute: { value: windowMinute("send-window-end") },
|
|
86
|
+
send_window_timezone: "send-window-timezone",
|
|
87
|
+
};
|
|
63
88
|
const PROSPECT_STATUSES = ["new", "contacted", "replied", "unsubscribed", "archived"];
|
|
64
89
|
const mailerIds = {
|
|
65
90
|
value: (flags) => {
|
|
@@ -101,6 +126,7 @@ export const ARGS = {
|
|
|
101
126
|
},
|
|
102
127
|
mailer_ids: mailerIds,
|
|
103
128
|
...SEQUENCE_RAIL_ARGS,
|
|
129
|
+
...SEQUENCE_WINDOW_ARGS,
|
|
104
130
|
},
|
|
105
131
|
update_sequence: {
|
|
106
132
|
sequence_id: { positional: 0, label: "sequence-id", required: true },
|
|
@@ -109,6 +135,7 @@ export const ARGS = {
|
|
|
109
135
|
status: { flag: "status", enum: SEQUENCE_STATUSES },
|
|
110
136
|
mailer_ids: mailerIds,
|
|
111
137
|
...SEQUENCE_RAIL_ARGS,
|
|
138
|
+
...SEQUENCE_WINDOW_ARGS,
|
|
112
139
|
},
|
|
113
140
|
enroll_in_sequence: {
|
|
114
141
|
sequence_id: { positional: 0, label: "sequence-id", required: true },
|
|
@@ -176,6 +203,7 @@ export const ARGS = {
|
|
|
176
203
|
list_name: "list-name",
|
|
177
204
|
limit: { flag: "limit", type: "num" },
|
|
178
205
|
one_per_company: { flag: "one-per-company", type: "bool" },
|
|
206
|
+
enrich: { flag: "enrich", type: "bool" },
|
|
179
207
|
},
|
|
180
208
|
enrich_prospects: {
|
|
181
209
|
list_id: "list",
|
|
@@ -260,8 +288,8 @@ export const ARGS = {
|
|
|
260
288
|
|
|
261
289
|
// Flags the computed `value` sources read (refuseUnknownFlags can't see them).
|
|
262
290
|
const VALUE_FLAGS = {
|
|
263
|
-
create_sequence: ["flow", "flow-file", "mailer"],
|
|
264
|
-
update_sequence: ["flow", "flow-file", "mailer"],
|
|
291
|
+
create_sequence: ["flow", "flow-file", "mailer", "send-window-start", "send-window-end"],
|
|
292
|
+
update_sequence: ["flow", "flow-file", "mailer", "send-window-start", "send-window-end"],
|
|
265
293
|
enroll_in_sequence: ["recipients", "recipients-file", "email"],
|
|
266
294
|
update_review_item: ["body", "file"],
|
|
267
295
|
import_prospects_csv: ["csv", "csv-file"],
|