@dench.com/cli 2.2.1 → 2.2.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/email.ts +305 -4
- package/lib/command-registry.ts +238 -1
- package/package.json +1 -1
package/email.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import type { ConvexHttpClient } from "convex/browser";
|
|
3
3
|
import { makeFunctionReference } from "convex/server";
|
|
4
|
-
import { getFlag, parseJson } from "./lib/cli-args";
|
|
4
|
+
import { getFlag, hasFlag, parseJson } from "./lib/cli-args";
|
|
5
5
|
|
|
6
6
|
type EmailCliContext = {
|
|
7
7
|
convex: ConvexHttpClient;
|
|
@@ -202,11 +202,29 @@ Usage:
|
|
|
202
202
|
dench email template create --name "Intro" --subject "Hi {{firstName}}" --html-file body.html [--text-file body.txt] [--json]
|
|
203
203
|
dench email template preview --template <id> --data '{"firstName":"Ada"}' [--json]
|
|
204
204
|
dench email campaign create --name "Q2 outreach" --identity <identityId|fromEmail> --template <id> [--json]
|
|
205
|
+
dench email campaign list [--status sending] [--limit 25] [--json]
|
|
205
206
|
dench email campaign recipients add --campaign <id> --file recipients.jsonl [--json]
|
|
207
|
+
dench email campaign recipients list --campaign <id> [--status queued] [--limit 50] [--json]
|
|
208
|
+
dench email campaign recipients add-from-object --campaign <id> --object prospect --email-field "Email" --entries id1,id2 [--json]
|
|
206
209
|
dench email campaign preview --campaign <id> [--sample 5] [--json]
|
|
207
210
|
dench email campaign submit --campaign <id> [--json]
|
|
208
211
|
dench email campaign status --campaign <id> [--json]
|
|
209
|
-
dench email campaign pause|resume|cancel --campaign <id> [--json]
|
|
212
|
+
dench email campaign pause|resume|cancel --campaign <id> [--json]
|
|
213
|
+
|
|
214
|
+
Sequences (automatic multi-step follow-ups):
|
|
215
|
+
dench email sequence create --name "New-customer follow-up" --identity <identityId|fromEmail> [--stop-on-click] [--no-stop-on-reply] [--json]
|
|
216
|
+
dench email sequence list [--all] [--json]
|
|
217
|
+
dench email sequence status --sequence <id> [--json]
|
|
218
|
+
dench email sequence steps add --sequence <id> --subject "Hi {{firstName}}" --html-file step1.html [--delay-days 0] [--delay-hours 0] [--json]
|
|
219
|
+
dench email sequence steps update --step <id> [--subject ...] [--html-file ...] [--delay-days 3] [--json]
|
|
220
|
+
dench email sequence steps remove --step <id> [--json]
|
|
221
|
+
dench email sequence steps reorder --sequence <id> --steps id1,id2,id3 [--json]
|
|
222
|
+
dench email sequence activate|deactivate --sequence <id> [--json]
|
|
223
|
+
dench email sequence enroll --sequence <id> --file recipients.jsonl [--json]
|
|
224
|
+
dench email sequence enroll-from-object --sequence <id> --object prospect --email-field "Email" --entries id1,id2 [--json]
|
|
225
|
+
dench email sequence enrollments list --sequence <id> [--status active] [--limit 50] [--json]
|
|
226
|
+
dench email sequence enrollment pause|resume|stop --enrollment <id> [--json]
|
|
227
|
+
dench email sequence archive --sequence <id> [--json]`);
|
|
210
228
|
}
|
|
211
229
|
|
|
212
230
|
export async function runEmailCommand(ctx: EmailCliContext): Promise<void> {
|
|
@@ -235,9 +253,22 @@ export async function runEmailCommand(ctx: EmailCliContext): Promise<void> {
|
|
|
235
253
|
await runCampaign(ctx);
|
|
236
254
|
return;
|
|
237
255
|
}
|
|
256
|
+
if (group === "sequence") {
|
|
257
|
+
await runSequence(ctx);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
238
260
|
throw new EmailCliError(`Unknown dench email subcommand: ${group}`);
|
|
239
261
|
}
|
|
240
262
|
|
|
263
|
+
/** Parse a comma-separated list of CRM entry ids. */
|
|
264
|
+
function parseEntryIds(value: string | undefined): string[] {
|
|
265
|
+
if (!value?.trim()) return [];
|
|
266
|
+
return value
|
|
267
|
+
.split(",")
|
|
268
|
+
.map((id) => id.trim())
|
|
269
|
+
.filter(Boolean);
|
|
270
|
+
}
|
|
271
|
+
|
|
241
272
|
/**
|
|
242
273
|
* Parse a comma-separated address list where each entry is either a bare
|
|
243
274
|
* email or `Name <email>`.
|
|
@@ -662,11 +693,60 @@ async function runCampaign(ctx: EmailCliContext) {
|
|
|
662
693
|
);
|
|
663
694
|
return;
|
|
664
695
|
}
|
|
696
|
+
if (sub === "list") {
|
|
697
|
+
const limitRaw = getFlag(ctx.args, "--limit");
|
|
698
|
+
const status = getFlag(ctx.args, "--status");
|
|
699
|
+
const payload = await callQuery(
|
|
700
|
+
ctx,
|
|
701
|
+
"functions/emailCampaigns:listCampaigns",
|
|
702
|
+
{
|
|
703
|
+
paginationOpts: {
|
|
704
|
+
numItems: limitRaw ? Number(limitRaw) : 25,
|
|
705
|
+
cursor: null,
|
|
706
|
+
},
|
|
707
|
+
status,
|
|
708
|
+
},
|
|
709
|
+
);
|
|
710
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
665
713
|
if (sub === "recipients") {
|
|
666
714
|
const nested = ctx.args.shift();
|
|
715
|
+
if (nested === "list") {
|
|
716
|
+
const limitRaw = getFlag(ctx.args, "--limit");
|
|
717
|
+
const status = getFlag(ctx.args, "--status");
|
|
718
|
+
const payload = await callQuery(
|
|
719
|
+
ctx,
|
|
720
|
+
"functions/emailCampaigns:listRecipients",
|
|
721
|
+
{
|
|
722
|
+
campaignId: requiredFlag(ctx.args, "--campaign"),
|
|
723
|
+
paginationOpts: {
|
|
724
|
+
numItems: limitRaw ? Number(limitRaw) : 50,
|
|
725
|
+
cursor: null,
|
|
726
|
+
},
|
|
727
|
+
status,
|
|
728
|
+
},
|
|
729
|
+
);
|
|
730
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
if (nested === "add-from-object") {
|
|
734
|
+
const payload = await callMutation(
|
|
735
|
+
ctx,
|
|
736
|
+
"functions/emailCampaigns:addRecipientsFromCrm",
|
|
737
|
+
{
|
|
738
|
+
campaignId: requiredFlag(ctx.args, "--campaign"),
|
|
739
|
+
objectName: requiredFlag(ctx.args, "--object"),
|
|
740
|
+
emailFieldName: getFlag(ctx.args, "--email-field"),
|
|
741
|
+
entryIds: parseEntryIds(requiredFlag(ctx.args, "--entries")),
|
|
742
|
+
},
|
|
743
|
+
);
|
|
744
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
667
747
|
if (nested !== "add") {
|
|
668
748
|
throw new EmailCliError(
|
|
669
|
-
"Usage: dench email campaign recipients add
|
|
749
|
+
"Usage: dench email campaign recipients add|list|add-from-object",
|
|
670
750
|
);
|
|
671
751
|
}
|
|
672
752
|
const campaignId = requiredFlag(ctx.args, "--campaign");
|
|
@@ -734,6 +814,227 @@ async function runCampaign(ctx: EmailCliContext) {
|
|
|
734
814
|
return;
|
|
735
815
|
}
|
|
736
816
|
throw new EmailCliError(
|
|
737
|
-
"Usage: dench email campaign create|recipients|preview|submit|status|pause|resume|cancel",
|
|
817
|
+
"Usage: dench email campaign create|list|recipients|preview|submit|status|pause|resume|cancel",
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
async function runSequence(ctx: EmailCliContext) {
|
|
822
|
+
const sub = ctx.args.shift();
|
|
823
|
+
if (sub === "create") {
|
|
824
|
+
const stopOnReply = !hasFlag(ctx.args, "--no-stop-on-reply");
|
|
825
|
+
const payload = await callMutation(
|
|
826
|
+
ctx,
|
|
827
|
+
"functions/emailSequences:createSequence",
|
|
828
|
+
{
|
|
829
|
+
name: requiredFlag(ctx.args, "--name"),
|
|
830
|
+
identityId: requiredFlag(ctx.args, "--identity"),
|
|
831
|
+
replyToMode: getFlag(ctx.args, "--reply-to-mode"),
|
|
832
|
+
stopOnReply,
|
|
833
|
+
stopOnClick: getFlag(ctx.args, "--stop-on-click") !== undefined,
|
|
834
|
+
},
|
|
835
|
+
);
|
|
836
|
+
out(
|
|
837
|
+
ctx,
|
|
838
|
+
payload,
|
|
839
|
+
`Sequence created: ${(payload as JsonRecord).sequenceId}`,
|
|
840
|
+
);
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
if (sub === "update") {
|
|
844
|
+
const payload = await callMutation(
|
|
845
|
+
ctx,
|
|
846
|
+
"functions/emailSequences:updateSequence",
|
|
847
|
+
{
|
|
848
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
849
|
+
name: getFlag(ctx.args, "--name"),
|
|
850
|
+
identityId: getFlag(ctx.args, "--identity"),
|
|
851
|
+
replyToMode: getFlag(ctx.args, "--reply-to-mode"),
|
|
852
|
+
},
|
|
853
|
+
);
|
|
854
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (sub === "activate" || sub === "deactivate") {
|
|
858
|
+
const payload = await callMutation(
|
|
859
|
+
ctx,
|
|
860
|
+
"functions/emailSequences:setSequenceActive",
|
|
861
|
+
{
|
|
862
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
863
|
+
active: sub === "activate",
|
|
864
|
+
},
|
|
865
|
+
);
|
|
866
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (sub === "archive") {
|
|
870
|
+
const payload = await callMutation(
|
|
871
|
+
ctx,
|
|
872
|
+
"functions/emailSequences:archiveSequence",
|
|
873
|
+
{ sequenceId: requiredFlag(ctx.args, "--sequence") },
|
|
874
|
+
);
|
|
875
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (sub === "list") {
|
|
879
|
+
const payload = await callQuery(
|
|
880
|
+
ctx,
|
|
881
|
+
"functions/emailSequences:listSequences",
|
|
882
|
+
{ includeArchived: getFlag(ctx.args, "--all") !== undefined },
|
|
883
|
+
);
|
|
884
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (sub === "status") {
|
|
888
|
+
const payload = await callQuery(
|
|
889
|
+
ctx,
|
|
890
|
+
"functions/emailSequences:getSequence",
|
|
891
|
+
{ sequenceId: requiredFlag(ctx.args, "--sequence") },
|
|
892
|
+
);
|
|
893
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
if (sub === "steps") {
|
|
897
|
+
const nested = ctx.args.shift();
|
|
898
|
+
if (nested === "add") {
|
|
899
|
+
const htmlBody = await readTextFlag(ctx.args, "--html", "--html-file");
|
|
900
|
+
if (!htmlBody) throw new EmailCliError("Missing --html or --html-file");
|
|
901
|
+
const delayDaysRaw = getFlag(ctx.args, "--delay-days");
|
|
902
|
+
const delayHoursRaw = getFlag(ctx.args, "--delay-hours");
|
|
903
|
+
const delayHours =
|
|
904
|
+
(delayDaysRaw ? Number(delayDaysRaw) * 24 : 0) +
|
|
905
|
+
(delayHoursRaw ? Number(delayHoursRaw) : 0);
|
|
906
|
+
const payload = await callMutation(
|
|
907
|
+
ctx,
|
|
908
|
+
"functions/emailSequences:addStep",
|
|
909
|
+
{
|
|
910
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
911
|
+
subject: requiredFlag(ctx.args, "--subject"),
|
|
912
|
+
htmlBody,
|
|
913
|
+
textBody: await readTextFlag(ctx.args, "--text", "--text-file"),
|
|
914
|
+
delayHours,
|
|
915
|
+
},
|
|
916
|
+
);
|
|
917
|
+
out(ctx, payload, `Step added: ${(payload as JsonRecord).stepId}`);
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
if (nested === "update") {
|
|
921
|
+
const delayDaysRaw = getFlag(ctx.args, "--delay-days");
|
|
922
|
+
const delayHoursRaw = getFlag(ctx.args, "--delay-hours");
|
|
923
|
+
const delayHours =
|
|
924
|
+
delayDaysRaw || delayHoursRaw
|
|
925
|
+
? (delayDaysRaw ? Number(delayDaysRaw) * 24 : 0) +
|
|
926
|
+
(delayHoursRaw ? Number(delayHoursRaw) : 0)
|
|
927
|
+
: undefined;
|
|
928
|
+
const payload = await callMutation(
|
|
929
|
+
ctx,
|
|
930
|
+
"functions/emailSequences:updateStep",
|
|
931
|
+
{
|
|
932
|
+
stepId: requiredFlag(ctx.args, "--step"),
|
|
933
|
+
subject: getFlag(ctx.args, "--subject"),
|
|
934
|
+
htmlBody: await readTextFlag(ctx.args, "--html", "--html-file"),
|
|
935
|
+
textBody: await readTextFlag(ctx.args, "--text", "--text-file"),
|
|
936
|
+
delayHours,
|
|
937
|
+
},
|
|
938
|
+
);
|
|
939
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (nested === "remove") {
|
|
943
|
+
const payload = await callMutation(
|
|
944
|
+
ctx,
|
|
945
|
+
"functions/emailSequences:removeStep",
|
|
946
|
+
{ stepId: requiredFlag(ctx.args, "--step") },
|
|
947
|
+
);
|
|
948
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
if (nested === "reorder") {
|
|
952
|
+
const payload = await callMutation(
|
|
953
|
+
ctx,
|
|
954
|
+
"functions/emailSequences:reorderSteps",
|
|
955
|
+
{
|
|
956
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
957
|
+
orderedStepIds: parseEntryIds(requiredFlag(ctx.args, "--steps")),
|
|
958
|
+
},
|
|
959
|
+
);
|
|
960
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
throw new EmailCliError(
|
|
964
|
+
"Usage: dench email sequence steps add|update|remove|reorder",
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
if (sub === "enroll") {
|
|
968
|
+
const file = getFlag(ctx.args, "--file");
|
|
969
|
+
const rows = file
|
|
970
|
+
? await readRecipients(file)
|
|
971
|
+
: ((optionalJsonFlag(ctx.args, "--data") as JsonRecord[] | undefined) ??
|
|
972
|
+
[]);
|
|
973
|
+
if (rows.length === 0) throw new EmailCliError("No recipients provided");
|
|
974
|
+
const payload = await callMutation(ctx, "functions/emailSequences:enroll", {
|
|
975
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
976
|
+
recipients: toRecipients(rows),
|
|
977
|
+
});
|
|
978
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if (sub === "enroll-from-object") {
|
|
982
|
+
const payload = await callMutation(
|
|
983
|
+
ctx,
|
|
984
|
+
"functions/emailSequences:enrollFromCrm",
|
|
985
|
+
{
|
|
986
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
987
|
+
objectName: requiredFlag(ctx.args, "--object"),
|
|
988
|
+
emailFieldName: getFlag(ctx.args, "--email-field"),
|
|
989
|
+
entryIds: parseEntryIds(requiredFlag(ctx.args, "--entries")),
|
|
990
|
+
},
|
|
991
|
+
);
|
|
992
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (sub === "enrollments") {
|
|
996
|
+
const nested = ctx.args.shift();
|
|
997
|
+
if (nested !== "list") {
|
|
998
|
+
throw new EmailCliError("Usage: dench email sequence enrollments list");
|
|
999
|
+
}
|
|
1000
|
+
const limitRaw = getFlag(ctx.args, "--limit");
|
|
1001
|
+
const payload = await callQuery(
|
|
1002
|
+
ctx,
|
|
1003
|
+
"functions/emailSequences:listEnrollments",
|
|
1004
|
+
{
|
|
1005
|
+
sequenceId: requiredFlag(ctx.args, "--sequence"),
|
|
1006
|
+
paginationOpts: {
|
|
1007
|
+
numItems: limitRaw ? Number(limitRaw) : 50,
|
|
1008
|
+
cursor: null,
|
|
1009
|
+
},
|
|
1010
|
+
status: getFlag(ctx.args, "--status"),
|
|
1011
|
+
},
|
|
1012
|
+
);
|
|
1013
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (sub === "enrollment") {
|
|
1017
|
+
const nested = ctx.args.shift();
|
|
1018
|
+
const fn =
|
|
1019
|
+
nested === "pause"
|
|
1020
|
+
? "pauseEnrollment"
|
|
1021
|
+
: nested === "resume"
|
|
1022
|
+
? "resumeEnrollment"
|
|
1023
|
+
: nested === "stop"
|
|
1024
|
+
? "stopEnrollment"
|
|
1025
|
+
: null;
|
|
1026
|
+
if (!fn) {
|
|
1027
|
+
throw new EmailCliError(
|
|
1028
|
+
"Usage: dench email sequence enrollment pause|resume|stop --enrollment <id>",
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
const payload = await callMutation(ctx, `functions/emailSequences:${fn}`, {
|
|
1032
|
+
enrollmentId: requiredFlag(ctx.args, "--enrollment"),
|
|
1033
|
+
});
|
|
1034
|
+
out(ctx, payload, JSON.stringify(payload, null, 2));
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
throw new EmailCliError(
|
|
1038
|
+
"Usage: dench email sequence create|update|activate|deactivate|archive|list|status|steps|enroll|enroll-from-object|enrollments|enrollment",
|
|
738
1039
|
);
|
|
739
1040
|
}
|
package/lib/command-registry.ts
CHANGED
|
@@ -1096,7 +1096,7 @@ const rawApiOperations = [
|
|
|
1096
1096
|
id: "crm.templates.removeSampleData",
|
|
1097
1097
|
group: "crm",
|
|
1098
1098
|
summary:
|
|
1099
|
-
|
|
1099
|
+
'Delete a CRM template\'s sample rows (tagged "Sample"); schema, views, and automations stay.',
|
|
1100
1100
|
cli: "dench crm templates remove-sample-data",
|
|
1101
1101
|
method: "POST",
|
|
1102
1102
|
path: "/crm/templates/{templateId}/remove-sample-data",
|
|
@@ -1410,6 +1410,243 @@ const rawApiOperations = [
|
|
|
1410
1410
|
responseSchema: anyResponse,
|
|
1411
1411
|
backend: convex("mutation", "functions/emailCampaigns:cancelCampaign"),
|
|
1412
1412
|
}),
|
|
1413
|
+
op({
|
|
1414
|
+
id: "email.campaign.list",
|
|
1415
|
+
group: "email",
|
|
1416
|
+
summary:
|
|
1417
|
+
"List managed email campaigns (paginated, optional status filter).",
|
|
1418
|
+
cli: "dench email campaign list",
|
|
1419
|
+
method: "GET",
|
|
1420
|
+
path: "/email/campaigns",
|
|
1421
|
+
requestSchema: anyObject,
|
|
1422
|
+
responseSchema: anyResponse,
|
|
1423
|
+
backend: convex("query", "functions/emailCampaigns:listCampaigns"),
|
|
1424
|
+
}),
|
|
1425
|
+
op({
|
|
1426
|
+
id: "email.campaign.recipients.list",
|
|
1427
|
+
group: "email",
|
|
1428
|
+
summary:
|
|
1429
|
+
"List a campaign's recipients (paginated, optional status filter).",
|
|
1430
|
+
cli: "dench email campaign recipients list",
|
|
1431
|
+
method: "GET",
|
|
1432
|
+
path: "/email/campaigns/{campaignId}/recipients",
|
|
1433
|
+
requestSchema: anyObject,
|
|
1434
|
+
responseSchema: anyResponse,
|
|
1435
|
+
backend: convex("query", "functions/emailCampaigns:listRecipients"),
|
|
1436
|
+
}),
|
|
1437
|
+
op({
|
|
1438
|
+
id: "email.campaign.recipients.addFromObject",
|
|
1439
|
+
group: "email",
|
|
1440
|
+
summary:
|
|
1441
|
+
"Add campaign recipients from a CRM object: pick the object, the email field, and the entry ids.",
|
|
1442
|
+
cli: "dench email campaign recipients add-from-object",
|
|
1443
|
+
method: "POST",
|
|
1444
|
+
path: "/email/campaigns/{campaignId}/recipients/from-object",
|
|
1445
|
+
requestSchema: anyObject,
|
|
1446
|
+
responseSchema: anyResponse,
|
|
1447
|
+
backend: convex(
|
|
1448
|
+
"mutation",
|
|
1449
|
+
"functions/emailCampaigns:addRecipientsFromCrm",
|
|
1450
|
+
),
|
|
1451
|
+
}),
|
|
1452
|
+
|
|
1453
|
+
// Managed email sequences (multi-step drip cadences).
|
|
1454
|
+
op({
|
|
1455
|
+
id: "email.sequence.create",
|
|
1456
|
+
group: "email",
|
|
1457
|
+
summary:
|
|
1458
|
+
"Create a follow-up sequence; choose a verified sender and reply/stop behavior.",
|
|
1459
|
+
cli: "dench email sequence create",
|
|
1460
|
+
method: "POST",
|
|
1461
|
+
path: "/email/sequences",
|
|
1462
|
+
requestSchema: anyObject,
|
|
1463
|
+
responseSchema: anyResponse,
|
|
1464
|
+
backend: convex("mutation", "functions/emailSequences:createSequence"),
|
|
1465
|
+
}),
|
|
1466
|
+
op({
|
|
1467
|
+
id: "email.sequence.update",
|
|
1468
|
+
group: "email",
|
|
1469
|
+
summary: "Update a sequence's name, sender, or reply/stop settings.",
|
|
1470
|
+
cli: "dench email sequence update",
|
|
1471
|
+
method: "POST",
|
|
1472
|
+
path: "/email/sequences/{sequenceId}",
|
|
1473
|
+
requestSchema: anyObject,
|
|
1474
|
+
responseSchema: anyResponse,
|
|
1475
|
+
backend: convex("mutation", "functions/emailSequences:updateSequence"),
|
|
1476
|
+
}),
|
|
1477
|
+
op({
|
|
1478
|
+
id: "email.sequence.activate",
|
|
1479
|
+
group: "email",
|
|
1480
|
+
summary: "Activate a sequence so its enrollments begin sending.",
|
|
1481
|
+
cli: "dench email sequence activate",
|
|
1482
|
+
method: "POST",
|
|
1483
|
+
path: "/email/sequences/{sequenceId}/activate",
|
|
1484
|
+
requestSchema: anyObject,
|
|
1485
|
+
responseSchema: anyResponse,
|
|
1486
|
+
backend: {
|
|
1487
|
+
...convex("mutation", "functions/emailSequences:setSequenceActive"),
|
|
1488
|
+
fixedArgs: { active: true },
|
|
1489
|
+
},
|
|
1490
|
+
}),
|
|
1491
|
+
op({
|
|
1492
|
+
id: "email.sequence.deactivate",
|
|
1493
|
+
group: "email",
|
|
1494
|
+
summary: "Deactivate a sequence (pause sending, revert to draft).",
|
|
1495
|
+
cli: "dench email sequence deactivate",
|
|
1496
|
+
method: "POST",
|
|
1497
|
+
path: "/email/sequences/{sequenceId}/deactivate",
|
|
1498
|
+
requestSchema: anyObject,
|
|
1499
|
+
responseSchema: anyResponse,
|
|
1500
|
+
backend: {
|
|
1501
|
+
...convex("mutation", "functions/emailSequences:setSequenceActive"),
|
|
1502
|
+
fixedArgs: { active: false },
|
|
1503
|
+
},
|
|
1504
|
+
}),
|
|
1505
|
+
op({
|
|
1506
|
+
id: "email.sequence.archive",
|
|
1507
|
+
group: "email",
|
|
1508
|
+
summary: "Archive a sequence (stops all sending).",
|
|
1509
|
+
cli: "dench email sequence archive",
|
|
1510
|
+
method: "POST",
|
|
1511
|
+
path: "/email/sequences/{sequenceId}/archive",
|
|
1512
|
+
requestSchema: anyObject,
|
|
1513
|
+
responseSchema: anyResponse,
|
|
1514
|
+
backend: convex("mutation", "functions/emailSequences:archiveSequence"),
|
|
1515
|
+
}),
|
|
1516
|
+
op({
|
|
1517
|
+
id: "email.sequence.list",
|
|
1518
|
+
group: "email",
|
|
1519
|
+
summary: "List the workspace's follow-up sequences.",
|
|
1520
|
+
cli: "dench email sequence list",
|
|
1521
|
+
method: "GET",
|
|
1522
|
+
path: "/email/sequences",
|
|
1523
|
+
requestSchema: anyObject,
|
|
1524
|
+
responseSchema: anyResponse,
|
|
1525
|
+
backend: convex("query", "functions/emailSequences:listSequences"),
|
|
1526
|
+
}),
|
|
1527
|
+
op({
|
|
1528
|
+
id: "email.sequence.get",
|
|
1529
|
+
group: "email",
|
|
1530
|
+
summary: "Read a sequence with its ordered steps.",
|
|
1531
|
+
cli: "dench email sequence status",
|
|
1532
|
+
method: "GET",
|
|
1533
|
+
path: "/email/sequences/{sequenceId}",
|
|
1534
|
+
requestSchema: anyObject,
|
|
1535
|
+
responseSchema: anyResponse,
|
|
1536
|
+
backend: convex("query", "functions/emailSequences:getSequence"),
|
|
1537
|
+
}),
|
|
1538
|
+
op({
|
|
1539
|
+
id: "email.sequence.step.add",
|
|
1540
|
+
group: "email",
|
|
1541
|
+
summary: "Add a step (subject, body, and wait delay) to a sequence.",
|
|
1542
|
+
cli: "dench email sequence steps add",
|
|
1543
|
+
method: "POST",
|
|
1544
|
+
path: "/email/sequences/{sequenceId}/steps",
|
|
1545
|
+
requestSchema: anyObject,
|
|
1546
|
+
responseSchema: anyResponse,
|
|
1547
|
+
backend: convex("mutation", "functions/emailSequences:addStep"),
|
|
1548
|
+
}),
|
|
1549
|
+
op({
|
|
1550
|
+
id: "email.sequence.step.update",
|
|
1551
|
+
group: "email",
|
|
1552
|
+
summary: "Update a sequence step's subject, body, or delay.",
|
|
1553
|
+
cli: "dench email sequence steps update",
|
|
1554
|
+
method: "POST",
|
|
1555
|
+
path: "/email/sequences/steps/{stepId}",
|
|
1556
|
+
requestSchema: anyObject,
|
|
1557
|
+
responseSchema: anyResponse,
|
|
1558
|
+
backend: convex("mutation", "functions/emailSequences:updateStep"),
|
|
1559
|
+
}),
|
|
1560
|
+
op({
|
|
1561
|
+
id: "email.sequence.step.remove",
|
|
1562
|
+
group: "email",
|
|
1563
|
+
summary: "Remove a step from a sequence.",
|
|
1564
|
+
cli: "dench email sequence steps remove",
|
|
1565
|
+
method: "POST",
|
|
1566
|
+
path: "/email/sequences/steps/{stepId}/remove",
|
|
1567
|
+
requestSchema: anyObject,
|
|
1568
|
+
responseSchema: anyResponse,
|
|
1569
|
+
backend: convex("mutation", "functions/emailSequences:removeStep"),
|
|
1570
|
+
}),
|
|
1571
|
+
op({
|
|
1572
|
+
id: "email.sequence.step.reorder",
|
|
1573
|
+
group: "email",
|
|
1574
|
+
summary: "Reorder a sequence's steps.",
|
|
1575
|
+
cli: "dench email sequence steps reorder",
|
|
1576
|
+
method: "POST",
|
|
1577
|
+
path: "/email/sequences/{sequenceId}/steps/reorder",
|
|
1578
|
+
requestSchema: anyObject,
|
|
1579
|
+
responseSchema: anyResponse,
|
|
1580
|
+
backend: convex("mutation", "functions/emailSequences:reorderSteps"),
|
|
1581
|
+
}),
|
|
1582
|
+
op({
|
|
1583
|
+
id: "email.sequence.enroll",
|
|
1584
|
+
group: "email",
|
|
1585
|
+
summary: "Enroll explicit recipients into a sequence.",
|
|
1586
|
+
cli: "dench email sequence enroll",
|
|
1587
|
+
method: "POST",
|
|
1588
|
+
path: "/email/sequences/{sequenceId}/enroll",
|
|
1589
|
+
requestSchema: anyObject,
|
|
1590
|
+
responseSchema: anyResponse,
|
|
1591
|
+
backend: convex("mutation", "functions/emailSequences:enroll"),
|
|
1592
|
+
}),
|
|
1593
|
+
op({
|
|
1594
|
+
id: "email.sequence.enrollFromObject",
|
|
1595
|
+
group: "email",
|
|
1596
|
+
summary:
|
|
1597
|
+
"Enroll people from a CRM object: pick the object, the email field, and the entry ids.",
|
|
1598
|
+
cli: "dench email sequence enroll-from-object",
|
|
1599
|
+
method: "POST",
|
|
1600
|
+
path: "/email/sequences/{sequenceId}/enroll/from-object",
|
|
1601
|
+
requestSchema: anyObject,
|
|
1602
|
+
responseSchema: anyResponse,
|
|
1603
|
+
backend: convex("mutation", "functions/emailSequences:enrollFromCrm"),
|
|
1604
|
+
}),
|
|
1605
|
+
op({
|
|
1606
|
+
id: "email.sequence.enrollments.list",
|
|
1607
|
+
group: "email",
|
|
1608
|
+
summary:
|
|
1609
|
+
"List a sequence's enrollments (paginated, optional status filter).",
|
|
1610
|
+
cli: "dench email sequence enrollments list",
|
|
1611
|
+
method: "GET",
|
|
1612
|
+
path: "/email/sequences/{sequenceId}/enrollments",
|
|
1613
|
+
requestSchema: anyObject,
|
|
1614
|
+
responseSchema: anyResponse,
|
|
1615
|
+
backend: convex("query", "functions/emailSequences:listEnrollments"),
|
|
1616
|
+
}),
|
|
1617
|
+
op({
|
|
1618
|
+
id: "email.sequence.enrollment.pause",
|
|
1619
|
+
group: "email",
|
|
1620
|
+
summary: "Pause one enrollment.",
|
|
1621
|
+
cli: "dench email sequence enrollment pause",
|
|
1622
|
+
method: "POST",
|
|
1623
|
+
path: "/email/sequences/enrollments/{enrollmentId}/pause",
|
|
1624
|
+
requestSchema: anyObject,
|
|
1625
|
+
responseSchema: anyResponse,
|
|
1626
|
+
backend: convex("mutation", "functions/emailSequences:pauseEnrollment"),
|
|
1627
|
+
}),
|
|
1628
|
+
op({
|
|
1629
|
+
id: "email.sequence.enrollment.resume",
|
|
1630
|
+
group: "email",
|
|
1631
|
+
summary: "Resume one paused enrollment.",
|
|
1632
|
+
cli: "dench email sequence enrollment resume",
|
|
1633
|
+
method: "POST",
|
|
1634
|
+
path: "/email/sequences/enrollments/{enrollmentId}/resume",
|
|
1635
|
+
requestSchema: anyObject,
|
|
1636
|
+
responseSchema: anyResponse,
|
|
1637
|
+
backend: convex("mutation", "functions/emailSequences:resumeEnrollment"),
|
|
1638
|
+
}),
|
|
1639
|
+
op({
|
|
1640
|
+
id: "email.sequence.enrollment.stop",
|
|
1641
|
+
group: "email",
|
|
1642
|
+
summary: "Stop one enrollment (no further steps send).",
|
|
1643
|
+
cli: "dench email sequence enrollment stop",
|
|
1644
|
+
method: "POST",
|
|
1645
|
+
path: "/email/sequences/enrollments/{enrollmentId}/stop",
|
|
1646
|
+
requestSchema: anyObject,
|
|
1647
|
+
responseSchema: anyResponse,
|
|
1648
|
+
backend: convex("mutation", "functions/emailSequences:stopEnrollment"),
|
|
1649
|
+
}),
|
|
1413
1650
|
|
|
1414
1651
|
// Routines.
|
|
1415
1652
|
op({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dench.com/cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Dench agent workspace CLI. v2 unifies auth behind `dench signin`; the legacy `dench login` / `dench onboard` / `dench setup` / `dench what-can-i-do` / `dench register` commands now error with a redirect.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|