@brew.new/cli 0.6.0 → 0.9.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 +8 -3
- package/dist/bin.js +2215 -640
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -31,6 +31,14 @@ var CliApiError = class extends Error {
|
|
|
31
31
|
suggestion;
|
|
32
32
|
docs;
|
|
33
33
|
requestId;
|
|
34
|
+
/**
|
|
35
|
+
* The envelope's `details` object when the API sent one — for a
|
|
36
|
+
* trigger-fire `payload_mismatch` that is `{ errors[], warnings[],
|
|
37
|
+
* payloadSchema, … }`, naming every field the payload got wrong.
|
|
38
|
+
*/
|
|
39
|
+
details;
|
|
40
|
+
/** The parsed response body exactly as received (`undefined` if not JSON). */
|
|
41
|
+
body;
|
|
34
42
|
constructor(input) {
|
|
35
43
|
super(input.message);
|
|
36
44
|
this.status = input.status;
|
|
@@ -40,8 +48,38 @@ var CliApiError = class extends Error {
|
|
|
40
48
|
this.suggestion = input.suggestion;
|
|
41
49
|
this.docs = input.docs;
|
|
42
50
|
this.requestId = input.requestId;
|
|
51
|
+
this.details = input.details;
|
|
52
|
+
this.body = input.body;
|
|
43
53
|
}
|
|
44
54
|
};
|
|
55
|
+
function errorTypeForStatus(status) {
|
|
56
|
+
switch (status) {
|
|
57
|
+
case 401:
|
|
58
|
+
return "authentication_error";
|
|
59
|
+
case 402:
|
|
60
|
+
return "payment_required";
|
|
61
|
+
case 403:
|
|
62
|
+
return "authorization_error";
|
|
63
|
+
case 404:
|
|
64
|
+
return "not_found";
|
|
65
|
+
case 409:
|
|
66
|
+
return "conflict";
|
|
67
|
+
case 429:
|
|
68
|
+
return "rate_limit";
|
|
69
|
+
case 501:
|
|
70
|
+
return "not_implemented";
|
|
71
|
+
case 503:
|
|
72
|
+
return "service_unavailable";
|
|
73
|
+
default:
|
|
74
|
+
return status >= 400 && status < 500 ? "invalid_request" : "internal_error";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function suggestionForStatus(status) {
|
|
78
|
+
if (status === 408 || status === 429 || status >= 500) {
|
|
79
|
+
return "Retry the request. If it keeps failing, contact support.";
|
|
80
|
+
}
|
|
81
|
+
return "Fix the request before sending it again \u2014 the same request fails the same way. See `details` for the specifics when present.";
|
|
82
|
+
}
|
|
45
83
|
var ConfirmationRequiredError = class extends Error {
|
|
46
84
|
envelope;
|
|
47
85
|
constructor(envelope) {
|
|
@@ -67,6 +105,7 @@ function toExitCode(error) {
|
|
|
67
105
|
}
|
|
68
106
|
function toErrorEnvelope(error) {
|
|
69
107
|
if (error instanceof BrewApiError || error instanceof CliApiError) {
|
|
108
|
+
const details = readErrorDetails(error);
|
|
70
109
|
return {
|
|
71
110
|
code: error.code,
|
|
72
111
|
type: error.type,
|
|
@@ -75,6 +114,7 @@ function toErrorEnvelope(error) {
|
|
|
75
114
|
...error.suggestion ? { suggestion: error.suggestion } : {},
|
|
76
115
|
...error.docs ? { docs: error.docs } : {},
|
|
77
116
|
...error.requestId ? { requestId: error.requestId } : {},
|
|
117
|
+
...details === void 0 ? {} : { details },
|
|
78
118
|
status: error.status
|
|
79
119
|
};
|
|
80
120
|
}
|
|
@@ -134,7 +174,10 @@ function printError(ctx, error) {
|
|
|
134
174
|
`);
|
|
135
175
|
return;
|
|
136
176
|
}
|
|
137
|
-
const lines = [
|
|
177
|
+
const lines = [
|
|
178
|
+
`brew-cli: ${envelope.message}`,
|
|
179
|
+
...formatDetailLines(envelope.details)
|
|
180
|
+
];
|
|
138
181
|
if (envelope.suggestion) {
|
|
139
182
|
lines.push(envelope.suggestion);
|
|
140
183
|
}
|
|
@@ -147,6 +190,29 @@ function printError(ctx, error) {
|
|
|
147
190
|
ctx.io.stderr.write(`${lines.join("\n")}
|
|
148
191
|
`);
|
|
149
192
|
}
|
|
193
|
+
function readErrorDetails(error) {
|
|
194
|
+
const details = error.details;
|
|
195
|
+
return isRecord(details) ? details : void 0;
|
|
196
|
+
}
|
|
197
|
+
function formatDetailLines(details) {
|
|
198
|
+
if (details === void 0) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
const issues = details.errors;
|
|
202
|
+
if (Array.isArray(issues) && issues.length > 0 && issues.every(isIssue)) {
|
|
203
|
+
return issues.map((issue) => {
|
|
204
|
+
const types = typeof issue.expectedType === "string" ? typeof issue.actualType === "string" ? ` (expected ${issue.expectedType}, got ${issue.actualType})` : ` (expected ${issue.expectedType})` : "";
|
|
205
|
+
return ` - ${issue.field}: ${issue.message}${types}`;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return [`Details: ${JSON.stringify(details)}`];
|
|
209
|
+
}
|
|
210
|
+
function isIssue(value) {
|
|
211
|
+
return isRecord(value) && typeof value.field === "string" && typeof value.message === "string";
|
|
212
|
+
}
|
|
213
|
+
function isRecord(value) {
|
|
214
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
215
|
+
}
|
|
150
216
|
function apiErrorStatus(error) {
|
|
151
217
|
if (error instanceof BrewApiError || error instanceof CliApiError) {
|
|
152
218
|
return error.status;
|
|
@@ -215,7 +281,7 @@ function shellQuote(token) {
|
|
|
215
281
|
|
|
216
282
|
// src/version.ts
|
|
217
283
|
var CLI_NAME = "brew-cli";
|
|
218
|
-
var CLI_VERSION = "0.
|
|
284
|
+
var CLI_VERSION = "0.9.0" ;
|
|
219
285
|
var CONFIG_KEYS = ["apiKey", "brandId", "apiUrl"];
|
|
220
286
|
function isConfigKey(value) {
|
|
221
287
|
return CONFIG_KEYS.includes(value);
|
|
@@ -286,6 +352,7 @@ var ORG_LEVEL_PATH_PREFIXES = [
|
|
|
286
352
|
"/v1/brands",
|
|
287
353
|
"/v1/usage",
|
|
288
354
|
"/v1/templates",
|
|
355
|
+
"/v1/flows",
|
|
289
356
|
"/v1/health",
|
|
290
357
|
"/v1/help",
|
|
291
358
|
"/v1/llms.txt",
|
|
@@ -586,6 +653,10 @@ var IDEMPOTENCY_FLAG = {
|
|
|
586
653
|
flag: "--idempotency-key <key>",
|
|
587
654
|
summary: "Idempotency-Key for safe retries (auto-generated otherwise)"
|
|
588
655
|
};
|
|
656
|
+
var NON_REPLAYING_IDEMPOTENCY_FLAG = {
|
|
657
|
+
flag: "--idempotency-key <key>",
|
|
658
|
+
summary: "Accepted for compatibility only: this route never replays, so a retry runs again"
|
|
659
|
+
};
|
|
589
660
|
var INPUT_FLAG = {
|
|
590
661
|
flag: "--input <json>",
|
|
591
662
|
summary: "Full JSON request body, or - to read stdin (flags override it)"
|
|
@@ -668,12 +739,111 @@ function renderAutomationRows(rows) {
|
|
|
668
739
|
]);
|
|
669
740
|
}
|
|
670
741
|
|
|
742
|
+
// src/commands/sends/list.ts
|
|
743
|
+
var SEND_STATUS_SUMMARY = "scheduled | queued | running | paused | completed | partially_completed | failed | canceled";
|
|
744
|
+
var sendsListCommand = defineCommand({
|
|
745
|
+
path: ["sends", "list"],
|
|
746
|
+
summary: "List sends (the unit of delivery and analytics) with lifetime stats",
|
|
747
|
+
sdkMethod: "sends.list",
|
|
748
|
+
route: { method: "GET", path: "/v1/sends" },
|
|
749
|
+
commandClass: "read",
|
|
750
|
+
flags: [
|
|
751
|
+
{ flag: "--email <emailId>", summary: "Only sends of this design" },
|
|
752
|
+
{ flag: "--kind <kind>", summary: "campaign | automation" },
|
|
753
|
+
{ flag: "--automation <automationId>", summary: "Filter by automation" },
|
|
754
|
+
{
|
|
755
|
+
flag: "--automation-run <automationRunId>",
|
|
756
|
+
summary: "Deliveries of one automation run"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
flag: "--audience-run <audienceRunId>",
|
|
760
|
+
summary: "Deliveries of one manual-audience run"
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
flag: "--trigger-instance <triggerInstanceId>",
|
|
764
|
+
summary: "Deliveries started by one fired trigger instance"
|
|
765
|
+
},
|
|
766
|
+
{ flag: "--status <status>", summary: SEND_STATUS_SUMMARY },
|
|
767
|
+
{
|
|
768
|
+
flag: "--message-class <class>",
|
|
769
|
+
summary: "marketing | transactional"
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
flag: "--since <datetime>",
|
|
773
|
+
summary: "Inclusive lower bound on updatedAt (ISO-8601)"
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
flag: "--until <datetime>",
|
|
777
|
+
summary: "Inclusive upper bound on updatedAt (ISO-8601)"
|
|
778
|
+
},
|
|
779
|
+
LIMIT_FLAG,
|
|
780
|
+
CURSOR_FLAG,
|
|
781
|
+
ALL_FLAG,
|
|
782
|
+
INPUT_FLAG
|
|
783
|
+
],
|
|
784
|
+
examples: [
|
|
785
|
+
"brew-cli sends list --status completed",
|
|
786
|
+
"brew-cli sends list --email eml_1 --all --json",
|
|
787
|
+
"brew-cli sends list --automation-run arun_9f2kX"
|
|
788
|
+
],
|
|
789
|
+
run: async ({ ctx, flags }) => {
|
|
790
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
791
|
+
const input = mergeInput(base, {
|
|
792
|
+
emailId: flagString(flags.email),
|
|
793
|
+
kind: flagString(flags.kind),
|
|
794
|
+
automationId: flagString(flags.automation),
|
|
795
|
+
automationRunId: flagString(flags.automationRun),
|
|
796
|
+
audienceRunId: flagString(flags.audienceRun),
|
|
797
|
+
triggerInstanceId: flagString(flags.triggerInstance),
|
|
798
|
+
status: flagString(flags.status),
|
|
799
|
+
messageClass: flagString(flags.messageClass),
|
|
800
|
+
from: flagString(flags.since),
|
|
801
|
+
to: flagString(flags.until),
|
|
802
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
803
|
+
cursor: flagString(flags.cursor)
|
|
804
|
+
});
|
|
805
|
+
return await listSends(ctx, input, flags.all === true);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
async function listSends(ctx, input, followCursor) {
|
|
809
|
+
const sends = ctx.client().sends;
|
|
810
|
+
if (followCursor) {
|
|
811
|
+
const rows = await collectAll(
|
|
812
|
+
ctx,
|
|
813
|
+
(cursor) => sends.list(
|
|
814
|
+
asSdkInput({
|
|
815
|
+
...input,
|
|
816
|
+
...cursor === void 0 ? {} : { cursor }
|
|
817
|
+
})
|
|
818
|
+
)
|
|
819
|
+
);
|
|
820
|
+
return {
|
|
821
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
822
|
+
human: renderSends(rows)
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
const result = await sends.list(asSdkInput(input));
|
|
826
|
+
return { data: result, human: renderSends(result.data) };
|
|
827
|
+
}
|
|
828
|
+
function renderSends(rows) {
|
|
829
|
+
if (rows.length === 0) {
|
|
830
|
+
return "No sends found.";
|
|
831
|
+
}
|
|
832
|
+
return renderTable(rows, [
|
|
833
|
+
{ key: "sendId", header: "SEND" },
|
|
834
|
+
{ key: "kind", header: "KIND" },
|
|
835
|
+
{ key: "status", header: "STATUS" },
|
|
836
|
+
{ key: "subject", header: "SUBJECT" }
|
|
837
|
+
]);
|
|
838
|
+
}
|
|
839
|
+
|
|
671
840
|
// src/commands/analytics/campaigns.ts
|
|
672
841
|
var analyticsCampaignsCommand = defineCommand({
|
|
673
842
|
path: ["analytics", "campaigns"],
|
|
674
|
-
summary: "Lifetime per-campaign KPIs (
|
|
675
|
-
sdkMethod:
|
|
676
|
-
|
|
843
|
+
summary: "Lifetime per-campaign KPIs (`sends list --kind campaign`; stats ride each row)",
|
|
844
|
+
sdkMethod: null,
|
|
845
|
+
derivedFrom: "sends.list",
|
|
846
|
+
route: { method: "GET", path: "/v1/sends" },
|
|
677
847
|
commandClass: "read",
|
|
678
848
|
flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG, INPUT_FLAG],
|
|
679
849
|
examples: [
|
|
@@ -683,41 +853,207 @@ var analyticsCampaignsCommand = defineCommand({
|
|
|
683
853
|
run: async ({ ctx, flags }) => {
|
|
684
854
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
685
855
|
const input = mergeInput(base, {
|
|
856
|
+
kind: "campaign",
|
|
686
857
|
limit: flagInt(flags.limit, "--limit"),
|
|
687
858
|
cursor: flagString(flags.cursor)
|
|
688
859
|
});
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
860
|
+
return await listSends(ctx, input, flags.all === true);
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
// src/lib/raw-request.ts
|
|
865
|
+
async function rawRequest(ctx, request) {
|
|
866
|
+
const auth = resolveAuth({
|
|
867
|
+
globals: ctx.globals,
|
|
868
|
+
env: ctx.io.env,
|
|
869
|
+
...request.allowAnonymous === true ? { allowAnonymous: true } : {}
|
|
870
|
+
});
|
|
871
|
+
const hasBody = request.body !== void 0;
|
|
872
|
+
const idempotencyKey = resolveRawIdempotencyKey(
|
|
873
|
+
request.method,
|
|
874
|
+
request.idempotencyKey
|
|
875
|
+
);
|
|
876
|
+
const headers = buildRawHeaders({
|
|
877
|
+
auth,
|
|
878
|
+
path: request.path,
|
|
879
|
+
hasJsonBody: hasBody,
|
|
880
|
+
idempotencyKey
|
|
881
|
+
});
|
|
882
|
+
const url = new URL(`${auth.apiUrl}${request.path}`);
|
|
883
|
+
for (const [key, value] of Object.entries(request.query ?? {})) {
|
|
884
|
+
if (value !== void 0) {
|
|
885
|
+
url.searchParams.set(key, value);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const response = await fetch(url, {
|
|
889
|
+
method: request.method,
|
|
890
|
+
headers,
|
|
891
|
+
...hasBody ? { body: JSON.stringify(request.body) } : {},
|
|
892
|
+
...request.signal === void 0 ? {} : { signal: request.signal }
|
|
893
|
+
});
|
|
894
|
+
const text = await response.text();
|
|
895
|
+
const parsed = tryParseJson(text);
|
|
896
|
+
if (!response.ok) {
|
|
897
|
+
throw responseToApiError(response, parsed);
|
|
898
|
+
}
|
|
899
|
+
if (parsed === void 0) {
|
|
900
|
+
throw new CliApiError({
|
|
901
|
+
status: response.status,
|
|
902
|
+
code: "UNEXPECTED_RESPONSE",
|
|
903
|
+
type: "internal_error",
|
|
904
|
+
message: "The API returned a non-JSON success response."
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
return parsed;
|
|
908
|
+
}
|
|
909
|
+
function resolveRawIdempotencyKey(method, provided) {
|
|
910
|
+
if (provided !== void 0 && provided !== "") {
|
|
911
|
+
return provided;
|
|
912
|
+
}
|
|
913
|
+
return method === "POST" ? crypto.randomUUID() : void 0;
|
|
914
|
+
}
|
|
915
|
+
function buildRawHeaders(input) {
|
|
916
|
+
const headers = new Headers({
|
|
917
|
+
authorization: `Bearer ${input.auth.apiKey}`,
|
|
918
|
+
"user-agent": `${CLI_NAME}/${CLI_VERSION}`,
|
|
919
|
+
accept: "application/json, text/plain;q=0.9"
|
|
920
|
+
});
|
|
921
|
+
if (input.hasJsonBody) {
|
|
922
|
+
headers.set("content-type", "application/json");
|
|
923
|
+
}
|
|
924
|
+
if (input.auth.brandId !== void 0 && !isOrgLevelPath(input.path)) {
|
|
925
|
+
headers.set("x-brand-id", input.auth.brandId);
|
|
926
|
+
}
|
|
927
|
+
if (input.idempotencyKey !== void 0 && input.idempotencyKey !== "") {
|
|
928
|
+
headers.set("idempotency-key", input.idempotencyKey);
|
|
929
|
+
}
|
|
930
|
+
return headers;
|
|
931
|
+
}
|
|
932
|
+
function responseToApiError(response, parsed) {
|
|
933
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
934
|
+
const record = isRecord2(parsed) ? parsed : void 0;
|
|
935
|
+
const standard = record !== void 0 && isRecord2(record.error) ? record.error : void 0;
|
|
936
|
+
const envelope = standard ?? record;
|
|
937
|
+
const readField = (key) => {
|
|
938
|
+
const value = envelope?.[key];
|
|
939
|
+
return typeof value === "string" ? value : void 0;
|
|
940
|
+
};
|
|
941
|
+
const param = readField("param");
|
|
942
|
+
const suggestion = readField("suggestion") ?? (envelope === void 0 ? void 0 : suggestionForStatus(response.status));
|
|
943
|
+
const docs = readField("docs");
|
|
944
|
+
const details = isRecord2(envelope?.details) ? envelope.details : void 0;
|
|
945
|
+
return new CliApiError({
|
|
946
|
+
status: response.status,
|
|
947
|
+
code: readField("code") ?? "HTTP_ERROR",
|
|
948
|
+
type: readField("type") ?? errorTypeForStatus(response.status),
|
|
949
|
+
message: readField("message") ?? `Request failed with status ${response.status}`,
|
|
950
|
+
...param === void 0 ? {} : { param },
|
|
951
|
+
...suggestion === void 0 ? {} : { suggestion },
|
|
952
|
+
...docs === void 0 ? {} : { docs },
|
|
953
|
+
...requestId === void 0 ? {} : { requestId },
|
|
954
|
+
...details === void 0 ? {} : { details },
|
|
955
|
+
...parsed === void 0 ? {} : { body: parsed }
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
function isRecord2(value) {
|
|
959
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
960
|
+
}
|
|
961
|
+
function tryParseJson(text) {
|
|
962
|
+
try {
|
|
963
|
+
return JSON.parse(text);
|
|
964
|
+
} catch {
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/commands/analytics/event-counts.ts
|
|
969
|
+
var analyticsEventCountsCommand = defineCommand({
|
|
970
|
+
path: ["analytics", "event-counts"],
|
|
971
|
+
summary: "Count email events per field and/or period (clicks per link, events per day, unsubscribe reasons)",
|
|
972
|
+
sdkMethod: null,
|
|
973
|
+
isRawTransport: true,
|
|
974
|
+
route: { method: "GET", path: "/v1/analytics/events" },
|
|
975
|
+
commandClass: "read",
|
|
976
|
+
flags: [
|
|
977
|
+
{
|
|
978
|
+
flag: "--group-by <fields>",
|
|
979
|
+
summary: "One or two comma-separated fields: eventType, emailId, automationId, sendId, source, link, recipientDomain, unsubscribeReason"
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
flag: "--bucket <period>",
|
|
983
|
+
summary: "Count per UTC day, week (Monday start) or month"
|
|
984
|
+
},
|
|
985
|
+
{ flag: "--since <datetime>", summary: "Window start (ISO-8601)" },
|
|
986
|
+
{ flag: "--until <datetime>", summary: "Window end (ISO-8601)" },
|
|
987
|
+
{
|
|
988
|
+
flag: "--event-type <type>",
|
|
989
|
+
summary: "Only one email event type (e.g. clicked)"
|
|
990
|
+
},
|
|
991
|
+
{ flag: "--send-id <sendId>", summary: "Only one send" },
|
|
992
|
+
{ flag: "--email-id <emailId>", summary: "Only one design" },
|
|
993
|
+
{
|
|
994
|
+
flag: "--recipient <rules>",
|
|
995
|
+
summary: "CSV of recipient rules (max 10): an address, @domain, or substring; prefix ! to exclude"
|
|
996
|
+
},
|
|
997
|
+
INPUT_FLAG
|
|
998
|
+
],
|
|
999
|
+
examples: [
|
|
1000
|
+
"brew-cli analytics event-counts --send-id snd_123 --event-type clicked --group-by link",
|
|
1001
|
+
"brew-cli analytics event-counts --group-by eventType --bucket day",
|
|
1002
|
+
"brew-cli analytics event-counts --group-by unsubscribeReason --json"
|
|
1003
|
+
],
|
|
1004
|
+
run: async ({ ctx, flags }) => {
|
|
1005
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1006
|
+
const input = mergeInput(base, {
|
|
1007
|
+
groupBy: flagString(flags.groupBy),
|
|
1008
|
+
bucket: flagString(flags.bucket),
|
|
1009
|
+
from: flagString(flags.since),
|
|
1010
|
+
to: flagString(flags.until),
|
|
1011
|
+
eventType: flagString(flags.eventType),
|
|
1012
|
+
sendId: flagString(flags.sendId),
|
|
1013
|
+
emailId: flagString(flags.emailId),
|
|
1014
|
+
recipient: flagString(flags.recipient)
|
|
1015
|
+
});
|
|
1016
|
+
if (input.groupBy === void 0 && input.bucket === void 0) {
|
|
1017
|
+
throw new CliUsageError(
|
|
1018
|
+
"Pass --group-by, --bucket, or both (`analytics events` lists the rows)."
|
|
699
1019
|
);
|
|
700
|
-
return {
|
|
701
|
-
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
702
|
-
human: renderCampaigns(rows)
|
|
703
|
-
};
|
|
704
1020
|
}
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1021
|
+
const query = {};
|
|
1022
|
+
for (const [key, value] of Object.entries(input)) {
|
|
1023
|
+
if (key === "cursor" || key === "limit") {
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
query[key] = value === void 0 || value === null ? void 0 : Array.isArray(value) ? value.map(String).join(",") : String(value);
|
|
1027
|
+
}
|
|
1028
|
+
const body = await rawRequest(ctx, {
|
|
1029
|
+
method: "GET",
|
|
1030
|
+
path: "/v1/analytics/events",
|
|
1031
|
+
query
|
|
1032
|
+
});
|
|
1033
|
+
return { data: body, human: renderCounts(body) };
|
|
709
1034
|
}
|
|
710
1035
|
});
|
|
711
|
-
function
|
|
712
|
-
if (
|
|
713
|
-
return
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
{
|
|
718
|
-
|
|
719
|
-
|
|
1036
|
+
function renderCounts(body) {
|
|
1037
|
+
if (body.groups.length === 0) {
|
|
1038
|
+
return `No events counted (total ${body.count}).`;
|
|
1039
|
+
}
|
|
1040
|
+
const rows = body.groups.map((group) => ({
|
|
1041
|
+
group: Object.entries(group.key ?? {}).map(([field, value]) => `${field}=${String(value)}`).join(" "),
|
|
1042
|
+
...group.bucket === void 0 ? {} : { bucket: group.bucket },
|
|
1043
|
+
count: group.count
|
|
1044
|
+
}));
|
|
1045
|
+
const table = renderTable(rows, [
|
|
1046
|
+
{ key: "group", header: "GROUP" },
|
|
1047
|
+
...rows.some((row) => "bucket" in row) ? [{ key: "bucket", header: "PERIOD" }] : [],
|
|
1048
|
+
{ key: "count", header: "COUNT" }
|
|
720
1049
|
]);
|
|
1050
|
+
const footer = [
|
|
1051
|
+
`total ${body.count}`,
|
|
1052
|
+
body.otherCount > 0 ? `${body.otherCount} in unlisted groups` : "",
|
|
1053
|
+
body.truncated ? `truncated (counted from ${body.coveredFrom ?? "?"})` : ""
|
|
1054
|
+
].filter(Boolean).join(" \xB7 ");
|
|
1055
|
+
return `${table}
|
|
1056
|
+
${footer}`;
|
|
721
1057
|
}
|
|
722
1058
|
|
|
723
1059
|
// src/commands/analytics/events.ts
|
|
@@ -730,7 +1066,10 @@ var analyticsEventsCommand = defineCommand({
|
|
|
730
1066
|
flags: [
|
|
731
1067
|
{ flag: "--since <datetime>", summary: "Window start (ISO-8601)" },
|
|
732
1068
|
{ flag: "--until <datetime>", summary: "Window end (ISO-8601)" },
|
|
733
|
-
{
|
|
1069
|
+
{
|
|
1070
|
+
flag: "--recipient <rules>",
|
|
1071
|
+
summary: "CSV of recipient rules (max 10): an address, @domain, or substring; prefix ! to exclude"
|
|
1072
|
+
},
|
|
734
1073
|
{
|
|
735
1074
|
flag: "--event-type <type>",
|
|
736
1075
|
summary: "Filter by event type (e.g. opened, clicked)"
|
|
@@ -751,7 +1090,7 @@ var analyticsEventsCommand = defineCommand({
|
|
|
751
1090
|
const input = mergeInput(base, {
|
|
752
1091
|
from: flagString(flags.since),
|
|
753
1092
|
to: flagString(flags.until),
|
|
754
|
-
|
|
1093
|
+
recipient: flagString(flags.recipient),
|
|
755
1094
|
eventType: flagString(flags.eventType),
|
|
756
1095
|
automationId: flagString(flags.automation),
|
|
757
1096
|
sendId: flagString(flags.send),
|
|
@@ -852,10 +1191,10 @@ var analyticsOverviewCommand = defineCommand({
|
|
|
852
1191
|
// src/commands/analytics/sends/get.ts
|
|
853
1192
|
var analyticsSendsGetCommand = defineCommand({
|
|
854
1193
|
path: ["analytics", "sends", "get"],
|
|
855
|
-
summary: "Fetch one send by id",
|
|
1194
|
+
summary: "Fetch one send by id \u2014 the bare row (`sends get`)",
|
|
856
1195
|
sdkMethod: null,
|
|
857
|
-
derivedFrom: "
|
|
858
|
-
route: { method: "GET", path: "/v1/
|
|
1196
|
+
derivedFrom: "sends.get",
|
|
1197
|
+
route: { method: "GET", path: "/v1/sends/{sendId}" },
|
|
859
1198
|
commandClass: "read",
|
|
860
1199
|
args: [
|
|
861
1200
|
{
|
|
@@ -875,46 +1214,54 @@ var analyticsSendsGetCommand = defineCommand({
|
|
|
875
1214
|
"brew-cli analytics sends get snd_123 --include events"
|
|
876
1215
|
],
|
|
877
1216
|
run: async ({ ctx, args, flags }) => {
|
|
878
|
-
const sendId = args.sendId ?? "";
|
|
879
1217
|
const include = flagString(flags.include);
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
sendId,
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
const send = result.data[0];
|
|
887
|
-
if (send === void 0) {
|
|
888
|
-
throw new CliApiError({
|
|
889
|
-
status: 404,
|
|
890
|
-
code: "SEND_NOT_FOUND",
|
|
891
|
-
type: "not_found",
|
|
892
|
-
message: `No send found for ${sendId}`,
|
|
893
|
-
suggestion: "List sends with `brew-cli analytics sends list`."
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
return { data: send };
|
|
1218
|
+
return {
|
|
1219
|
+
data: await ctx.client().sends.get(
|
|
1220
|
+
args.sendId ?? "",
|
|
1221
|
+
include === void 0 ? void 0 : { include }
|
|
1222
|
+
)
|
|
1223
|
+
};
|
|
897
1224
|
}
|
|
898
1225
|
});
|
|
899
1226
|
|
|
1227
|
+
// src/lib/compat.ts
|
|
1228
|
+
function singleRowPage(row) {
|
|
1229
|
+
return { data: [row], pagination: { cursor: null, hasMore: false } };
|
|
1230
|
+
}
|
|
1231
|
+
function inputField(base, key) {
|
|
1232
|
+
if (base === null || typeof base !== "object") {
|
|
1233
|
+
return void 0;
|
|
1234
|
+
}
|
|
1235
|
+
const value = base[key];
|
|
1236
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1237
|
+
}
|
|
1238
|
+
function includeRidesDetailRead(getCommand, idFlag) {
|
|
1239
|
+
const pairing = idFlag === void 0 ? "" : `, or pair it with ${idFlag}`;
|
|
1240
|
+
return new CliUsageError(
|
|
1241
|
+
`--include rides the detail read: use \`brew-cli ${getCommand} <id> --include \u2026\`${pairing}.`
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
900
1245
|
// src/commands/analytics/sends/list.ts
|
|
901
1246
|
var analyticsSendsListCommand = defineCommand({
|
|
902
1247
|
path: ["analytics", "sends", "list"],
|
|
903
|
-
summary: "List campaign/automation sends with delivery stats",
|
|
904
|
-
sdkMethod:
|
|
905
|
-
|
|
1248
|
+
summary: "List campaign/automation sends with delivery stats (`sends list`)",
|
|
1249
|
+
sdkMethod: null,
|
|
1250
|
+
derivedFrom: "sends.list",
|
|
1251
|
+
route: { method: "GET", path: "/v1/sends" },
|
|
906
1252
|
commandClass: "read",
|
|
907
1253
|
flags: [
|
|
908
|
-
{ flag: "--send <sendId>", summary: "Fetch one send (single-row page)" },
|
|
909
|
-
{ flag: "--email <emailId>", summary: "Filter by email design" },
|
|
910
1254
|
{
|
|
911
|
-
flag: "--
|
|
912
|
-
summary: "
|
|
1255
|
+
flag: "--send <sendId>",
|
|
1256
|
+
summary: "0.6 shim: read ONE send as a single-row page (`sends get` is the real read)"
|
|
913
1257
|
},
|
|
914
1258
|
{
|
|
915
|
-
flag: "--
|
|
916
|
-
summary: "
|
|
1259
|
+
flag: "--include <tokens>",
|
|
1260
|
+
summary: "With --send only: detail includes (`events`)"
|
|
917
1261
|
},
|
|
1262
|
+
{ flag: "--email <emailId>", summary: "Filter by email design" },
|
|
1263
|
+
{ flag: "--kind <kind>", summary: "campaign | automation" },
|
|
1264
|
+
{ flag: "--status <status>", summary: SEND_STATUS_SUMMARY },
|
|
918
1265
|
{ flag: "--since <datetime>", summary: "Window start (ISO-8601)" },
|
|
919
1266
|
{ flag: "--until <datetime>", summary: "Window end (ISO-8601)" },
|
|
920
1267
|
LIMIT_FLAG,
|
|
@@ -923,108 +1270,86 @@ var analyticsSendsListCommand = defineCommand({
|
|
|
923
1270
|
INPUT_FLAG
|
|
924
1271
|
],
|
|
925
1272
|
examples: [
|
|
926
|
-
"brew-cli analytics sends list --status
|
|
927
|
-
"brew-cli analytics sends list --email
|
|
1273
|
+
"brew-cli analytics sends list --status completed",
|
|
1274
|
+
"brew-cli analytics sends list --email eml_1 --all --json"
|
|
928
1275
|
],
|
|
929
1276
|
run: async ({ ctx, flags }) => {
|
|
930
1277
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1278
|
+
const sendId = flagString(flags.send) ?? inputField(base, "sendId");
|
|
1279
|
+
const include = flagString(flags.include) ?? inputField(base, "include");
|
|
1280
|
+
if (sendId !== void 0) {
|
|
1281
|
+
const row = await ctx.client().sends.get(sendId, include === void 0 ? void 0 : { include });
|
|
1282
|
+
return { data: singleRowPage(row), human: renderSends([row]) };
|
|
1283
|
+
}
|
|
1284
|
+
if (include !== void 0) {
|
|
1285
|
+
throw includeRidesDetailRead("sends get", "--send");
|
|
1286
|
+
}
|
|
931
1287
|
const input = mergeInput(base, {
|
|
932
|
-
sendId: flagString(flags.send),
|
|
933
1288
|
emailId: flagString(flags.email),
|
|
934
|
-
|
|
1289
|
+
kind: flagString(flags.kind),
|
|
935
1290
|
status: flagString(flags.status),
|
|
936
1291
|
from: flagString(flags.since),
|
|
937
1292
|
to: flagString(flags.until),
|
|
938
1293
|
limit: flagInt(flags.limit, "--limit"),
|
|
939
1294
|
cursor: flagString(flags.cursor)
|
|
940
1295
|
});
|
|
941
|
-
|
|
942
|
-
if (flags.all === true) {
|
|
943
|
-
const rows = await collectAll(
|
|
944
|
-
ctx,
|
|
945
|
-
(cursor) => sends.list(
|
|
946
|
-
asSdkInput({
|
|
947
|
-
...input,
|
|
948
|
-
...cursor === void 0 ? {} : { cursor }
|
|
949
|
-
})
|
|
950
|
-
)
|
|
951
|
-
);
|
|
952
|
-
return {
|
|
953
|
-
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
954
|
-
human: renderSends(rows)
|
|
955
|
-
};
|
|
956
|
-
}
|
|
957
|
-
const result = await sends.list(asSdkInput(input));
|
|
958
|
-
return { data: result, human: renderSends(result.data) };
|
|
1296
|
+
return await listSends(ctx, input, flags.all === true);
|
|
959
1297
|
}
|
|
960
1298
|
});
|
|
961
|
-
function renderSends(rows) {
|
|
962
|
-
if (rows.length === 0) {
|
|
963
|
-
return "No sends found.";
|
|
964
|
-
}
|
|
965
|
-
return renderTable(rows, [
|
|
966
|
-
{ key: "sendId", header: "SEND" },
|
|
967
|
-
{ key: "kind", header: "KIND" },
|
|
968
|
-
{ key: "status", header: "STATUS" },
|
|
969
|
-
{ key: "subject", header: "SUBJECT" }
|
|
970
|
-
]);
|
|
971
|
-
}
|
|
972
1299
|
|
|
973
|
-
// src/commands/
|
|
974
|
-
var
|
|
975
|
-
path: ["
|
|
976
|
-
summary: "List fired-trigger instances (
|
|
977
|
-
sdkMethod: "
|
|
978
|
-
route: { method: "GET", path: "/v1/
|
|
1300
|
+
// src/commands/automations/trigger-instances/list.ts
|
|
1301
|
+
var automationsTriggerInstancesListCommand = defineCommand({
|
|
1302
|
+
path: ["automations", "trigger-instances", "list"],
|
|
1303
|
+
summary: "List fired-trigger instances (the inbound-fire audit log); each row carries a lifecycle `state`",
|
|
1304
|
+
sdkMethod: "automations.triggerInstances.list",
|
|
1305
|
+
route: { method: "GET", path: "/v1/automations/trigger-instances" },
|
|
979
1306
|
commandClass: "read",
|
|
980
1307
|
flags: [
|
|
981
1308
|
{
|
|
982
1309
|
flag: "--trigger <triggerEventId>",
|
|
983
1310
|
summary: "Filter by trigger event"
|
|
984
1311
|
},
|
|
985
|
-
{
|
|
986
|
-
flag: "--trigger-instance <triggerInstanceId>",
|
|
987
|
-
summary: "Fetch one instance (single-row page)"
|
|
988
|
-
},
|
|
989
1312
|
LIMIT_FLAG,
|
|
990
1313
|
CURSOR_FLAG,
|
|
991
1314
|
ALL_FLAG,
|
|
992
1315
|
INPUT_FLAG
|
|
993
1316
|
],
|
|
994
1317
|
examples: [
|
|
995
|
-
"brew-cli
|
|
996
|
-
"brew-cli
|
|
1318
|
+
"brew-cli automations trigger-instances list --trigger tri_signup",
|
|
1319
|
+
"brew-cli automations trigger-instances list --all --json"
|
|
997
1320
|
],
|
|
998
1321
|
run: async ({ ctx, flags }) => {
|
|
999
1322
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1000
1323
|
const input = mergeInput(base, {
|
|
1001
1324
|
triggerEventId: flagString(flags.trigger),
|
|
1002
|
-
triggerInstanceId: flagString(flags.triggerInstance),
|
|
1003
1325
|
limit: flagInt(flags.limit, "--limit"),
|
|
1004
1326
|
cursor: flagString(flags.cursor)
|
|
1005
1327
|
});
|
|
1006
|
-
|
|
1007
|
-
if (flags.all === true) {
|
|
1008
|
-
const rows = await collectAll(
|
|
1009
|
-
ctx,
|
|
1010
|
-
(cursor) => triggerInstances.list(
|
|
1011
|
-
asSdkInput({
|
|
1012
|
-
...input,
|
|
1013
|
-
...cursor === void 0 ? {} : { cursor }
|
|
1014
|
-
})
|
|
1015
|
-
)
|
|
1016
|
-
);
|
|
1017
|
-
return {
|
|
1018
|
-
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
1019
|
-
human: renderInstances(rows)
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
const result = await triggerInstances.list(
|
|
1023
|
-
asSdkInput(input)
|
|
1024
|
-
);
|
|
1025
|
-
return { data: result, human: renderInstances(result.data) };
|
|
1328
|
+
return await listTriggerInstances(ctx, input, flags.all === true);
|
|
1026
1329
|
}
|
|
1027
1330
|
});
|
|
1331
|
+
async function listTriggerInstances(ctx, input, followCursor) {
|
|
1332
|
+
const triggerInstances = ctx.client().automations.triggerInstances;
|
|
1333
|
+
if (followCursor) {
|
|
1334
|
+
const rows = await collectAll(
|
|
1335
|
+
ctx,
|
|
1336
|
+
(cursor) => triggerInstances.list(
|
|
1337
|
+
asSdkInput({
|
|
1338
|
+
...input,
|
|
1339
|
+
...cursor === void 0 ? {} : { cursor }
|
|
1340
|
+
})
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1343
|
+
return {
|
|
1344
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
1345
|
+
human: renderInstances(rows)
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
const result = await triggerInstances.list(
|
|
1349
|
+
asSdkInput(input)
|
|
1350
|
+
);
|
|
1351
|
+
return { data: result, human: renderInstances(result.data) };
|
|
1352
|
+
}
|
|
1028
1353
|
function renderInstances(rows) {
|
|
1029
1354
|
if (rows.length === 0) {
|
|
1030
1355
|
return "No trigger instances found.";
|
|
@@ -1037,102 +1362,47 @@ function renderInstances(rows) {
|
|
|
1037
1362
|
]);
|
|
1038
1363
|
}
|
|
1039
1364
|
|
|
1040
|
-
// src/
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1365
|
+
// src/commands/analytics/trigger-instances/list.ts
|
|
1366
|
+
var analyticsTriggerInstancesListCommand = defineCommand({
|
|
1367
|
+
path: ["analytics", "trigger-instances", "list"],
|
|
1368
|
+
summary: "List fired-trigger instances with their lifecycle `state` (`automations trigger-instances list`)",
|
|
1369
|
+
sdkMethod: null,
|
|
1370
|
+
derivedFrom: "automations.triggerInstances.list",
|
|
1371
|
+
route: { method: "GET", path: "/v1/automations/trigger-instances" },
|
|
1372
|
+
commandClass: "read",
|
|
1373
|
+
flags: [
|
|
1374
|
+
{
|
|
1375
|
+
flag: "--trigger <triggerEventId>",
|
|
1376
|
+
summary: "Filter by trigger event"
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
flag: "--trigger-instance <triggerInstanceId>",
|
|
1380
|
+
summary: "0.6 shim: read ONE instance as a single-row page (`automations trigger-instances get` is the real read)"
|
|
1381
|
+
},
|
|
1382
|
+
LIMIT_FLAG,
|
|
1383
|
+
CURSOR_FLAG,
|
|
1384
|
+
ALL_FLAG,
|
|
1385
|
+
INPUT_FLAG
|
|
1386
|
+
],
|
|
1387
|
+
examples: [
|
|
1388
|
+
"brew-cli analytics trigger-instances list --trigger tri_signup",
|
|
1389
|
+
"brew-cli analytics trigger-instances list --all --json"
|
|
1390
|
+
],
|
|
1391
|
+
run: async ({ ctx, flags }) => {
|
|
1392
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1393
|
+
const triggerInstanceId = flagString(flags.triggerInstance) ?? inputField(base, "triggerInstanceId");
|
|
1394
|
+
if (triggerInstanceId !== void 0) {
|
|
1395
|
+
const row = await ctx.client().automations.triggerInstances.get(triggerInstanceId);
|
|
1396
|
+
return { data: singleRowPage(row), human: renderInstances([row]) };
|
|
1062
1397
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
...hasBody ? { body: JSON.stringify(request.body) } : {},
|
|
1068
|
-
...request.signal === void 0 ? {} : { signal: request.signal }
|
|
1069
|
-
});
|
|
1070
|
-
const text = await response.text();
|
|
1071
|
-
const parsed = tryParseJson(text);
|
|
1072
|
-
if (!response.ok) {
|
|
1073
|
-
throw responseToApiError(response, parsed);
|
|
1074
|
-
}
|
|
1075
|
-
if (parsed === void 0) {
|
|
1076
|
-
throw new CliApiError({
|
|
1077
|
-
status: response.status,
|
|
1078
|
-
code: "UNEXPECTED_RESPONSE",
|
|
1079
|
-
type: "internal_error",
|
|
1080
|
-
message: "The API returned a non-JSON success response."
|
|
1398
|
+
const input = mergeInput(base, {
|
|
1399
|
+
triggerEventId: flagString(flags.trigger),
|
|
1400
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
1401
|
+
cursor: flagString(flags.cursor)
|
|
1081
1402
|
});
|
|
1403
|
+
return await listTriggerInstances(ctx, input, flags.all === true);
|
|
1082
1404
|
}
|
|
1083
|
-
|
|
1084
|
-
}
|
|
1085
|
-
function resolveRawIdempotencyKey(method, provided) {
|
|
1086
|
-
if (provided !== void 0 && provided !== "") {
|
|
1087
|
-
return provided;
|
|
1088
|
-
}
|
|
1089
|
-
return method === "POST" ? crypto.randomUUID() : void 0;
|
|
1090
|
-
}
|
|
1091
|
-
function buildRawHeaders(input) {
|
|
1092
|
-
const headers = new Headers({
|
|
1093
|
-
authorization: `Bearer ${input.auth.apiKey}`,
|
|
1094
|
-
"user-agent": `${CLI_NAME}/${CLI_VERSION}`,
|
|
1095
|
-
accept: "application/json, text/plain;q=0.9"
|
|
1096
|
-
});
|
|
1097
|
-
if (input.hasJsonBody) {
|
|
1098
|
-
headers.set("content-type", "application/json");
|
|
1099
|
-
}
|
|
1100
|
-
if (input.auth.brandId !== void 0 && !isOrgLevelPath(input.path)) {
|
|
1101
|
-
headers.set("x-brand-id", input.auth.brandId);
|
|
1102
|
-
}
|
|
1103
|
-
if (input.idempotencyKey !== void 0 && input.idempotencyKey !== "") {
|
|
1104
|
-
headers.set("idempotency-key", input.idempotencyKey);
|
|
1105
|
-
}
|
|
1106
|
-
return headers;
|
|
1107
|
-
}
|
|
1108
|
-
function responseToApiError(response, parsed) {
|
|
1109
|
-
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1110
|
-
const record = parsed !== null && typeof parsed === "object" ? parsed : void 0;
|
|
1111
|
-
const envelope = record !== void 0 && record.error !== null && typeof record.error === "object" ? record.error : record;
|
|
1112
|
-
const readField = (key) => {
|
|
1113
|
-
const value = envelope?.[key];
|
|
1114
|
-
return typeof value === "string" ? value : void 0;
|
|
1115
|
-
};
|
|
1116
|
-
const param = readField("param");
|
|
1117
|
-
const suggestion = readField("suggestion");
|
|
1118
|
-
const docs = readField("docs");
|
|
1119
|
-
return new CliApiError({
|
|
1120
|
-
status: response.status,
|
|
1121
|
-
code: readField("code") ?? "HTTP_ERROR",
|
|
1122
|
-
type: readField("type") ?? "internal_error",
|
|
1123
|
-
message: readField("message") ?? `Request failed with status ${response.status}`,
|
|
1124
|
-
...param === void 0 ? {} : { param },
|
|
1125
|
-
...suggestion === void 0 ? {} : { suggestion },
|
|
1126
|
-
...docs === void 0 ? {} : { docs },
|
|
1127
|
-
...requestId === void 0 ? {} : { requestId }
|
|
1128
|
-
});
|
|
1129
|
-
}
|
|
1130
|
-
function tryParseJson(text) {
|
|
1131
|
-
try {
|
|
1132
|
-
return JSON.parse(text);
|
|
1133
|
-
} catch {
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1405
|
+
});
|
|
1136
1406
|
|
|
1137
1407
|
// src/commands/api.ts
|
|
1138
1408
|
var METHODS = ["GET", "POST", "PATCH", "DELETE"];
|
|
@@ -1276,7 +1546,9 @@ var apiKeysCreateCommand = defineCommand({
|
|
|
1276
1546
|
summary: "Bind the NEW key to this brand id (omit for an organization-wide key); not the acting --brand"
|
|
1277
1547
|
},
|
|
1278
1548
|
INPUT_FLAG,
|
|
1279
|
-
|
|
1549
|
+
// The route never replays (a replay would disclose the plaintext key
|
|
1550
|
+
// again): a retry mints a second key, whatever the key says.
|
|
1551
|
+
NON_REPLAYING_IDEMPOTENCY_FLAG
|
|
1280
1552
|
],
|
|
1281
1553
|
examples: [
|
|
1282
1554
|
"brew-cli api-keys create --name CI --permissions emails domains",
|
|
@@ -1320,9 +1592,31 @@ var apiKeysListCommand = defineCommand({
|
|
|
1320
1592
|
sdkMethod: "apiKeys.list",
|
|
1321
1593
|
route: { method: "GET", path: "/v1/api-keys" },
|
|
1322
1594
|
commandClass: "read",
|
|
1595
|
+
flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG],
|
|
1323
1596
|
examples: ["brew-cli api-keys list", "brew-cli api-keys list --json"],
|
|
1324
|
-
run: async ({ ctx }) => {
|
|
1325
|
-
const
|
|
1597
|
+
run: async ({ ctx, flags }) => {
|
|
1598
|
+
const limit = flagInt(flags.limit, "--limit");
|
|
1599
|
+
const cursor = flagString(flags.cursor);
|
|
1600
|
+
if (limit === void 0 && cursor === void 0 && flags.all !== true) {
|
|
1601
|
+
const result2 = await ctx.client().apiKeys.list();
|
|
1602
|
+
return { data: result2, human: renderApiKeys(result2.data) };
|
|
1603
|
+
}
|
|
1604
|
+
const page = (after) => rawRequest(ctx, {
|
|
1605
|
+
method: "GET",
|
|
1606
|
+
path: "/v1/api-keys",
|
|
1607
|
+
query: {
|
|
1608
|
+
limit: limit === void 0 ? void 0 : String(limit),
|
|
1609
|
+
cursor: after
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
if (flags.all === true) {
|
|
1613
|
+
const rows = await collectAll(ctx, (next) => page(next ?? cursor));
|
|
1614
|
+
return {
|
|
1615
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
1616
|
+
human: renderApiKeys(rows)
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
const result = await page(cursor);
|
|
1326
1620
|
return { data: result, human: renderApiKeys(result.data) };
|
|
1327
1621
|
}
|
|
1328
1622
|
});
|
|
@@ -1479,10 +1773,9 @@ var audiencesFromEventsCommand = defineCommand({
|
|
|
1479
1773
|
// src/commands/audiences/get.ts
|
|
1480
1774
|
var audiencesGetCommand = defineCommand({
|
|
1481
1775
|
path: ["audiences", "get"],
|
|
1482
|
-
summary: "Fetch one audience segment by id",
|
|
1483
|
-
sdkMethod:
|
|
1484
|
-
|
|
1485
|
-
route: { method: "GET", path: "/v1/audiences" },
|
|
1776
|
+
summary: "Fetch one audience segment by id \u2014 the bare row",
|
|
1777
|
+
sdkMethod: "audiences.get",
|
|
1778
|
+
route: { method: "GET", path: "/v1/audiences/{audienceId}" },
|
|
1486
1779
|
commandClass: "read",
|
|
1487
1780
|
args: [
|
|
1488
1781
|
{ name: "audienceId", summary: "Audience id to fetch", isRequired: true }
|
|
@@ -1490,42 +1783,35 @@ var audiencesGetCommand = defineCommand({
|
|
|
1490
1783
|
flags: [
|
|
1491
1784
|
{
|
|
1492
1785
|
flag: "--include <tokens>",
|
|
1493
|
-
summary: "Comma-separated expansions: count"
|
|
1786
|
+
summary: "Comma-separated expansions: count, build"
|
|
1494
1787
|
}
|
|
1495
1788
|
],
|
|
1496
|
-
examples: [
|
|
1789
|
+
examples: [
|
|
1790
|
+
"brew-cli audiences get aud_3k9sQ",
|
|
1791
|
+
"brew-cli audiences get aud_3k9sQ --include count,build"
|
|
1792
|
+
],
|
|
1497
1793
|
run: async ({ ctx, args, flags }) => {
|
|
1498
|
-
const audienceId = args.audienceId ?? "";
|
|
1499
1794
|
const include = flagString(flags.include);
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
throw new CliApiError({
|
|
1507
|
-
status: 404,
|
|
1508
|
-
code: "AUDIENCE_NOT_FOUND",
|
|
1509
|
-
type: "not_found",
|
|
1510
|
-
message: `No audience found for ${audienceId}`,
|
|
1511
|
-
suggestion: "List audiences with `brew-cli audiences list`."
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1514
|
-
return { data: audience };
|
|
1795
|
+
return {
|
|
1796
|
+
data: await ctx.client().audiences.get(
|
|
1797
|
+
args.audienceId ?? "",
|
|
1798
|
+
include === void 0 ? void 0 : { include }
|
|
1799
|
+
)
|
|
1800
|
+
};
|
|
1515
1801
|
}
|
|
1516
1802
|
});
|
|
1517
1803
|
|
|
1518
1804
|
// src/commands/audiences/list.ts
|
|
1519
1805
|
var audiencesListCommand = defineCommand({
|
|
1520
1806
|
path: ["audiences", "list"],
|
|
1521
|
-
summary: "List audience segments",
|
|
1807
|
+
summary: "List audience segments; one segment is `audiences get`",
|
|
1522
1808
|
sdkMethod: "audiences.list",
|
|
1523
1809
|
route: { method: "GET", path: "/v1/audiences" },
|
|
1524
1810
|
commandClass: "read",
|
|
1525
1811
|
flags: [
|
|
1526
1812
|
{
|
|
1527
1813
|
flag: "--include <tokens>",
|
|
1528
|
-
summary: "
|
|
1814
|
+
summary: "0.6 flag: includes ride the detail read now (`audiences get --include count,build`)"
|
|
1529
1815
|
},
|
|
1530
1816
|
LIMIT_FLAG,
|
|
1531
1817
|
CURSOR_FLAG,
|
|
@@ -1534,13 +1820,15 @@ var audiencesListCommand = defineCommand({
|
|
|
1534
1820
|
],
|
|
1535
1821
|
examples: [
|
|
1536
1822
|
"brew-cli audiences list",
|
|
1537
|
-
"brew-cli audiences list --
|
|
1823
|
+
"brew-cli audiences list --limit 10",
|
|
1538
1824
|
"brew-cli audiences list --all --json"
|
|
1539
1825
|
],
|
|
1540
1826
|
run: async ({ ctx, flags }) => {
|
|
1541
1827
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1828
|
+
if ((flagString(flags.include) ?? inputField(base, "include")) !== void 0) {
|
|
1829
|
+
throw includeRidesDetailRead("audiences get");
|
|
1830
|
+
}
|
|
1542
1831
|
const input = mergeInput(base, {
|
|
1543
|
-
include: flagString(flags.include),
|
|
1544
1832
|
limit: flagInt(flags.limit, "--limit"),
|
|
1545
1833
|
cursor: flagString(flags.cursor)
|
|
1546
1834
|
});
|
|
@@ -1607,16 +1895,45 @@ var audiencesUpdateCommand = defineCommand({
|
|
|
1607
1895
|
}
|
|
1608
1896
|
});
|
|
1609
1897
|
|
|
1610
|
-
// src/commands/automations/audience-runs/
|
|
1611
|
-
var
|
|
1612
|
-
path: ["automations", "audience-runs", "
|
|
1613
|
-
summary: "
|
|
1614
|
-
sdkMethod: "automations.audienceRuns.
|
|
1898
|
+
// src/commands/automations/audience-runs/cancel.ts
|
|
1899
|
+
var automationsAudienceRunsCancelCommand = defineCommand({
|
|
1900
|
+
path: ["automations", "audience-runs", "cancel"],
|
|
1901
|
+
summary: "Cancel a manual-audience run for good \u2014 it can never be resumed",
|
|
1902
|
+
sdkMethod: "automations.audienceRuns.cancel",
|
|
1615
1903
|
route: {
|
|
1616
1904
|
method: "POST",
|
|
1617
|
-
path: "/v1/automations/audience-runs/{audienceRunId}/
|
|
1905
|
+
path: "/v1/automations/audience-runs/{audienceRunId}/cancel"
|
|
1618
1906
|
},
|
|
1619
1907
|
commandClass: "destructive",
|
|
1908
|
+
args: [
|
|
1909
|
+
{
|
|
1910
|
+
name: "audienceRunId",
|
|
1911
|
+
summary: "Audience run id to cancel",
|
|
1912
|
+
isRequired: true
|
|
1913
|
+
}
|
|
1914
|
+
],
|
|
1915
|
+
flags: [IDEMPOTENCY_FLAG],
|
|
1916
|
+
examples: ["brew-cli automations audience-runs cancel arun_01HZ --yes"],
|
|
1917
|
+
confirmSummary: ({ args }) => `Cancel audience run ${args.audienceRunId ?? ""} for good. Emails already sent are not recalled, and a canceled run cannot be resumed.`,
|
|
1918
|
+
run: async ({ ctx, args, flags }) => ({
|
|
1919
|
+
data: await ctx.client().automations.audienceRuns.cancel(
|
|
1920
|
+
args.audienceRunId ?? "",
|
|
1921
|
+
requestOptions(flags)
|
|
1922
|
+
)
|
|
1923
|
+
})
|
|
1924
|
+
});
|
|
1925
|
+
|
|
1926
|
+
// src/commands/automations/audience-runs/control.ts
|
|
1927
|
+
var automationsAudienceRunsControlCommand = defineCommand({
|
|
1928
|
+
path: ["automations", "audience-runs", "control"],
|
|
1929
|
+
summary: "Pause, resume, or cancel an in-flight manual-audience run (0.6 form of `audience-runs pause|resume|cancel`)",
|
|
1930
|
+
sdkMethod: null,
|
|
1931
|
+
derivedFrom: [
|
|
1932
|
+
"automations.audienceRuns.pause",
|
|
1933
|
+
"automations.audienceRuns.resume",
|
|
1934
|
+
"automations.audienceRuns.cancel"
|
|
1935
|
+
],
|
|
1936
|
+
commandClass: "destructive",
|
|
1620
1937
|
args: [
|
|
1621
1938
|
{
|
|
1622
1939
|
name: "audienceRunId",
|
|
@@ -1628,7 +1945,8 @@ var automationsAudienceRunsControlCommand = defineCommand({
|
|
|
1628
1945
|
{
|
|
1629
1946
|
flag: "--action <action>",
|
|
1630
1947
|
summary: "pause (resumable) | resume | cancel (final)"
|
|
1631
|
-
}
|
|
1948
|
+
},
|
|
1949
|
+
IDEMPOTENCY_FLAG
|
|
1632
1950
|
],
|
|
1633
1951
|
examples: [
|
|
1634
1952
|
"brew-cli automations audience-runs control arun_01HZ --action pause",
|
|
@@ -1637,58 +1955,182 @@ var automationsAudienceRunsControlCommand = defineCommand({
|
|
|
1637
1955
|
// Only cancel is irreversible; pause and resume proceed ungated.
|
|
1638
1956
|
confirmSummary: ({ args, flags }) => flagString(flags.action) === "cancel" ? `Cancel audience run ${args.audienceRunId ?? ""} for good. Emails already sent are not recalled, and a canceled run cannot be resumed.` : void 0,
|
|
1639
1957
|
run: async ({ ctx, args, flags }) => {
|
|
1640
|
-
const
|
|
1641
|
-
|
|
1642
|
-
|
|
1958
|
+
const audienceRuns = ctx.client().automations.audienceRuns;
|
|
1959
|
+
const audienceRunId = args.audienceRunId ?? "";
|
|
1960
|
+
const options = requestOptions(flags);
|
|
1961
|
+
switch (flagString(flags.action)) {
|
|
1962
|
+
case "pause":
|
|
1963
|
+
return { data: await audienceRuns.pause(audienceRunId, options) };
|
|
1964
|
+
case "resume":
|
|
1965
|
+
return { data: await audienceRuns.resume(audienceRunId, options) };
|
|
1966
|
+
case "cancel":
|
|
1967
|
+
return { data: await audienceRuns.cancel(audienceRunId, options) };
|
|
1968
|
+
default:
|
|
1969
|
+
throw new CliUsageError(
|
|
1970
|
+
"--action is required: pause, resume, or cancel."
|
|
1971
|
+
);
|
|
1643
1972
|
}
|
|
1644
|
-
return {
|
|
1645
|
-
data: await ctx.client().automations.audienceRuns.control(
|
|
1646
|
-
asSdkInput({
|
|
1647
|
-
audienceRunId: args.audienceRunId ?? "",
|
|
1648
|
-
action
|
|
1649
|
-
})
|
|
1650
|
-
)
|
|
1651
|
-
};
|
|
1652
1973
|
}
|
|
1653
1974
|
});
|
|
1654
1975
|
|
|
1976
|
+
// src/commands/automations/audience-runs/get.ts
|
|
1977
|
+
var automationsAudienceRunsGetCommand = defineCommand({
|
|
1978
|
+
path: ["automations", "audience-runs", "get"],
|
|
1979
|
+
summary: "Fetch one manual-audience run by id \u2014 the bare row",
|
|
1980
|
+
sdkMethod: "automations.audienceRuns.get",
|
|
1981
|
+
route: {
|
|
1982
|
+
method: "GET",
|
|
1983
|
+
path: "/v1/automations/audience-runs/{audienceRunId}"
|
|
1984
|
+
},
|
|
1985
|
+
commandClass: "read",
|
|
1986
|
+
args: [
|
|
1987
|
+
{
|
|
1988
|
+
name: "audienceRunId",
|
|
1989
|
+
summary: "Audience run id to fetch",
|
|
1990
|
+
isRequired: true
|
|
1991
|
+
}
|
|
1992
|
+
],
|
|
1993
|
+
examples: ["brew-cli automations audience-runs get arun_01HZ"],
|
|
1994
|
+
run: async ({ ctx, args }) => ({
|
|
1995
|
+
data: await ctx.client().automations.audienceRuns.get(args.audienceRunId ?? "")
|
|
1996
|
+
})
|
|
1997
|
+
});
|
|
1998
|
+
|
|
1655
1999
|
// src/commands/automations/audience-runs/list.ts
|
|
1656
2000
|
var automationsAudienceRunsListCommand = defineCommand({
|
|
1657
2001
|
path: ["automations", "audience-runs", "list"],
|
|
1658
|
-
summary: "List manual-audience runs
|
|
2002
|
+
summary: "List manual-audience runs, newest first; one run is `automations audience-runs get`",
|
|
1659
2003
|
sdkMethod: "automations.audienceRuns.list",
|
|
1660
2004
|
route: { method: "GET", path: "/v1/automations/audience-runs" },
|
|
1661
2005
|
commandClass: "read",
|
|
1662
|
-
// The spec paginates by --limit only: no cursor, and the response carries
|
|
1663
|
-
// no pagination envelope, so there is no --all here.
|
|
1664
2006
|
flags: [
|
|
1665
2007
|
{
|
|
1666
|
-
flag: "--
|
|
1667
|
-
summary: "
|
|
2008
|
+
flag: "--automation <automationId>",
|
|
2009
|
+
summary: "Only runs of this automation"
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
flag: "--automation-id <automationId>",
|
|
2013
|
+
summary: "0.6 alias of --automation"
|
|
2014
|
+
},
|
|
2015
|
+
{
|
|
2016
|
+
flag: "--audience-run-id <audienceRunId>",
|
|
2017
|
+
summary: "0.6 shim: read ONE run as a single-row page (`automations audience-runs get` is the real read)"
|
|
1668
2018
|
},
|
|
1669
2019
|
{
|
|
1670
|
-
flag: "--
|
|
1671
|
-
summary: "
|
|
2020
|
+
flag: "--status <status>",
|
|
2021
|
+
summary: "queued | scheduled | running | paused | completed | failed | canceled"
|
|
1672
2022
|
},
|
|
1673
|
-
|
|
2023
|
+
LIMIT_FLAG,
|
|
2024
|
+
CURSOR_FLAG,
|
|
2025
|
+
ALL_FLAG,
|
|
2026
|
+
INPUT_FLAG
|
|
1674
2027
|
],
|
|
1675
2028
|
examples: [
|
|
1676
2029
|
"brew-cli automations audience-runs list",
|
|
1677
|
-
"brew-cli automations audience-runs list --automation
|
|
2030
|
+
"brew-cli automations audience-runs list --automation am_123 --status running"
|
|
1678
2031
|
],
|
|
1679
2032
|
run: async ({ ctx, flags }) => {
|
|
1680
|
-
const
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
)
|
|
1689
|
-
|
|
2033
|
+
const audienceRuns = ctx.client().automations.audienceRuns;
|
|
2034
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
2035
|
+
const audienceRunId = flagString(flags.audienceRunId) ?? inputField(base, "audienceRunId");
|
|
2036
|
+
if (audienceRunId !== void 0) {
|
|
2037
|
+
const row = await audienceRuns.get(audienceRunId);
|
|
2038
|
+
return { data: singleRowPage(row), human: renderAudienceRuns([row]) };
|
|
2039
|
+
}
|
|
2040
|
+
const input = mergeInput(base, {
|
|
2041
|
+
automationId: flagString(flags.automation) ?? flagString(flags.automationId),
|
|
2042
|
+
status: flagString(flags.status),
|
|
2043
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
2044
|
+
cursor: flagString(flags.cursor)
|
|
2045
|
+
});
|
|
2046
|
+
if (flags.all === true) {
|
|
2047
|
+
const rows = await collectAll(
|
|
2048
|
+
ctx,
|
|
2049
|
+
(cursor) => audienceRuns.list(
|
|
2050
|
+
asSdkInput({
|
|
2051
|
+
...input,
|
|
2052
|
+
...cursor === void 0 ? {} : { cursor }
|
|
2053
|
+
})
|
|
2054
|
+
)
|
|
2055
|
+
);
|
|
2056
|
+
return {
|
|
2057
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
2058
|
+
human: renderAudienceRuns(rows)
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
const result = await audienceRuns.list(
|
|
2062
|
+
asSdkInput(input)
|
|
2063
|
+
);
|
|
2064
|
+
return { data: result, human: renderAudienceRuns(result.data) };
|
|
1690
2065
|
}
|
|
1691
2066
|
});
|
|
2067
|
+
function renderAudienceRuns(rows) {
|
|
2068
|
+
if (rows.length === 0) {
|
|
2069
|
+
return "No audience runs found.";
|
|
2070
|
+
}
|
|
2071
|
+
return renderTable(rows, [
|
|
2072
|
+
{ key: "audienceRunId", header: "AUDIENCE RUN" },
|
|
2073
|
+
{ key: "automationId", header: "AUTOMATION" },
|
|
2074
|
+
{ key: "status", header: "STATUS" },
|
|
2075
|
+
{ key: "totalRecipients", header: "RECIPIENTS" }
|
|
2076
|
+
]);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// src/commands/automations/audience-runs/pause.ts
|
|
2080
|
+
var automationsAudienceRunsPauseCommand = defineCommand({
|
|
2081
|
+
path: ["automations", "audience-runs", "pause"],
|
|
2082
|
+
summary: "Pause a running manual-audience run at its next step boundary (resumable)",
|
|
2083
|
+
sdkMethod: "automations.audienceRuns.pause",
|
|
2084
|
+
route: {
|
|
2085
|
+
method: "POST",
|
|
2086
|
+
path: "/v1/automations/audience-runs/{audienceRunId}/pause"
|
|
2087
|
+
},
|
|
2088
|
+
commandClass: "write",
|
|
2089
|
+
args: [
|
|
2090
|
+
{
|
|
2091
|
+
name: "audienceRunId",
|
|
2092
|
+
summary: "Audience run id to pause",
|
|
2093
|
+
isRequired: true
|
|
2094
|
+
}
|
|
2095
|
+
],
|
|
2096
|
+
flags: [IDEMPOTENCY_FLAG],
|
|
2097
|
+
examples: ["brew-cli automations audience-runs pause arun_01HZ"],
|
|
2098
|
+
run: async ({ ctx, args, flags }) => ({
|
|
2099
|
+
data: await ctx.client().automations.audienceRuns.pause(
|
|
2100
|
+
args.audienceRunId ?? "",
|
|
2101
|
+
requestOptions(flags)
|
|
2102
|
+
)
|
|
2103
|
+
})
|
|
2104
|
+
});
|
|
2105
|
+
|
|
2106
|
+
// src/commands/automations/audience-runs/resume.ts
|
|
2107
|
+
var automationsAudienceRunsResumeCommand = defineCommand({
|
|
2108
|
+
path: ["automations", "audience-runs", "resume"],
|
|
2109
|
+
summary: "Resume a paused manual-audience run, or restart a failed one from its first undelivered send",
|
|
2110
|
+
sdkMethod: "automations.audienceRuns.resume",
|
|
2111
|
+
route: {
|
|
2112
|
+
method: "POST",
|
|
2113
|
+
path: "/v1/automations/audience-runs/{audienceRunId}/resume"
|
|
2114
|
+
},
|
|
2115
|
+
commandClass: "write",
|
|
2116
|
+
args: [
|
|
2117
|
+
{
|
|
2118
|
+
name: "audienceRunId",
|
|
2119
|
+
summary: "Audience run id to resume",
|
|
2120
|
+
isRequired: true
|
|
2121
|
+
}
|
|
2122
|
+
],
|
|
2123
|
+
flags: [IDEMPOTENCY_FLAG],
|
|
2124
|
+
// `resumedFrom` on the response reports which case ran: `paused` or
|
|
2125
|
+
// `failed`. A failed restart never resends a step the failed run finished.
|
|
2126
|
+
examples: ["brew-cli automations audience-runs resume arun_01HZ"],
|
|
2127
|
+
run: async ({ ctx, args, flags }) => ({
|
|
2128
|
+
data: await ctx.client().automations.audienceRuns.resume(
|
|
2129
|
+
args.audienceRunId ?? "",
|
|
2130
|
+
requestOptions(flags)
|
|
2131
|
+
)
|
|
2132
|
+
})
|
|
2133
|
+
});
|
|
1692
2134
|
|
|
1693
2135
|
// src/commands/automations/create.ts
|
|
1694
2136
|
var automationsCreateCommand = defineCommand({
|
|
@@ -1755,10 +2197,9 @@ var automationsDeleteCommand = defineCommand({
|
|
|
1755
2197
|
// src/commands/automations/get.ts
|
|
1756
2198
|
var automationsGetCommand = defineCommand({
|
|
1757
2199
|
path: ["automations", "get"],
|
|
1758
|
-
summary: "Fetch one automation by id",
|
|
1759
|
-
sdkMethod:
|
|
1760
|
-
|
|
1761
|
-
route: { method: "GET", path: "/v1/automations" },
|
|
2200
|
+
summary: "Fetch one automation by id \u2014 the bare row, lean by default",
|
|
2201
|
+
sdkMethod: "automations.get",
|
|
2202
|
+
route: { method: "GET", path: "/v1/automations/{automationId}" },
|
|
1762
2203
|
commandClass: "read",
|
|
1763
2204
|
args: [
|
|
1764
2205
|
{
|
|
@@ -1770,7 +2211,7 @@ var automationsGetCommand = defineCommand({
|
|
|
1770
2211
|
flags: [
|
|
1771
2212
|
{
|
|
1772
2213
|
flag: "--include <tokens>",
|
|
1773
|
-
summary: "Comma-separated expansions: graph
|
|
2214
|
+
summary: "Comma-separated expansions: graph, versions"
|
|
1774
2215
|
}
|
|
1775
2216
|
],
|
|
1776
2217
|
examples: [
|
|
@@ -1778,23 +2219,13 @@ var automationsGetCommand = defineCommand({
|
|
|
1778
2219
|
"brew-cli automations get am_123 --include graph,versions"
|
|
1779
2220
|
],
|
|
1780
2221
|
run: async ({ ctx, args, flags }) => {
|
|
1781
|
-
const automationId = args.automationId ?? "";
|
|
1782
2222
|
const include = flagString(flags.include);
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
throw new CliApiError({
|
|
1790
|
-
status: 404,
|
|
1791
|
-
code: "AUTOMATION_NOT_FOUND",
|
|
1792
|
-
type: "not_found",
|
|
1793
|
-
message: `No automation found for ${automationId}`,
|
|
1794
|
-
suggestion: "List automations with `brew-cli automations list`."
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
1797
|
-
return { data: automation };
|
|
2223
|
+
return {
|
|
2224
|
+
data: await ctx.client().automations.get(
|
|
2225
|
+
args.automationId ?? "",
|
|
2226
|
+
include === void 0 ? void 0 : { include }
|
|
2227
|
+
)
|
|
2228
|
+
};
|
|
1798
2229
|
}
|
|
1799
2230
|
});
|
|
1800
2231
|
|
|
@@ -1918,7 +2349,7 @@ var automationsRunCommand = defineCommand({
|
|
|
1918
2349
|
],
|
|
1919
2350
|
confirmSummary: ({ args, flags }) => {
|
|
1920
2351
|
const inline = parseInlineInput(flags.input);
|
|
1921
|
-
if (flags.dryRun === true || inline?.
|
|
2352
|
+
if (flags.dryRun === true || inline?.dryRun === true) {
|
|
1922
2353
|
return;
|
|
1923
2354
|
}
|
|
1924
2355
|
const scheduleAt = flagString(flags.scheduleAt) ?? asString(inline?.scheduledAt);
|
|
@@ -1928,8 +2359,7 @@ var automationsRunCommand = defineCommand({
|
|
|
1928
2359
|
run: async ({ ctx, args, flags }) => {
|
|
1929
2360
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
1930
2361
|
const input = mergeInput(base, {
|
|
1931
|
-
|
|
1932
|
-
dry_run: flags.dryRun === true ? true : void 0,
|
|
2362
|
+
dryRun: flags.dryRun === true ? true : void 0,
|
|
1933
2363
|
scheduledAt: flagString(flags.scheduleAt)
|
|
1934
2364
|
});
|
|
1935
2365
|
return {
|
|
@@ -1957,22 +2387,89 @@ function asString(value) {
|
|
|
1957
2387
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1958
2388
|
}
|
|
1959
2389
|
|
|
2390
|
+
// src/commands/automations/runs/cancel.ts
|
|
2391
|
+
var automationsRunsCancelCommand = defineCommand({
|
|
2392
|
+
path: ["automations", "runs", "cancel"],
|
|
2393
|
+
summary: "Cancel one in-flight automation run (event execution or test run) \u2014 nothing further is sent, and it can never be resumed",
|
|
2394
|
+
sdkMethod: "automations.runs.cancel",
|
|
2395
|
+
route: {
|
|
2396
|
+
method: "POST",
|
|
2397
|
+
path: "/v1/automations/runs/{automationRunId}/cancel"
|
|
2398
|
+
},
|
|
2399
|
+
commandClass: "destructive",
|
|
2400
|
+
args: [
|
|
2401
|
+
{
|
|
2402
|
+
name: "automationRunId",
|
|
2403
|
+
summary: "Run id to cancel (from `automations runs list`, a test start, or a fire response)",
|
|
2404
|
+
isRequired: true
|
|
2405
|
+
}
|
|
2406
|
+
],
|
|
2407
|
+
flags: [
|
|
2408
|
+
{ flag: "--reason <text>", summary: "Operator note stored on the run" },
|
|
2409
|
+
IDEMPOTENCY_FLAG
|
|
2410
|
+
],
|
|
2411
|
+
examples: [
|
|
2412
|
+
'brew-cli automations runs cancel run_9f2kX --reason "wrong audience" --yes'
|
|
2413
|
+
],
|
|
2414
|
+
confirmSummary: ({ args }) => `Cancel automation run ${args.automationRunId ?? ""}. Nothing further is sent; emails already delivered are not recalled, and a canceled run can never be resumed.`,
|
|
2415
|
+
run: async ({ ctx, args, flags }) => {
|
|
2416
|
+
const reason = flagString(flags.reason);
|
|
2417
|
+
const options = {
|
|
2418
|
+
...requestOptions(flags),
|
|
2419
|
+
...reason === void 0 ? {} : { reason }
|
|
2420
|
+
};
|
|
2421
|
+
return {
|
|
2422
|
+
data: await ctx.client().automations.runs.cancel(
|
|
2423
|
+
args.automationRunId ?? "",
|
|
2424
|
+
Object.keys(options).length === 0 ? void 0 : options
|
|
2425
|
+
)
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2428
|
+
});
|
|
2429
|
+
|
|
2430
|
+
// src/commands/automations/runs/get.ts
|
|
2431
|
+
var automationsRunsGetCommand = defineCommand({
|
|
2432
|
+
path: ["automations", "runs", "get"],
|
|
2433
|
+
summary: "Fetch one automation run by id \u2014 the bare row",
|
|
2434
|
+
sdkMethod: "automations.runs.get",
|
|
2435
|
+
route: { method: "GET", path: "/v1/automations/runs/{automationRunId}" },
|
|
2436
|
+
commandClass: "read",
|
|
2437
|
+
args: [
|
|
2438
|
+
{
|
|
2439
|
+
name: "automationRunId",
|
|
2440
|
+
summary: "Run id (from `automations runs list`, a test start, or a fire)",
|
|
2441
|
+
isRequired: true
|
|
2442
|
+
}
|
|
2443
|
+
],
|
|
2444
|
+
flags: [
|
|
2445
|
+
{
|
|
2446
|
+
flag: "--include <tokens>",
|
|
2447
|
+
summary: "Expansions: logs (newest 100 per-node execution logs)"
|
|
2448
|
+
}
|
|
2449
|
+
],
|
|
2450
|
+
examples: [
|
|
2451
|
+
"brew-cli automations runs get run_9f2kX",
|
|
2452
|
+
"brew-cli automations runs get run_9f2kX --include logs"
|
|
2453
|
+
],
|
|
2454
|
+
run: async ({ ctx, args, flags }) => {
|
|
2455
|
+
const include = flagString(flags.include);
|
|
2456
|
+
return {
|
|
2457
|
+
data: await ctx.client().automations.runs.get(
|
|
2458
|
+
args.automationRunId ?? "",
|
|
2459
|
+
include === void 0 ? void 0 : { include }
|
|
2460
|
+
)
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
});
|
|
2464
|
+
|
|
1960
2465
|
// src/commands/automations/runs/list.ts
|
|
1961
2466
|
var automationsRunsListCommand = defineCommand({
|
|
1962
2467
|
path: ["automations", "runs", "list"],
|
|
1963
|
-
summary: "List automation runs (live + test history)",
|
|
2468
|
+
summary: "List automation runs (live + test history); one run is `automations runs get`",
|
|
1964
2469
|
sdkMethod: "automations.runs.list",
|
|
1965
2470
|
route: { method: "GET", path: "/v1/automations/runs" },
|
|
1966
2471
|
commandClass: "read",
|
|
1967
2472
|
flags: [
|
|
1968
|
-
{
|
|
1969
|
-
flag: "--run <automationRunId>",
|
|
1970
|
-
summary: "Fetch one run (single-row page)"
|
|
1971
|
-
},
|
|
1972
|
-
{
|
|
1973
|
-
flag: "--include <tokens>",
|
|
1974
|
-
summary: "Comma-separated expansions: logs"
|
|
1975
|
-
},
|
|
1976
2473
|
{ flag: "--automation <automationId>", summary: "Filter by automation" },
|
|
1977
2474
|
{
|
|
1978
2475
|
flag: "--trigger <triggerEventId>",
|
|
@@ -1982,12 +2479,23 @@ var automationsRunsListCommand = defineCommand({
|
|
|
1982
2479
|
flag: "--trigger-instance <triggerInstanceId>",
|
|
1983
2480
|
summary: "Filter by fired trigger instance"
|
|
1984
2481
|
},
|
|
1985
|
-
{ flag: "--recipient <email>", summary: "Filter by recipient email" },
|
|
1986
2482
|
{
|
|
1987
2483
|
flag: "--status <status>",
|
|
1988
|
-
summary: "
|
|
2484
|
+
summary: "queued | running | completed | failed | canceled"
|
|
1989
2485
|
},
|
|
1990
2486
|
{ flag: "--mode <mode>", summary: "live | test" },
|
|
2487
|
+
{
|
|
2488
|
+
flag: "--recipient <email>",
|
|
2489
|
+
summary: "Only runs for this recipient (case-insensitive match on the run row's recipientEmail)"
|
|
2490
|
+
},
|
|
2491
|
+
{
|
|
2492
|
+
flag: "--run <automationRunId>",
|
|
2493
|
+
summary: "0.6 shim: read ONE run as a single-row page (`automations runs get` is the real read)"
|
|
2494
|
+
},
|
|
2495
|
+
{
|
|
2496
|
+
flag: "--include <tokens>",
|
|
2497
|
+
summary: "With --run only: detail includes (`logs`)"
|
|
2498
|
+
},
|
|
1991
2499
|
{ flag: "--since <datetime>", summary: "Runs started at/after (ISO-8601)" },
|
|
1992
2500
|
{
|
|
1993
2501
|
flag: "--until <datetime>",
|
|
@@ -2000,13 +2508,24 @@ var automationsRunsListCommand = defineCommand({
|
|
|
2000
2508
|
],
|
|
2001
2509
|
examples: [
|
|
2002
2510
|
"brew-cli automations runs list --automation am_123 --status failed",
|
|
2003
|
-
"brew-cli automations runs list --
|
|
2511
|
+
"brew-cli automations runs list --trigger-instance tin_2f1c9d8a"
|
|
2004
2512
|
],
|
|
2005
2513
|
run: async ({ ctx, flags }) => {
|
|
2514
|
+
const runs = ctx.client().automations.runs;
|
|
2006
2515
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
2516
|
+
const runId = flagString(flags.run) ?? inputField(base, "automationRunId");
|
|
2517
|
+
const include = flagString(flags.include) ?? inputField(base, "include");
|
|
2518
|
+
if (runId !== void 0) {
|
|
2519
|
+
const row = await runs.get(
|
|
2520
|
+
runId,
|
|
2521
|
+
include === void 0 ? void 0 : { include }
|
|
2522
|
+
);
|
|
2523
|
+
return { data: singleRowPage(row), human: renderRuns([row]) };
|
|
2524
|
+
}
|
|
2525
|
+
if (include !== void 0) {
|
|
2526
|
+
throw includeRidesDetailRead("automations runs get", "--run");
|
|
2527
|
+
}
|
|
2007
2528
|
const input = mergeInput(base, {
|
|
2008
|
-
automationRunId: flagString(flags.run),
|
|
2009
|
-
include: flagString(flags.include),
|
|
2010
2529
|
automationId: flagString(flags.automation),
|
|
2011
2530
|
triggerEventId: flagString(flags.trigger),
|
|
2012
2531
|
triggerInstanceId: flagString(flags.triggerInstance),
|
|
@@ -2018,7 +2537,6 @@ var automationsRunsListCommand = defineCommand({
|
|
|
2018
2537
|
limit: flagInt(flags.limit, "--limit"),
|
|
2019
2538
|
cursor: flagString(flags.cursor)
|
|
2020
2539
|
});
|
|
2021
|
-
const runs = ctx.client().automations.runs;
|
|
2022
2540
|
if (flags.all === true) {
|
|
2023
2541
|
const rows = await collectAll(
|
|
2024
2542
|
ctx,
|
|
@@ -2083,6 +2601,29 @@ var automationsTestCommand = defineCommand({
|
|
|
2083
2601
|
}
|
|
2084
2602
|
});
|
|
2085
2603
|
|
|
2604
|
+
// src/commands/automations/trigger-instances/get.ts
|
|
2605
|
+
var automationsTriggerInstancesGetCommand = defineCommand({
|
|
2606
|
+
path: ["automations", "trigger-instances", "get"],
|
|
2607
|
+
summary: "Fetch one fired-trigger instance by id \u2014 the bare row, with its lifecycle `state` and the runs it started",
|
|
2608
|
+
sdkMethod: "automations.triggerInstances.get",
|
|
2609
|
+
route: {
|
|
2610
|
+
method: "GET",
|
|
2611
|
+
path: "/v1/automations/trigger-instances/{triggerInstanceId}"
|
|
2612
|
+
},
|
|
2613
|
+
commandClass: "read",
|
|
2614
|
+
args: [
|
|
2615
|
+
{
|
|
2616
|
+
name: "triggerInstanceId",
|
|
2617
|
+
summary: "Instance id returned by a fire, or by the instances list",
|
|
2618
|
+
isRequired: true
|
|
2619
|
+
}
|
|
2620
|
+
],
|
|
2621
|
+
examples: ["brew-cli automations trigger-instances get tin_2f1c9d8a"],
|
|
2622
|
+
run: async ({ ctx, args }) => ({
|
|
2623
|
+
data: await ctx.client().automations.triggerInstances.get(args.triggerInstanceId ?? "")
|
|
2624
|
+
})
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2086
2627
|
// src/commands/automations/triggers/contract.ts
|
|
2087
2628
|
var FORMAT_FLAG = {
|
|
2088
2629
|
flag: "--format <format>",
|
|
@@ -2355,17 +2896,52 @@ var automationsTriggersFireCommand = defineCommand({
|
|
|
2355
2896
|
}
|
|
2356
2897
|
});
|
|
2357
2898
|
|
|
2899
|
+
// src/commands/automations/triggers/get.ts
|
|
2900
|
+
var automationsTriggersGetCommand = defineCommand({
|
|
2901
|
+
path: ["automations", "triggers", "get"],
|
|
2902
|
+
summary: "Fetch one trigger by id \u2014 the bare row with its payload schema",
|
|
2903
|
+
sdkMethod: "automations.triggers.get",
|
|
2904
|
+
route: { method: "GET", path: "/v1/automations/triggers/{triggerEventId}" },
|
|
2905
|
+
commandClass: "read",
|
|
2906
|
+
args: [
|
|
2907
|
+
{
|
|
2908
|
+
name: "triggerEventId",
|
|
2909
|
+
summary: "Trigger id (tri_\u2026, or an integration composite id)",
|
|
2910
|
+
isRequired: true
|
|
2911
|
+
}
|
|
2912
|
+
],
|
|
2913
|
+
flags: [
|
|
2914
|
+
{
|
|
2915
|
+
flag: "--include <tokens>",
|
|
2916
|
+
summary: "Expansions: skill (a SKILL.md-shaped wiring brief)"
|
|
2917
|
+
}
|
|
2918
|
+
],
|
|
2919
|
+
examples: [
|
|
2920
|
+
"brew-cli automations triggers get tri_signup",
|
|
2921
|
+
"brew-cli automations triggers get tri_signup --include skill"
|
|
2922
|
+
],
|
|
2923
|
+
run: async ({ ctx, args, flags }) => {
|
|
2924
|
+
const include = flagString(flags.include);
|
|
2925
|
+
return {
|
|
2926
|
+
data: await ctx.client().automations.triggers.get(
|
|
2927
|
+
args.triggerEventId ?? "",
|
|
2928
|
+
include === void 0 ? void 0 : { include }
|
|
2929
|
+
)
|
|
2930
|
+
};
|
|
2931
|
+
}
|
|
2932
|
+
});
|
|
2933
|
+
|
|
2358
2934
|
// src/commands/automations/triggers/list.ts
|
|
2359
2935
|
var automationsTriggersListCommand = defineCommand({
|
|
2360
2936
|
path: ["automations", "triggers", "list"],
|
|
2361
|
-
summary: "List trigger events (their payload schemas drive fires)",
|
|
2937
|
+
summary: "List trigger events (their payload schemas drive fires); one trigger is `automations triggers get`",
|
|
2362
2938
|
sdkMethod: "automations.triggers.list",
|
|
2363
2939
|
route: { method: "GET", path: "/v1/automations/triggers" },
|
|
2364
2940
|
commandClass: "read",
|
|
2365
2941
|
flags: [
|
|
2366
2942
|
{
|
|
2367
2943
|
flag: "--trigger <triggerEventId>",
|
|
2368
|
-
summary: "
|
|
2944
|
+
summary: "0.6 shim: read ONE trigger as a single-row page (`automations triggers get` is the real read)"
|
|
2369
2945
|
},
|
|
2370
2946
|
LIMIT_FLAG,
|
|
2371
2947
|
CURSOR_FLAG,
|
|
@@ -2374,16 +2950,20 @@ var automationsTriggersListCommand = defineCommand({
|
|
|
2374
2950
|
],
|
|
2375
2951
|
examples: [
|
|
2376
2952
|
"brew-cli automations triggers list",
|
|
2377
|
-
"brew-cli automations triggers list --
|
|
2953
|
+
"brew-cli automations triggers list --all --json"
|
|
2378
2954
|
],
|
|
2379
2955
|
run: async ({ ctx, flags }) => {
|
|
2956
|
+
const triggers = ctx.client().automations.triggers;
|
|
2380
2957
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
2958
|
+
const triggerEventId = flagString(flags.trigger) ?? inputField(base, "triggerEventId");
|
|
2959
|
+
if (triggerEventId !== void 0) {
|
|
2960
|
+
const row = await triggers.get(triggerEventId);
|
|
2961
|
+
return { data: singleRowPage(row), human: renderTriggers([row]) };
|
|
2962
|
+
}
|
|
2381
2963
|
const input = mergeInput(base, {
|
|
2382
|
-
triggerEventId: flagString(flags.trigger),
|
|
2383
2964
|
limit: flagInt(flags.limit, "--limit"),
|
|
2384
2965
|
cursor: flagString(flags.cursor)
|
|
2385
2966
|
});
|
|
2386
|
-
const triggers = ctx.client().automations.triggers;
|
|
2387
2967
|
if (flags.all === true) {
|
|
2388
2968
|
const rows = await collectAll(
|
|
2389
2969
|
ctx,
|
|
@@ -2418,10 +2998,10 @@ function renderTriggers(rows) {
|
|
|
2418
2998
|
var automationsTriggersReadyCommand = defineCommand({
|
|
2419
2999
|
path: ["automations", "triggers", "ready"],
|
|
2420
3000
|
summary: "Preflight a trigger without firing: key + scope + permissions pass/fail, the payload contract, and what a fire would start",
|
|
2421
|
-
sdkMethod: "automations.triggers.
|
|
3001
|
+
sdkMethod: "automations.triggers.readiness",
|
|
2422
3002
|
route: {
|
|
2423
3003
|
method: "GET",
|
|
2424
|
-
path: "/v1/automations/triggers/{triggerEventId}/
|
|
3004
|
+
path: "/v1/automations/triggers/{triggerEventId}/readiness"
|
|
2425
3005
|
},
|
|
2426
3006
|
commandClass: "read",
|
|
2427
3007
|
args: [
|
|
@@ -2432,17 +3012,13 @@ var automationsTriggersReadyCommand = defineCommand({
|
|
|
2432
3012
|
}
|
|
2433
3013
|
],
|
|
2434
3014
|
examples: ["brew-cli automations triggers ready tri_signup"],
|
|
2435
|
-
// 200 `
|
|
2436
|
-
// trigger
|
|
2437
|
-
// logged but start no runs until a wired
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
})
|
|
2443
|
-
);
|
|
2444
|
-
return { data: result };
|
|
2445
|
-
}
|
|
3015
|
+
// 200 `ready: true` means the exact credential in use can fire this
|
|
3016
|
+
// trigger. A `NO_PUBLISHED_AUTOMATION` blocker with `ready: false` means
|
|
3017
|
+
// fires are accepted and logged but start no runs until a wired
|
|
3018
|
+
// automation is published — still a 200, because a probe has to say why.
|
|
3019
|
+
run: async ({ ctx, args }) => ({
|
|
3020
|
+
data: await ctx.client().automations.triggers.readiness(args.triggerEventId ?? "")
|
|
3021
|
+
})
|
|
2446
3022
|
});
|
|
2447
3023
|
|
|
2448
3024
|
// src/commands/automations/triggers/update.ts
|
|
@@ -2581,21 +3157,37 @@ var brandGetCommand = defineCommand({
|
|
|
2581
3157
|
});
|
|
2582
3158
|
|
|
2583
3159
|
// src/commands/brand/get-images.ts
|
|
3160
|
+
var RETIRED_FILTERS = {
|
|
3161
|
+
type: "--type (type) was retired by the API: use --kind logo|brand|generated.",
|
|
3162
|
+
aspectRatio: "--aspect-ratio (aspectRatio) was retired by the API: every image carries its width and height."
|
|
3163
|
+
};
|
|
2584
3164
|
var brandGetImagesCommand = defineCommand({
|
|
2585
3165
|
path: ["brand", "get-images"],
|
|
2586
|
-
summary: "Browse or semantically search the brand's
|
|
2587
|
-
sdkMethod:
|
|
3166
|
+
summary: "Browse or semantically search the brand's assets (logos, brand images, images made with Brew)",
|
|
3167
|
+
sdkMethod: null,
|
|
3168
|
+
isRawTransport: true,
|
|
2588
3169
|
route: { method: "GET", path: "/v1/brand/images" },
|
|
2589
3170
|
commandClass: "read",
|
|
2590
3171
|
flags: [
|
|
2591
3172
|
{
|
|
2592
3173
|
flag: "--query <text>",
|
|
2593
|
-
summary: "Semantic search over
|
|
3174
|
+
summary: "Semantic search over what the images show (1 credit per new search; logos are not searchable)"
|
|
3175
|
+
},
|
|
3176
|
+
{
|
|
3177
|
+
flag: "--kind <kind>",
|
|
3178
|
+
summary: "logo, brand (from the site or uploaded) or generated"
|
|
3179
|
+
},
|
|
3180
|
+
{
|
|
3181
|
+
flag: "--sort <order>",
|
|
3182
|
+
summary: "Browse order: newest (default) or oldest; ignored by --query"
|
|
3183
|
+
},
|
|
3184
|
+
{
|
|
3185
|
+
flag: "--type <type>",
|
|
3186
|
+
summary: "Retired by the API: use --kind"
|
|
2594
3187
|
},
|
|
2595
|
-
{ flag: "--type <type>", summary: "Filter by image category" },
|
|
2596
3188
|
{
|
|
2597
3189
|
flag: "--aspect-ratio <ratio>",
|
|
2598
|
-
summary: "
|
|
3190
|
+
summary: "Retired by the API: rows carry width and height instead of a shape filter"
|
|
2599
3191
|
},
|
|
2600
3192
|
LIMIT_FLAG,
|
|
2601
3193
|
CURSOR_FLAG,
|
|
@@ -2604,48 +3196,68 @@ var brandGetImagesCommand = defineCommand({
|
|
|
2604
3196
|
],
|
|
2605
3197
|
examples: [
|
|
2606
3198
|
"brew-cli brand get-images",
|
|
2607
|
-
|
|
3199
|
+
"brew-cli brand get-images --kind generated --sort oldest --all",
|
|
3200
|
+
'brew-cli brand get-images --query "team photo" --kind brand'
|
|
2608
3201
|
],
|
|
2609
3202
|
run: async ({ ctx, flags }) => {
|
|
2610
3203
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
2611
3204
|
const input = mergeInput(base, {
|
|
2612
3205
|
q: flagString(flags.query),
|
|
2613
|
-
|
|
2614
|
-
|
|
3206
|
+
kind: flagString(flags.kind),
|
|
3207
|
+
sort: flagString(flags.sort),
|
|
2615
3208
|
limit: flagInt(flags.limit, "--limit"),
|
|
2616
|
-
cursor: flagString(flags.cursor)
|
|
3209
|
+
cursor: flagString(flags.cursor),
|
|
3210
|
+
type: flagString(flags.type),
|
|
3211
|
+
aspectRatio: flagString(flags.aspectRatio)
|
|
3212
|
+
});
|
|
3213
|
+
for (const [key, message] of Object.entries(RETIRED_FILTERS)) {
|
|
3214
|
+
if (input[key] !== void 0) {
|
|
3215
|
+
throw new CliUsageError(message);
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
const page = (cursor) => rawRequest(ctx, {
|
|
3219
|
+
method: "GET",
|
|
3220
|
+
path: "/v1/brand/images",
|
|
3221
|
+
query: toQuery(cursor === void 0 ? input : { ...input, cursor })
|
|
2617
3222
|
});
|
|
2618
|
-
const brand = ctx.client().brand;
|
|
2619
3223
|
if (flags.all === true) {
|
|
2620
|
-
const rows = await collectAll(
|
|
2621
|
-
ctx,
|
|
2622
|
-
(cursor) => brand.getImages(
|
|
2623
|
-
asSdkInput({
|
|
2624
|
-
...input,
|
|
2625
|
-
...cursor === void 0 ? {} : { cursor }
|
|
2626
|
-
})
|
|
2627
|
-
)
|
|
2628
|
-
);
|
|
3224
|
+
const rows = await collectAll(ctx, page);
|
|
2629
3225
|
return {
|
|
2630
3226
|
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
2631
|
-
human:
|
|
3227
|
+
human: renderAssets(rows)
|
|
2632
3228
|
};
|
|
2633
3229
|
}
|
|
2634
|
-
const result = await
|
|
2635
|
-
|
|
2636
|
-
);
|
|
2637
|
-
return { data: result, human: renderImages(result.data) };
|
|
3230
|
+
const result = await page(void 0);
|
|
3231
|
+
return { data: result, human: renderAssets(result.data) };
|
|
2638
3232
|
}
|
|
2639
3233
|
});
|
|
2640
|
-
function
|
|
2641
|
-
|
|
2642
|
-
|
|
3234
|
+
function toQuery(input) {
|
|
3235
|
+
const query = {};
|
|
3236
|
+
for (const [key, value] of Object.entries(input)) {
|
|
3237
|
+
query[key] = value === void 0 || value === null ? void 0 : String(value);
|
|
2643
3238
|
}
|
|
2644
|
-
return
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
3239
|
+
return query;
|
|
3240
|
+
}
|
|
3241
|
+
function renderAssets(rows) {
|
|
3242
|
+
if (rows.length === 0) {
|
|
3243
|
+
return "No brand assets found.";
|
|
3244
|
+
}
|
|
3245
|
+
return renderTable(
|
|
3246
|
+
rows.map((row) => ({
|
|
3247
|
+
assetId: row.assetId,
|
|
3248
|
+
kind: row.kind,
|
|
3249
|
+
url: row.url,
|
|
3250
|
+
size: row.width !== void 0 && row.height !== void 0 ? `${row.width}x${row.height}` : "",
|
|
3251
|
+
added: row.addedAt ?? ""
|
|
3252
|
+
})),
|
|
3253
|
+
[
|
|
3254
|
+
{ key: "assetId", header: "ASSET ID" },
|
|
3255
|
+
{ key: "kind", header: "KIND" },
|
|
3256
|
+
{ key: "url", header: "URL" },
|
|
3257
|
+
{ key: "size", header: "SIZE" },
|
|
3258
|
+
{ key: "added", header: "ADDED" }
|
|
3259
|
+
]
|
|
3260
|
+
);
|
|
2649
3261
|
}
|
|
2650
3262
|
|
|
2651
3263
|
// src/commands/brand/update.ts
|
|
@@ -2747,33 +3359,66 @@ var brandsListCommand = defineCommand({
|
|
|
2747
3359
|
sdkMethod: "brands.list",
|
|
2748
3360
|
route: { method: "GET", path: "/v1/brands" },
|
|
2749
3361
|
commandClass: "read",
|
|
2750
|
-
|
|
2751
|
-
run: async ({ ctx }) => ({
|
|
2752
|
-
data: await ctx.client().brands.list()
|
|
2753
|
-
})
|
|
2754
|
-
});
|
|
2755
|
-
|
|
2756
|
-
// src/commands/chats/get.ts
|
|
2757
|
-
var chatsGetCommand = defineCommand({
|
|
2758
|
-
path: ["chats", "get"],
|
|
2759
|
-
summary: "Brand-scoped digest of a Brew chat (artifacts + transcript tail)",
|
|
2760
|
-
sdkMethod: "chats.get",
|
|
2761
|
-
route: { method: "GET", path: "/v1/chats/{chatId}" },
|
|
2762
|
-
commandClass: "read",
|
|
2763
|
-
args: [
|
|
3362
|
+
flags: [
|
|
2764
3363
|
{
|
|
2765
|
-
|
|
2766
|
-
summary: "
|
|
2767
|
-
|
|
2768
|
-
|
|
3364
|
+
flag: "--status <status>",
|
|
3365
|
+
summary: "Only brands in one lifecycle state: extracting | completed | failed | deleting"
|
|
3366
|
+
},
|
|
3367
|
+
LIMIT_FLAG,
|
|
3368
|
+
CURSOR_FLAG,
|
|
3369
|
+
ALL_FLAG
|
|
2769
3370
|
],
|
|
2770
|
-
examples: [
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
3371
|
+
examples: [
|
|
3372
|
+
"brew-cli brands list --json",
|
|
3373
|
+
"brew-cli brands list --status completed",
|
|
3374
|
+
"brew-cli brands list --all --json"
|
|
3375
|
+
],
|
|
3376
|
+
run: async ({ ctx, flags }) => {
|
|
3377
|
+
const input = {
|
|
3378
|
+
status: flagString(flags.status),
|
|
3379
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
3380
|
+
cursor: flagString(flags.cursor)
|
|
3381
|
+
};
|
|
3382
|
+
const brands = ctx.client().brands;
|
|
3383
|
+
if (flags.all === true) {
|
|
3384
|
+
const rows = await collectAll(
|
|
3385
|
+
ctx,
|
|
3386
|
+
(cursor) => brands.list(
|
|
3387
|
+
asSdkInput({
|
|
3388
|
+
...input,
|
|
3389
|
+
...cursor === void 0 ? {} : { cursor }
|
|
3390
|
+
})
|
|
3391
|
+
)
|
|
3392
|
+
);
|
|
3393
|
+
return {
|
|
3394
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } }
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
return { data: await brands.list(asSdkInput(input)) };
|
|
3398
|
+
}
|
|
3399
|
+
});
|
|
3400
|
+
|
|
3401
|
+
// src/commands/chats/get.ts
|
|
3402
|
+
var chatsGetCommand = defineCommand({
|
|
3403
|
+
path: ["chats", "get"],
|
|
3404
|
+
summary: "Brand-scoped digest of a Brew chat (artifacts + transcript tail)",
|
|
3405
|
+
sdkMethod: "chats.get",
|
|
3406
|
+
route: { method: "GET", path: "/v1/chats/{chatId}" },
|
|
3407
|
+
commandClass: "read",
|
|
3408
|
+
args: [
|
|
3409
|
+
{
|
|
3410
|
+
name: "chatId",
|
|
3411
|
+
summary: "Brew chat id (from the chat URL / the app)",
|
|
3412
|
+
isRequired: true
|
|
3413
|
+
}
|
|
3414
|
+
],
|
|
3415
|
+
examples: ["brew-cli chats get Hk2mZ8t9QbY3sW1vR0pLd"],
|
|
3416
|
+
run: async ({ ctx, args }) => ({
|
|
3417
|
+
data: await ctx.client().chats.get(args.chatId ?? "")
|
|
3418
|
+
})
|
|
3419
|
+
});
|
|
3420
|
+
|
|
3421
|
+
// src/commands/config.ts
|
|
2777
3422
|
var SETTABLE_KEYS = ["brandId", "apiUrl"];
|
|
2778
3423
|
var configListCommand = defineCommand({
|
|
2779
3424
|
path: ["config", "list"],
|
|
@@ -2962,77 +3607,161 @@ function inlineEmailCount(input) {
|
|
|
2962
3607
|
// src/commands/contacts/get.ts
|
|
2963
3608
|
var contactsGetCommand = defineCommand({
|
|
2964
3609
|
path: ["contacts", "get"],
|
|
2965
|
-
summary: "Fetch one contact by email",
|
|
2966
|
-
sdkMethod:
|
|
2967
|
-
|
|
2968
|
-
route: { method: "POST", path: "/v1/contacts/search" },
|
|
3610
|
+
summary: "Fetch one contact by email \u2014 the bare row",
|
|
3611
|
+
sdkMethod: "contacts.get",
|
|
3612
|
+
route: { method: "GET", path: "/v1/contacts/{email}" },
|
|
2969
3613
|
commandClass: "read",
|
|
2970
3614
|
args: [
|
|
2971
3615
|
{
|
|
2972
3616
|
name: "email",
|
|
2973
|
-
summary: "Email address of the contact",
|
|
3617
|
+
summary: "Email address of the contact (the contact primary key)",
|
|
2974
3618
|
isRequired: true
|
|
2975
3619
|
}
|
|
2976
3620
|
],
|
|
2977
3621
|
examples: ["brew-cli contacts get jane@example.com"],
|
|
2978
|
-
run: async ({ ctx, args }) => {
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
filters: [{ field: "email", operator: "equals", value: email }],
|
|
2982
|
-
limit: 1
|
|
2983
|
-
});
|
|
2984
|
-
const contact = result.data[0];
|
|
2985
|
-
if (contact === void 0) {
|
|
2986
|
-
throw new CliApiError({
|
|
2987
|
-
status: 404,
|
|
2988
|
-
code: "CONTACT_NOT_FOUND",
|
|
2989
|
-
type: "not_found",
|
|
2990
|
-
message: `No contact found for ${email}`,
|
|
2991
|
-
suggestion: "Check the address, or create the contact with `brew-cli contacts upsert`."
|
|
2992
|
-
});
|
|
2993
|
-
}
|
|
2994
|
-
return { data: contact };
|
|
2995
|
-
}
|
|
3622
|
+
run: async ({ ctx, args }) => ({
|
|
3623
|
+
data: await ctx.client().contacts.get(args.email ?? "")
|
|
3624
|
+
})
|
|
2996
3625
|
});
|
|
2997
3626
|
|
|
2998
3627
|
// src/commands/contacts/import-csv.ts
|
|
2999
3628
|
var contactsImportCsvCommand = defineCommand({
|
|
3000
3629
|
path: ["contacts", "import-csv"],
|
|
3001
|
-
summary: "Bulk-import contacts from a CSV file or stdin",
|
|
3630
|
+
summary: "Bulk-import contacts from a CSV file or stdin (free; --validate costs 2 credits per address)",
|
|
3002
3631
|
sdkMethod: "contacts.importCsv",
|
|
3003
3632
|
route: { method: "POST", path: "/v1/contacts/import-csv" },
|
|
3004
3633
|
commandClass: "write",
|
|
3005
3634
|
flags: [
|
|
3006
|
-
{
|
|
3635
|
+
{
|
|
3636
|
+
flag: "--file <path>",
|
|
3637
|
+
summary: "CSV file to import, or - for stdin (or csv in --input)"
|
|
3638
|
+
},
|
|
3007
3639
|
{
|
|
3008
3640
|
flag: "--mapping <pairs...>",
|
|
3009
3641
|
summary: "Column mapping csvColumn=fieldName, repeatable"
|
|
3010
3642
|
},
|
|
3643
|
+
{
|
|
3644
|
+
flag: "--date-order <order>",
|
|
3645
|
+
summary: "month_first or day_first: how to read dates like 03/04/2026 (a day over 12 in the column wins; default month-first, with a DATE_ORDER_ASSUMED warning)"
|
|
3646
|
+
},
|
|
3647
|
+
{
|
|
3648
|
+
flag: "--validate",
|
|
3649
|
+
summary: "Deliverability-check every imported address (2 credits per address)"
|
|
3650
|
+
},
|
|
3651
|
+
{
|
|
3652
|
+
flag: "--consent-source <source>",
|
|
3653
|
+
summary: "Stamp a marketing consent record on every row: api, form or import (sets the source of a record given in --input)"
|
|
3654
|
+
},
|
|
3655
|
+
INPUT_FLAG,
|
|
3011
3656
|
IDEMPOTENCY_FLAG
|
|
3012
3657
|
],
|
|
3013
3658
|
examples: [
|
|
3014
3659
|
"brew-cli contacts import-csv --file contacts.csv",
|
|
3015
|
-
"cat contacts.csv | brew-cli contacts import-csv --file - --mapping Email=email"
|
|
3660
|
+
"cat contacts.csv | brew-cli contacts import-csv --file - --mapping Email=email",
|
|
3661
|
+
"brew-cli contacts import-csv --file eu-signups.csv --date-order day_first --consent-source import"
|
|
3016
3662
|
],
|
|
3017
3663
|
run: async ({ ctx, flags }) => {
|
|
3018
|
-
|
|
3019
|
-
|
|
3664
|
+
if (flags.input === "-" && flags.file === "-") {
|
|
3665
|
+
throw new CliUsageError("Only one of --input and --file can read stdin.");
|
|
3666
|
+
}
|
|
3667
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
3668
|
+
const consentSource = flagString(flags.consentSource);
|
|
3669
|
+
const input = mergeInput(base, {
|
|
3670
|
+
csv: await readTextFlag(ctx, flags.file, "--file"),
|
|
3671
|
+
mapping: parseKeyValues(flags.mapping, "--mapping"),
|
|
3672
|
+
dateOrder: flagString(flags.dateOrder),
|
|
3673
|
+
validate: flags.validate === true ? true : void 0
|
|
3674
|
+
});
|
|
3675
|
+
if (typeof input.csv !== "string" || input.csv.trim() === "") {
|
|
3020
3676
|
throw new CliUsageError(
|
|
3021
|
-
"--file
|
|
3677
|
+
"Pass the CSV with --file (a path, or - for stdin) or as csv in --input."
|
|
3022
3678
|
);
|
|
3023
3679
|
}
|
|
3024
|
-
|
|
3680
|
+
if (consentSource !== void 0) {
|
|
3681
|
+
const record = input.consent;
|
|
3682
|
+
input.consent = {
|
|
3683
|
+
...typeof record === "object" && record !== null ? record : {},
|
|
3684
|
+
source: consentSource
|
|
3685
|
+
};
|
|
3686
|
+
}
|
|
3025
3687
|
const result = await ctx.client().contacts.importCsv(
|
|
3026
|
-
asSdkInput(
|
|
3027
|
-
csv,
|
|
3028
|
-
...mapping === void 0 ? {} : { mapping }
|
|
3029
|
-
}),
|
|
3688
|
+
asSdkInput(input),
|
|
3030
3689
|
requestOptions(flags)
|
|
3031
3690
|
);
|
|
3032
3691
|
return { data: result };
|
|
3033
3692
|
}
|
|
3034
3693
|
});
|
|
3035
3694
|
|
|
3695
|
+
// src/commands/contacts/list.ts
|
|
3696
|
+
var contactsListCommand = defineCommand({
|
|
3697
|
+
path: ["contacts", "list"],
|
|
3698
|
+
summary: "List contacts, newest first \u2014 free-text search and one audience; typed clauses are `contacts search`",
|
|
3699
|
+
sdkMethod: "contacts.list",
|
|
3700
|
+
route: { method: "GET", path: "/v1/contacts" },
|
|
3701
|
+
commandClass: "read",
|
|
3702
|
+
flags: [
|
|
3703
|
+
{ flag: "--search <text>", summary: "Free-text search" },
|
|
3704
|
+
{
|
|
3705
|
+
flag: "--audience <audienceId>",
|
|
3706
|
+
summary: "Only members of this saved audience"
|
|
3707
|
+
},
|
|
3708
|
+
{
|
|
3709
|
+
flag: "--sort <field>",
|
|
3710
|
+
summary: "Any core column or custom field (default createdAt)"
|
|
3711
|
+
},
|
|
3712
|
+
{ flag: "--order <order>", summary: "Sort order: asc | desc" },
|
|
3713
|
+
LIMIT_FLAG,
|
|
3714
|
+
CURSOR_FLAG,
|
|
3715
|
+
ALL_FLAG,
|
|
3716
|
+
INPUT_FLAG
|
|
3717
|
+
],
|
|
3718
|
+
examples: [
|
|
3719
|
+
"brew-cli contacts list --limit 20",
|
|
3720
|
+
"brew-cli contacts list --audience aud_3k9sQ --all --json",
|
|
3721
|
+
"brew-cli contacts list --search acme --sort email --order asc"
|
|
3722
|
+
],
|
|
3723
|
+
run: async ({ ctx, flags }) => {
|
|
3724
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
3725
|
+
const input = mergeInput(base, {
|
|
3726
|
+
search: flagString(flags.search),
|
|
3727
|
+
audienceId: flagString(flags.audience),
|
|
3728
|
+
sort: flagString(flags.sort),
|
|
3729
|
+
order: flagString(flags.order),
|
|
3730
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
3731
|
+
cursor: flagString(flags.cursor)
|
|
3732
|
+
});
|
|
3733
|
+
const contacts = ctx.client().contacts;
|
|
3734
|
+
if (flags.all === true) {
|
|
3735
|
+
const rows = await collectAll(
|
|
3736
|
+
ctx,
|
|
3737
|
+
(cursor) => contacts.list(
|
|
3738
|
+
asSdkInput({
|
|
3739
|
+
...input,
|
|
3740
|
+
...cursor === void 0 ? {} : { cursor }
|
|
3741
|
+
})
|
|
3742
|
+
)
|
|
3743
|
+
);
|
|
3744
|
+
return {
|
|
3745
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
3746
|
+
human: renderContacts(rows)
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
const result = await contacts.list(asSdkInput(input));
|
|
3750
|
+
return { data: result, human: renderContacts(result.data) };
|
|
3751
|
+
}
|
|
3752
|
+
});
|
|
3753
|
+
function renderContacts(rows) {
|
|
3754
|
+
if (rows.length === 0) {
|
|
3755
|
+
return "No contacts found.";
|
|
3756
|
+
}
|
|
3757
|
+
return renderTable(rows, [
|
|
3758
|
+
{ key: "email", header: "EMAIL" },
|
|
3759
|
+
{ key: "firstName", header: "FIRST" },
|
|
3760
|
+
{ key: "lastName", header: "LAST" },
|
|
3761
|
+
{ key: "subscribed", header: "SUBSCRIBED" }
|
|
3762
|
+
]);
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3036
3765
|
// src/commands/contacts/search.ts
|
|
3037
3766
|
var contactsSearchCommand = defineCommand({
|
|
3038
3767
|
path: ["contacts", "search"],
|
|
@@ -3085,14 +3814,14 @@ var contactsSearchCommand = defineCommand({
|
|
|
3085
3814
|
);
|
|
3086
3815
|
return {
|
|
3087
3816
|
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
3088
|
-
human:
|
|
3817
|
+
human: renderContacts2(rows)
|
|
3089
3818
|
};
|
|
3090
3819
|
}
|
|
3091
3820
|
const result = await contacts.search(asSdkInput(input));
|
|
3092
|
-
return { data: result, human:
|
|
3821
|
+
return { data: result, human: renderContacts2(result.data) };
|
|
3093
3822
|
}
|
|
3094
3823
|
});
|
|
3095
|
-
function
|
|
3824
|
+
function renderContacts2(rows) {
|
|
3096
3825
|
if (rows.length === 0) {
|
|
3097
3826
|
return "No contacts matched.";
|
|
3098
3827
|
}
|
|
@@ -3560,14 +4289,17 @@ var contractsInferCommand = defineCommand({
|
|
|
3560
4289
|
examples: [
|
|
3561
4290
|
`brew-cli contracts infer --input '{"email":"jane@example.com","order":{"total":9.5}}'`
|
|
3562
4291
|
],
|
|
3563
|
-
// Accepts either the bare example object or `{ example: {...} }
|
|
3564
|
-
//
|
|
4292
|
+
// Accepts either the bare example object or `{ example: {...} }`; only the
|
|
4293
|
+
// envelope carries `subjectKind` (a bare example may have its own field of
|
|
4294
|
+
// that name). Un-inferable spots (nulls, empty arrays) come back under
|
|
4295
|
+
// `issues`.
|
|
3565
4296
|
run: async ({ ctx, flags }) => {
|
|
3566
4297
|
const input = mergeInput(
|
|
3567
4298
|
await readJsonFlag(ctx, flags.input, "--input"),
|
|
3568
4299
|
{}
|
|
3569
4300
|
);
|
|
3570
|
-
const
|
|
4301
|
+
const isEnvelope = input.example !== void 0;
|
|
4302
|
+
const example = isEnvelope ? input.example : input;
|
|
3571
4303
|
if (typeof example !== "object" || example === null || Array.isArray(example) || Object.keys(example).length === 0) {
|
|
3572
4304
|
throw new CliUsageError(
|
|
3573
4305
|
"--input with a non-empty example object is required (the JSON your system sends)."
|
|
@@ -3576,7 +4308,10 @@ var contractsInferCommand = defineCommand({
|
|
|
3576
4308
|
const body = await rawRequest(ctx, {
|
|
3577
4309
|
method: "POST",
|
|
3578
4310
|
path: "/v1/payload-contracts/infer",
|
|
3579
|
-
body: {
|
|
4311
|
+
body: {
|
|
4312
|
+
example,
|
|
4313
|
+
...isEnvelope && input.subjectKind !== void 0 ? { subjectKind: input.subjectKind } : {}
|
|
4314
|
+
}
|
|
3580
4315
|
});
|
|
3581
4316
|
return { data: body };
|
|
3582
4317
|
}
|
|
@@ -3628,6 +4363,10 @@ var SDK_SKIP_LIST = [
|
|
|
3628
4363
|
sdkPath: "automations.triggers.validatePayload",
|
|
3629
4364
|
reason: "covered by `automations triggers contract validate` (raw route, bound pre-SDK-v9)"
|
|
3630
4365
|
},
|
|
4366
|
+
{
|
|
4367
|
+
sdkPath: "brand.getImages",
|
|
4368
|
+
reason: "covered by `brand get-images` (raw route: SDK 10 cannot send `kind` or `sort`, brew-v2#1713; bind SDK 11.2)"
|
|
4369
|
+
},
|
|
3631
4370
|
{
|
|
3632
4371
|
sdkPath: "payloadContracts.infer",
|
|
3633
4372
|
reason: "covered by `contracts infer` (raw route, bound pre-SDK-v9)"
|
|
@@ -3641,12 +4380,12 @@ var SDK_SKIP_LIST = [
|
|
|
3641
4380
|
reason: "auto-pager covered by `analytics events --all`"
|
|
3642
4381
|
},
|
|
3643
4382
|
{
|
|
3644
|
-
sdkPath: "
|
|
3645
|
-
reason: "auto-pager covered by `
|
|
4383
|
+
sdkPath: "sends.listAll",
|
|
4384
|
+
reason: "auto-pager covered by `sends list --all`"
|
|
3646
4385
|
},
|
|
3647
4386
|
{
|
|
3648
|
-
sdkPath: "
|
|
3649
|
-
reason: "auto-pager covered by `
|
|
4387
|
+
sdkPath: "automations.triggerInstances.listAll",
|
|
4388
|
+
reason: "auto-pager covered by `automations trigger-instances list --all`"
|
|
3650
4389
|
},
|
|
3651
4390
|
{
|
|
3652
4391
|
sdkPath: "brand.update",
|
|
@@ -3722,7 +4461,7 @@ function buildManifest() {
|
|
|
3722
4461
|
|
|
3723
4462
|
// src/commands/docs.ts
|
|
3724
4463
|
var DOCS_POINTERS = {
|
|
3725
|
-
documentation: "https://docs.
|
|
4464
|
+
documentation: "https://docs.brew.new",
|
|
3726
4465
|
openapiSpec: "https://brew.new/openapi/public-api-v1.yaml",
|
|
3727
4466
|
agentGuide: "https://brew.new/api/v1/llms.txt",
|
|
3728
4467
|
apiCatalog: "https://brew.new/api/v1/help",
|
|
@@ -3913,28 +4652,15 @@ var domainsDeleteCommand = defineCommand({
|
|
|
3913
4652
|
// src/commands/domains/get.ts
|
|
3914
4653
|
var domainsGetCommand = defineCommand({
|
|
3915
4654
|
path: ["domains", "get"],
|
|
3916
|
-
summary: "Fetch one sending domain by id",
|
|
3917
|
-
sdkMethod:
|
|
3918
|
-
|
|
3919
|
-
route: { method: "GET", path: "/v1/domains" },
|
|
4655
|
+
summary: "Fetch one sending domain by id \u2014 the bare row",
|
|
4656
|
+
sdkMethod: "domains.get",
|
|
4657
|
+
route: { method: "GET", path: "/v1/domains/{domainId}" },
|
|
3920
4658
|
commandClass: "read",
|
|
3921
4659
|
args: [{ name: "domainId", summary: "Domain id to fetch", isRequired: true }],
|
|
3922
4660
|
examples: ["brew-cli domains get dom_3k9sQ"],
|
|
3923
|
-
run: async ({ ctx, args }) => {
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
const domain = result.data[0];
|
|
3927
|
-
if (domain === void 0) {
|
|
3928
|
-
throw new CliApiError({
|
|
3929
|
-
status: 404,
|
|
3930
|
-
code: "DOMAIN_NOT_FOUND",
|
|
3931
|
-
type: "not_found",
|
|
3932
|
-
message: `No domain found for ${domainId}`,
|
|
3933
|
-
suggestion: "List domains with `brew-cli domains list`."
|
|
3934
|
-
});
|
|
3935
|
-
}
|
|
3936
|
-
return { data: domain };
|
|
3937
|
-
}
|
|
4661
|
+
run: async ({ ctx, args }) => ({
|
|
4662
|
+
data: await ctx.client().domains.get(args.domainId ?? "")
|
|
4663
|
+
})
|
|
3938
4664
|
});
|
|
3939
4665
|
|
|
3940
4666
|
// src/commands/domains/health.ts
|
|
@@ -4015,109 +4741,297 @@ function renderDomains(rows) {
|
|
|
4015
4741
|
]);
|
|
4016
4742
|
}
|
|
4017
4743
|
|
|
4018
|
-
// src/commands/domains/
|
|
4019
|
-
var
|
|
4020
|
-
path: ["domains", "
|
|
4021
|
-
summary: "
|
|
4022
|
-
sdkMethod:
|
|
4023
|
-
|
|
4744
|
+
// src/commands/domains/unsubscribes/add.ts
|
|
4745
|
+
var domainsUnsubscribesAddCommand = defineCommand({
|
|
4746
|
+
path: ["domains", "unsubscribes", "add"],
|
|
4747
|
+
summary: "Add addresses to a marketing domain's unsubscribe list (that domain only)",
|
|
4748
|
+
sdkMethod: null,
|
|
4749
|
+
isRawTransport: true,
|
|
4750
|
+
route: { method: "POST", path: "/v1/domains/{domainId}/unsubscribes" },
|
|
4024
4751
|
commandClass: "write",
|
|
4025
4752
|
args: [
|
|
4026
|
-
{ name: "domainId", summary: "
|
|
4753
|
+
{ name: "domainId", summary: "Marketing domain id", isRequired: true }
|
|
4027
4754
|
],
|
|
4028
4755
|
flags: [
|
|
4029
4756
|
{
|
|
4030
|
-
flag: "--
|
|
4031
|
-
summary: "
|
|
4032
|
-
},
|
|
4033
|
-
{
|
|
4034
|
-
flag: "--default-from-email <email>",
|
|
4035
|
-
summary: "Default From address on this domain"
|
|
4036
|
-
},
|
|
4037
|
-
{
|
|
4038
|
-
flag: "--default-reply-to-email <email>",
|
|
4039
|
-
summary: "Default Reply-To address"
|
|
4757
|
+
flag: "--email <addresses...>",
|
|
4758
|
+
summary: "Address to suppress, repeatable (up to 1,000)"
|
|
4040
4759
|
},
|
|
4041
|
-
|
|
4760
|
+
IDEMPOTENCY_FLAG
|
|
4042
4761
|
],
|
|
4043
4762
|
examples: [
|
|
4044
|
-
|
|
4763
|
+
"brew-cli domains unsubscribes add dom_123 --email ada@example.com --email bo@example.com"
|
|
4045
4764
|
],
|
|
4046
4765
|
run: async ({ ctx, args, flags }) => {
|
|
4047
|
-
const
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
defaultFromEmail: flagString(flags.defaultFromEmail),
|
|
4051
|
-
defaultReplyToEmail: flagString(flags.defaultReplyToEmail)
|
|
4052
|
-
});
|
|
4053
|
-
if (Object.keys(input).length === 0) {
|
|
4054
|
-
throw new CliUsageError("Nothing to update \u2014 pass flags or --input.");
|
|
4766
|
+
const emails = toStringArray(flags.email);
|
|
4767
|
+
if (emails === void 0) {
|
|
4768
|
+
throw new CliUsageError("Pass at least one --email.");
|
|
4055
4769
|
}
|
|
4056
|
-
const
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
);
|
|
4062
|
-
return { data:
|
|
4770
|
+
const body = await rawRequest(ctx, {
|
|
4771
|
+
method: "POST",
|
|
4772
|
+
path: `/v1/domains/${encodeURIComponent(args.domainId ?? "")}/unsubscribes`,
|
|
4773
|
+
body: { emails },
|
|
4774
|
+
idempotencyKey: flagString(flags.idempotencyKey)
|
|
4775
|
+
});
|
|
4776
|
+
return { data: body };
|
|
4063
4777
|
}
|
|
4064
4778
|
});
|
|
4065
4779
|
|
|
4066
|
-
// src/commands/domains/
|
|
4067
|
-
var
|
|
4068
|
-
path: ["domains", "
|
|
4069
|
-
summary: "
|
|
4070
|
-
sdkMethod:
|
|
4071
|
-
|
|
4072
|
-
|
|
4780
|
+
// src/commands/domains/unsubscribes/export.ts
|
|
4781
|
+
var domainsUnsubscribesExportCommand = defineCommand({
|
|
4782
|
+
path: ["domains", "unsubscribes", "export"],
|
|
4783
|
+
summary: "A domain's unsubscribe list as CSV (truncated when capped)",
|
|
4784
|
+
sdkMethod: null,
|
|
4785
|
+
isRawTransport: true,
|
|
4786
|
+
route: {
|
|
4787
|
+
method: "GET",
|
|
4788
|
+
path: "/v1/domains/{domainId}/unsubscribes/export"
|
|
4789
|
+
},
|
|
4790
|
+
commandClass: "read",
|
|
4073
4791
|
args: [
|
|
4074
|
-
{ name: "domainId", summary: "
|
|
4792
|
+
{ name: "domainId", summary: "Marketing domain id", isRequired: true }
|
|
4075
4793
|
],
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4794
|
+
flags: [
|
|
4795
|
+
{
|
|
4796
|
+
flag: "--scope <scope>",
|
|
4797
|
+
summary: "any (default), domain or all"
|
|
4798
|
+
}
|
|
4799
|
+
],
|
|
4800
|
+
examples: [
|
|
4801
|
+
"brew-cli domains unsubscribes export dom_123 > optouts.csv",
|
|
4802
|
+
"brew-cli domains unsubscribes export dom_123 --scope all --json"
|
|
4803
|
+
],
|
|
4804
|
+
run: async ({ ctx, args, flags }) => {
|
|
4805
|
+
const body = await rawRequest(ctx, {
|
|
4806
|
+
method: "GET",
|
|
4807
|
+
path: `/v1/domains/${encodeURIComponent(args.domainId ?? "")}/unsubscribes/export`,
|
|
4808
|
+
query: { scope: flagString(flags.scope) }
|
|
4809
|
+
});
|
|
4810
|
+
return { data: body, human: body.csv };
|
|
4811
|
+
}
|
|
4080
4812
|
});
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4813
|
+
|
|
4814
|
+
// src/commands/domains/unsubscribes/import.ts
|
|
4815
|
+
var domainsUnsubscribesImportCommand = defineCommand({
|
|
4816
|
+
path: ["domains", "unsubscribes", "import"],
|
|
4817
|
+
summary: "Add every address in a CSV to a domain's unsubscribe list",
|
|
4818
|
+
sdkMethod: null,
|
|
4819
|
+
isRawTransport: true,
|
|
4820
|
+
route: {
|
|
4821
|
+
method: "POST",
|
|
4822
|
+
path: "/v1/domains/{domainId}/unsubscribes/import"
|
|
4823
|
+
},
|
|
4090
4824
|
commandClass: "write",
|
|
4091
|
-
|
|
4825
|
+
args: [
|
|
4826
|
+
{ name: "domainId", summary: "Marketing domain id", isRequired: true }
|
|
4827
|
+
],
|
|
4092
4828
|
flags: [
|
|
4829
|
+
{ flag: "--file <path>", summary: "CSV file, or - for stdin" },
|
|
4093
4830
|
{
|
|
4094
|
-
flag: "--
|
|
4095
|
-
summary: "
|
|
4096
|
-
},
|
|
4097
|
-
{ flag: "--subject <text>", summary: "Inbox subject line" },
|
|
4098
|
-
{
|
|
4099
|
-
flag: "--preview-text <text>",
|
|
4100
|
-
summary: "Inbox preview text; an explicit empty value stays empty"
|
|
4101
|
-
},
|
|
4102
|
-
{
|
|
4103
|
-
flag: "--sending-purpose <purpose>",
|
|
4104
|
-
summary: "marketing | transactional (default: marketing)"
|
|
4831
|
+
flag: "--column <header>",
|
|
4832
|
+
summary: "The column holding the addresses (by header)"
|
|
4105
4833
|
},
|
|
4106
|
-
INPUT_FLAG,
|
|
4107
4834
|
IDEMPOTENCY_FLAG
|
|
4108
4835
|
],
|
|
4109
4836
|
examples: [
|
|
4110
|
-
|
|
4111
|
-
'cat email.html | brew-cli emails audit --file - --subject "Receipt" --sending-purpose transactional',
|
|
4112
|
-
`brew-cli emails audit --input '{"emailHtml":"<p>Hello</p>","subject":"Hello"}'`
|
|
4837
|
+
"brew-cli domains unsubscribes import dom_123 --file optouts.csv --column Email"
|
|
4113
4838
|
],
|
|
4114
|
-
run: async ({ ctx, flags }) => {
|
|
4115
|
-
const
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4839
|
+
run: async ({ ctx, args, flags }) => {
|
|
4840
|
+
const csv = await readTextFlag(ctx, flags.file, "--file");
|
|
4841
|
+
if (csv === void 0 || csv.trim() === "") {
|
|
4842
|
+
throw new CliUsageError(
|
|
4843
|
+
"--file is required (a CSV path, or - for stdin)."
|
|
4844
|
+
);
|
|
4845
|
+
}
|
|
4846
|
+
const column = flagString(flags.column);
|
|
4847
|
+
const body = await rawRequest(ctx, {
|
|
4848
|
+
method: "POST",
|
|
4849
|
+
path: `/v1/domains/${encodeURIComponent(args.domainId ?? "")}/unsubscribes/import`,
|
|
4850
|
+
body: { csv, ...column === void 0 ? {} : { column } },
|
|
4851
|
+
idempotencyKey: flagString(flags.idempotencyKey)
|
|
4852
|
+
});
|
|
4853
|
+
return { data: body };
|
|
4854
|
+
}
|
|
4855
|
+
});
|
|
4856
|
+
|
|
4857
|
+
// src/commands/domains/unsubscribes/list.ts
|
|
4858
|
+
var domainsUnsubscribesListCommand = defineCommand({
|
|
4859
|
+
path: ["domains", "unsubscribes", "list"],
|
|
4860
|
+
summary: "One page of a marketing domain's unsubscribe list, newest first",
|
|
4861
|
+
sdkMethod: null,
|
|
4862
|
+
isRawTransport: true,
|
|
4863
|
+
route: { method: "GET", path: "/v1/domains/{domainId}/unsubscribes" },
|
|
4864
|
+
commandClass: "read",
|
|
4865
|
+
args: [
|
|
4866
|
+
{ name: "domainId", summary: "Marketing domain id", isRequired: true }
|
|
4867
|
+
],
|
|
4868
|
+
flags: [
|
|
4869
|
+
{ flag: "--q <text>", summary: "Search by address" },
|
|
4870
|
+
{
|
|
4871
|
+
flag: "--scope <scope>",
|
|
4872
|
+
summary: "any (default), domain (this list only) or all (brand-wide opt-outs)"
|
|
4873
|
+
},
|
|
4874
|
+
LIMIT_FLAG,
|
|
4875
|
+
CURSOR_FLAG
|
|
4876
|
+
],
|
|
4877
|
+
examples: [
|
|
4878
|
+
"brew-cli domains unsubscribes list dom_123",
|
|
4879
|
+
"brew-cli domains unsubscribes list dom_123 --scope domain --q ada"
|
|
4880
|
+
],
|
|
4881
|
+
run: async ({ ctx, args, flags }) => {
|
|
4882
|
+
const limit = flagInt(flags.limit, "--limit");
|
|
4883
|
+
const body = await rawRequest(ctx, {
|
|
4884
|
+
method: "GET",
|
|
4885
|
+
path: `/v1/domains/${encodeURIComponent(args.domainId ?? "")}/unsubscribes`,
|
|
4886
|
+
query: {
|
|
4887
|
+
q: flagString(flags.q),
|
|
4888
|
+
scope: flagString(flags.scope),
|
|
4889
|
+
limit: limit === void 0 ? void 0 : String(limit),
|
|
4890
|
+
cursor: flagString(flags.cursor)
|
|
4891
|
+
}
|
|
4892
|
+
});
|
|
4893
|
+
return { data: body, human: renderRows(body.data) };
|
|
4894
|
+
}
|
|
4895
|
+
});
|
|
4896
|
+
function renderRows(rows) {
|
|
4897
|
+
if (rows.length === 0) {
|
|
4898
|
+
return "No unsubscribes on this list.";
|
|
4899
|
+
}
|
|
4900
|
+
return renderTable(rows, [
|
|
4901
|
+
{ key: "email", header: "EMAIL" },
|
|
4902
|
+
{ key: "scope", header: "SCOPE" },
|
|
4903
|
+
{ key: "unsubscribedAt", header: "UNSUBSCRIBED" }
|
|
4904
|
+
]);
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
// src/commands/domains/unsubscribes/remove.ts
|
|
4908
|
+
var domainsUnsubscribesRemoveCommand = defineCommand({
|
|
4909
|
+
path: ["domains", "unsubscribes", "remove"],
|
|
4910
|
+
summary: "Take one address off a domain's unsubscribe list (never re-subscribes a brand-wide opt-out)",
|
|
4911
|
+
sdkMethod: null,
|
|
4912
|
+
isRawTransport: true,
|
|
4913
|
+
route: {
|
|
4914
|
+
method: "DELETE",
|
|
4915
|
+
path: "/v1/domains/{domainId}/unsubscribes/{email}"
|
|
4916
|
+
},
|
|
4917
|
+
commandClass: "write",
|
|
4918
|
+
args: [
|
|
4919
|
+
{ name: "domainId", summary: "Marketing domain id", isRequired: true },
|
|
4920
|
+
{ name: "email", summary: "Address to remove", isRequired: true }
|
|
4921
|
+
],
|
|
4922
|
+
flags: [],
|
|
4923
|
+
examples: ["brew-cli domains unsubscribes remove dom_123 ada@example.com"],
|
|
4924
|
+
run: async ({ ctx, args }) => ({
|
|
4925
|
+
data: await rawRequest(ctx, {
|
|
4926
|
+
method: "DELETE",
|
|
4927
|
+
path: `/v1/domains/${encodeURIComponent(args.domainId ?? "")}/unsubscribes/${encodeURIComponent(args.email ?? "")}`
|
|
4928
|
+
})
|
|
4929
|
+
})
|
|
4930
|
+
});
|
|
4931
|
+
|
|
4932
|
+
// src/commands/domains/update.ts
|
|
4933
|
+
var domainsUpdateCommand = defineCommand({
|
|
4934
|
+
path: ["domains", "update"],
|
|
4935
|
+
summary: "Update default sender settings for a domain",
|
|
4936
|
+
sdkMethod: "domains.updateSettings",
|
|
4937
|
+
route: { method: "PATCH", path: "/v1/domains/{domainId}" },
|
|
4938
|
+
commandClass: "write",
|
|
4939
|
+
args: [
|
|
4940
|
+
{ name: "domainId", summary: "Domain id to update", isRequired: true }
|
|
4941
|
+
],
|
|
4942
|
+
flags: [
|
|
4943
|
+
{
|
|
4944
|
+
flag: "--default-sender-name <name>",
|
|
4945
|
+
summary: "Default From display name"
|
|
4946
|
+
},
|
|
4947
|
+
{
|
|
4948
|
+
flag: "--default-from-email <email>",
|
|
4949
|
+
summary: "Default From address on this domain"
|
|
4950
|
+
},
|
|
4951
|
+
{
|
|
4952
|
+
flag: "--default-reply-to-email <email>",
|
|
4953
|
+
summary: "Default Reply-To address"
|
|
4954
|
+
},
|
|
4955
|
+
INPUT_FLAG
|
|
4956
|
+
],
|
|
4957
|
+
examples: [
|
|
4958
|
+
'brew-cli domains update dom_8s1Kj --default-sender-name "Brew Coffee"'
|
|
4959
|
+
],
|
|
4960
|
+
run: async ({ ctx, args, flags }) => {
|
|
4961
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
4962
|
+
const input = mergeInput(base, {
|
|
4963
|
+
defaultSenderName: flagString(flags.defaultSenderName),
|
|
4964
|
+
defaultFromEmail: flagString(flags.defaultFromEmail),
|
|
4965
|
+
defaultReplyToEmail: flagString(flags.defaultReplyToEmail)
|
|
4966
|
+
});
|
|
4967
|
+
if (Object.keys(input).length === 0) {
|
|
4968
|
+
throw new CliUsageError("Nothing to update \u2014 pass flags or --input.");
|
|
4969
|
+
}
|
|
4970
|
+
const result = await ctx.client().domains.updateSettings(
|
|
4971
|
+
asSdkInput({
|
|
4972
|
+
...input,
|
|
4973
|
+
domainId: args.domainId ?? ""
|
|
4974
|
+
})
|
|
4975
|
+
);
|
|
4976
|
+
return { data: result };
|
|
4977
|
+
}
|
|
4978
|
+
});
|
|
4979
|
+
|
|
4980
|
+
// src/commands/domains/verify.ts
|
|
4981
|
+
var domainsVerifyCommand = defineCommand({
|
|
4982
|
+
path: ["domains", "verify"],
|
|
4983
|
+
summary: "Re-check DNS records and refresh domain verification",
|
|
4984
|
+
sdkMethod: "domains.verify",
|
|
4985
|
+
route: { method: "POST", path: "/v1/domains/{domainId}/verify" },
|
|
4986
|
+
commandClass: "write",
|
|
4987
|
+
args: [
|
|
4988
|
+
{ name: "domainId", summary: "Domain id to verify", isRequired: true }
|
|
4989
|
+
],
|
|
4990
|
+
examples: ["brew-cli domains verify dom_8s1Kj"],
|
|
4991
|
+
run: async ({ ctx, args }) => ({
|
|
4992
|
+
data: await ctx.client().domains.verify({ domainId: args.domainId ?? "" })
|
|
4993
|
+
})
|
|
4994
|
+
});
|
|
4995
|
+
var SENDING_PURPOSES = /* @__PURE__ */ new Set(["marketing", "transactional"]);
|
|
4996
|
+
function optionalText(value) {
|
|
4997
|
+
return typeof value === "string" ? value : void 0;
|
|
4998
|
+
}
|
|
4999
|
+
var emailsAuditCommand = defineCommand({
|
|
5000
|
+
path: ["emails", "audit"],
|
|
5001
|
+
summary: "Audit raw email content for production readiness (5 credits when complete)",
|
|
5002
|
+
sdkMethod: "emails.auditEmail",
|
|
5003
|
+
route: { method: "POST", path: "/v1/emails/audit" },
|
|
5004
|
+
commandClass: "write",
|
|
5005
|
+
isCredited: true,
|
|
5006
|
+
flags: [
|
|
5007
|
+
{
|
|
5008
|
+
flag: "--file <path>",
|
|
5009
|
+
summary: "Email HTML file to audit, or - for stdin"
|
|
5010
|
+
},
|
|
5011
|
+
{ flag: "--subject <text>", summary: "Inbox subject line" },
|
|
5012
|
+
{
|
|
5013
|
+
flag: "--preview-text <text>",
|
|
5014
|
+
summary: "Inbox preview text; an explicit empty value stays empty"
|
|
5015
|
+
},
|
|
5016
|
+
{
|
|
5017
|
+
flag: "--sending-purpose <purpose>",
|
|
5018
|
+
summary: "marketing | transactional (default: marketing)"
|
|
5019
|
+
},
|
|
5020
|
+
INPUT_FLAG,
|
|
5021
|
+
IDEMPOTENCY_FLAG
|
|
5022
|
+
],
|
|
5023
|
+
examples: [
|
|
5024
|
+
'brew-cli emails audit --file newsletter.html --subject "August update" --sending-purpose marketing',
|
|
5025
|
+
'cat email.html | brew-cli emails audit --file - --subject "Receipt" --sending-purpose transactional',
|
|
5026
|
+
`brew-cli emails audit --input '{"emailHtml":"<p>Hello</p>","subject":"Hello"}'`
|
|
5027
|
+
],
|
|
5028
|
+
run: async ({ ctx, flags }) => {
|
|
5029
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
5030
|
+
const emailHtml = await readTextFlag(ctx, flags.file, "--file");
|
|
5031
|
+
const sendingPurpose = flagString(flags.sendingPurpose);
|
|
5032
|
+
if (sendingPurpose !== void 0 && !SENDING_PURPOSES.has(sendingPurpose)) {
|
|
5033
|
+
throw new CliUsageError(
|
|
5034
|
+
`Unknown --sending-purpose '${sendingPurpose}' (expected marketing | transactional).`
|
|
4121
5035
|
);
|
|
4122
5036
|
}
|
|
4123
5037
|
const input = mergeInput(base, {
|
|
@@ -4160,19 +5074,41 @@ var emailsCloneCommand = defineCommand({
|
|
|
4160
5074
|
flag: "--email-version-id <id>",
|
|
4161
5075
|
summary: "Exact source version to clone (default: latest)"
|
|
4162
5076
|
},
|
|
5077
|
+
{
|
|
5078
|
+
flag: "--title <title>",
|
|
5079
|
+
summary: "Name for the clone (default: Copy of <source title>)"
|
|
5080
|
+
},
|
|
5081
|
+
{
|
|
5082
|
+
flag: "--group-id <groupId>",
|
|
5083
|
+
summary: "File the clone under an existing group (grp_\u2026), or ungrouped"
|
|
5084
|
+
},
|
|
5085
|
+
{
|
|
5086
|
+
flag: "--group-name <name>",
|
|
5087
|
+
summary: "File the clone under a group found (or created) by this name; not with --group-id"
|
|
5088
|
+
},
|
|
4163
5089
|
IDEMPOTENCY_FLAG
|
|
4164
5090
|
],
|
|
4165
5091
|
examples: [
|
|
4166
5092
|
"brew-cli emails clone eml_2SmZOWV3ZQ7W5x6g3m4p",
|
|
4167
|
-
"brew-cli emails clone eml_2SmZOWV3ZQ7W5x6g3m4p --email-version-id emv_9f2kX"
|
|
5093
|
+
"brew-cli emails clone eml_2SmZOWV3ZQ7W5x6g3m4p --email-version-id emv_9f2kX",
|
|
5094
|
+
'brew-cli emails clone eml_2SmZOWV3ZQ7W5x6g3m4p --title "Fall sale (B)" --group-name "Fall campaign"'
|
|
4168
5095
|
],
|
|
4169
5096
|
run: async ({ ctx, args, flags }) => {
|
|
4170
5097
|
const emailVersionId = flagString(flags.emailVersionId);
|
|
5098
|
+
const title = flagString(flags.title);
|
|
5099
|
+
const groupId = flagString(flags.groupId);
|
|
5100
|
+
const groupName = flagString(flags.groupName);
|
|
5101
|
+
if (groupId !== void 0 && groupName !== void 0) {
|
|
5102
|
+
throw new CliUsageError("Pass --group-id or --group-name, not both.");
|
|
5103
|
+
}
|
|
4171
5104
|
return {
|
|
4172
5105
|
data: await ctx.client().emails.clone(
|
|
4173
5106
|
asSdkInput({
|
|
4174
5107
|
emailId: args.emailId ?? "",
|
|
4175
|
-
...emailVersionId === void 0 ? {} : { emailVersionId }
|
|
5108
|
+
...emailVersionId === void 0 ? {} : { emailVersionId },
|
|
5109
|
+
...title === void 0 ? {} : { title },
|
|
5110
|
+
...groupId === void 0 ? {} : { groupId },
|
|
5111
|
+
...groupName === void 0 ? {} : { groupName }
|
|
4176
5112
|
}),
|
|
4177
5113
|
requestOptions(flags)
|
|
4178
5114
|
)
|
|
@@ -4184,7 +5120,7 @@ var emailsCloneCommand = defineCommand({
|
|
|
4184
5120
|
var emailsCreateInboxPlacementTestCommand = defineCommand({
|
|
4185
5121
|
path: ["emails", "create-inbox-placement-test"],
|
|
4186
5122
|
summary: "Seed-test where the design lands (inbox vs spam) via a real small send (10 credits)",
|
|
4187
|
-
sdkMethod: "emails.
|
|
5123
|
+
sdkMethod: "emails.inboxPlacementTests.create",
|
|
4188
5124
|
route: { method: "POST", path: "/v1/emails/{emailId}/inbox-placement-tests" },
|
|
4189
5125
|
commandClass: "write",
|
|
4190
5126
|
isCredited: true,
|
|
@@ -4228,9 +5164,9 @@ var emailsCreateInboxPlacementTestCommand = defineCommand({
|
|
|
4228
5164
|
const emailVersionId = flagString(flags.emailVersionId);
|
|
4229
5165
|
const providers = toStringArray(flags.providers);
|
|
4230
5166
|
return {
|
|
4231
|
-
// The API answers 202 with a pending test (status: "
|
|
4232
|
-
//
|
|
4233
|
-
data: await ctx.client().emails.
|
|
5167
|
+
// The API answers 202 with a pending test (status: "queued"); poll
|
|
5168
|
+
// `emails get-inbox-placement-results --test-id` for the outcome.
|
|
5169
|
+
data: await ctx.client().emails.inboxPlacementTests.create(
|
|
4234
5170
|
asSdkInput({
|
|
4235
5171
|
emailId: args.emailId ?? "",
|
|
4236
5172
|
domainId,
|
|
@@ -4261,9 +5197,13 @@ var emailsDeleteCommand = defineCommand({
|
|
|
4261
5197
|
});
|
|
4262
5198
|
|
|
4263
5199
|
// src/commands/emails/edit.ts
|
|
5200
|
+
var ENVELOPE_FIELDS = ["title", "subjectLine", "groupId"];
|
|
5201
|
+
function isText(value) {
|
|
5202
|
+
return typeof value === "string" && value !== "";
|
|
5203
|
+
}
|
|
4264
5204
|
var emailsEditCommand = defineCommand({
|
|
4265
5205
|
path: ["emails", "edit"],
|
|
4266
|
-
summary: "AI-edit an email design, and/or set its subject line (
|
|
5206
|
+
summary: "AI-edit an email design, and/or set its subject line, title or group (free without a prompt)",
|
|
4267
5207
|
sdkMethod: "emails.edit",
|
|
4268
5208
|
route: { method: "PATCH", path: "/v1/emails/{emailId}" },
|
|
4269
5209
|
commandClass: "write",
|
|
@@ -4283,30 +5223,54 @@ var emailsEditCommand = defineCommand({
|
|
|
4283
5223
|
flag: "--subject-line <text>",
|
|
4284
5224
|
summary: "The design's default inbox subject line; alone it skips the AI run"
|
|
4285
5225
|
},
|
|
5226
|
+
{
|
|
5227
|
+
flag: "--title <text>",
|
|
5228
|
+
summary: "Rename the design (its canvas name); alone it skips the AI run"
|
|
5229
|
+
},
|
|
5230
|
+
{
|
|
5231
|
+
flag: "--group-id <groupId>",
|
|
5232
|
+
summary: "Move the design into this existing group; alone it skips the AI run"
|
|
5233
|
+
},
|
|
5234
|
+
{
|
|
5235
|
+
flag: "--ungroup",
|
|
5236
|
+
summary: "Move the design to Ungrouped (groupId: null)"
|
|
5237
|
+
},
|
|
4286
5238
|
INPUT_FLAG
|
|
4287
5239
|
],
|
|
4288
5240
|
examples: [
|
|
4289
5241
|
'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --prompt "Tighten the hero copy"',
|
|
4290
|
-
'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --subject-line "Your September roundup"'
|
|
5242
|
+
'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --subject-line "Your September roundup"',
|
|
5243
|
+
'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --title "Fall sale v2" --group-id grp_7Hq2',
|
|
5244
|
+
"brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --ungroup"
|
|
4291
5245
|
],
|
|
4292
5246
|
run: async ({ ctx, args, flags }) => {
|
|
5247
|
+
const groupId = flagString(flags.groupId);
|
|
5248
|
+
if (groupId !== void 0 && flags.ungroup === true) {
|
|
5249
|
+
throw new CliUsageError(
|
|
5250
|
+
"--group-id and --ungroup conflict: pick one group move."
|
|
5251
|
+
);
|
|
5252
|
+
}
|
|
4293
5253
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
4294
5254
|
const input = mergeInput(base, {
|
|
4295
5255
|
prompt: flagString(flags.prompt),
|
|
4296
5256
|
emailVersionId: flagString(flags.emailVersionId),
|
|
4297
5257
|
contentUrls: toStringArray(flags.contentUrls),
|
|
4298
|
-
subjectLine: flagString(flags.subjectLine)
|
|
5258
|
+
subjectLine: flagString(flags.subjectLine),
|
|
5259
|
+
title: flagString(flags.title),
|
|
5260
|
+
groupId: flags.ungroup === true ? null : groupId
|
|
4299
5261
|
});
|
|
4300
|
-
const isPromptEdit =
|
|
4301
|
-
const
|
|
4302
|
-
|
|
5262
|
+
const isPromptEdit = isText(input.prompt);
|
|
5263
|
+
const envelope = ENVELOPE_FIELDS.filter(
|
|
5264
|
+
(field) => isText(input[field]) || field === "groupId" && input[field] === null
|
|
5265
|
+
);
|
|
5266
|
+
if (!isPromptEdit && envelope.length === 0) {
|
|
4303
5267
|
throw new CliUsageError(
|
|
4304
|
-
"--prompt or --subject-line
|
|
5268
|
+
"Pass --prompt, or at least one of --subject-line, --title, --group-id or --ungroup (or those fields via --input)."
|
|
4305
5269
|
);
|
|
4306
5270
|
}
|
|
4307
5271
|
progress(
|
|
4308
5272
|
ctx,
|
|
4309
|
-
isPromptEdit ? "Editing email\u2026 (typically 30-90s)" : "Setting the subject line\u2026"
|
|
5273
|
+
isPromptEdit ? "Editing email\u2026 (typically 30-90s)" : envelope.length === 1 && envelope[0] === "subjectLine" ? "Setting the subject line\u2026" : "Updating the design (no AI run)\u2026"
|
|
4310
5274
|
);
|
|
4311
5275
|
const result = await ctx.client().emails.edit(
|
|
4312
5276
|
asSdkInput({ ...input, emailId: args.emailId ?? "" }),
|
|
@@ -4327,12 +5291,16 @@ var emailsExportCommand = defineCommand({
|
|
|
4327
5291
|
flags: [
|
|
4328
5292
|
{
|
|
4329
5293
|
flag: "--provider <provider>",
|
|
4330
|
-
summary: "Connected ESP: braze, hubspot, klaviyo, mailchimp, iterable, postmark, onesignal, mailgun, sendgrid"
|
|
5294
|
+
summary: "Connected ESP: braze, brevo, hubspot, klaviyo, mailchimp, mailjet, iterable, postmark, onesignal, mailgun, sendgrid"
|
|
4331
5295
|
},
|
|
4332
5296
|
{
|
|
4333
5297
|
flag: "--template-name <name>",
|
|
4334
5298
|
summary: "Template name in the ESP (default: the email title)"
|
|
4335
5299
|
},
|
|
5300
|
+
{
|
|
5301
|
+
flag: "--sender-email <email>",
|
|
5302
|
+
summary: "Brevo or Mailjet: the active sender to use (omit when the account has exactly one)"
|
|
5303
|
+
},
|
|
4336
5304
|
{
|
|
4337
5305
|
flag: "--dry-run",
|
|
4338
5306
|
summary: "Validate design, ownership, and ESP connection without creating a template"
|
|
@@ -4347,18 +5315,20 @@ var emailsExportCommand = defineCommand({
|
|
|
4347
5315
|
const provider = flagString(flags.provider);
|
|
4348
5316
|
if (provider === void 0) {
|
|
4349
5317
|
throw new CliUsageError(
|
|
4350
|
-
"--provider is required: braze, hubspot, klaviyo, mailchimp, iterable, postmark, onesignal, mailgun, or sendgrid."
|
|
5318
|
+
"--provider is required: braze, brevo, hubspot, klaviyo, mailchimp, mailjet, iterable, postmark, onesignal, mailgun, or sendgrid."
|
|
4351
5319
|
);
|
|
4352
5320
|
}
|
|
4353
5321
|
const templateName = flagString(flags.templateName);
|
|
5322
|
+
const senderEmail = flagString(flags.senderEmail);
|
|
4354
5323
|
return {
|
|
4355
5324
|
data: await ctx.client().emails.export(
|
|
4356
5325
|
asSdkInput({
|
|
4357
5326
|
emailId: args.emailId ?? "",
|
|
4358
5327
|
provider,
|
|
4359
5328
|
...templateName === void 0 ? {} : { templateName },
|
|
5329
|
+
...senderEmail === void 0 ? {} : { senderEmail },
|
|
4360
5330
|
// The spec field is snake_case, unlike the rest of the API surface.
|
|
4361
|
-
...flags.dryRun === true ? {
|
|
5331
|
+
...flags.dryRun === true ? { dryRun: true } : {}
|
|
4362
5332
|
}),
|
|
4363
5333
|
requestOptions(flags)
|
|
4364
5334
|
)
|
|
@@ -4427,10 +5397,9 @@ var emailsGenerateCommand = defineCommand({
|
|
|
4427
5397
|
// src/commands/emails/get.ts
|
|
4428
5398
|
var emailsGetCommand = defineCommand({
|
|
4429
5399
|
path: ["emails", "get"],
|
|
4430
|
-
summary: "Fetch one email design by id",
|
|
4431
|
-
sdkMethod:
|
|
4432
|
-
|
|
4433
|
-
route: { method: "GET", path: "/v1/emails" },
|
|
5400
|
+
summary: "Fetch one email design by id \u2014 the bare row",
|
|
5401
|
+
sdkMethod: "emails.get",
|
|
5402
|
+
route: { method: "GET", path: "/v1/emails/{emailId}" },
|
|
4434
5403
|
commandClass: "read",
|
|
4435
5404
|
args: [
|
|
4436
5405
|
{
|
|
@@ -4442,39 +5411,126 @@ var emailsGetCommand = defineCommand({
|
|
|
4442
5411
|
flags: [
|
|
4443
5412
|
{
|
|
4444
5413
|
flag: "--include <tokens>",
|
|
4445
|
-
summary: "Comma-separated expansions: html,versions"
|
|
5414
|
+
summary: "Comma-separated expansions: html, versions, text, links"
|
|
5415
|
+
},
|
|
5416
|
+
{
|
|
5417
|
+
flag: "--email-version-id <emailVersionId>",
|
|
5418
|
+
summary: "Read this saved version instead of the current head (ids from --include versions)"
|
|
5419
|
+
},
|
|
5420
|
+
{
|
|
5421
|
+
flag: "--run-id <runId>",
|
|
5422
|
+
summary: "Read the version a generate or edit run produced (the runId it returned)"
|
|
4446
5423
|
}
|
|
4447
5424
|
],
|
|
4448
5425
|
examples: [
|
|
4449
5426
|
"brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p",
|
|
4450
|
-
"brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p --include html,versions"
|
|
5427
|
+
"brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p --include html,versions",
|
|
5428
|
+
"brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p --include text,links",
|
|
5429
|
+
"brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p --email-version-id emv_2SmZOWV3ZQ7W5x6g3m4p --include html"
|
|
4451
5430
|
],
|
|
4452
5431
|
run: async ({ ctx, args, flags }) => {
|
|
4453
5432
|
const emailId = args.emailId ?? "";
|
|
4454
5433
|
const include = flagString(flags.include);
|
|
4455
|
-
const
|
|
4456
|
-
|
|
4457
|
-
|
|
5434
|
+
const emailVersionId = flagString(flags.emailVersionId);
|
|
5435
|
+
const runId = flagString(flags.runId);
|
|
5436
|
+
if (emailVersionId !== void 0 && runId !== void 0) {
|
|
5437
|
+
throw new CliUsageError(
|
|
5438
|
+
"Pass --email-version-id or --run-id, not both: each selects the version to read."
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5441
|
+
if (emailVersionId === void 0 && runId === void 0) {
|
|
5442
|
+
return {
|
|
5443
|
+
data: await ctx.client().emails.get(emailId, include === void 0 ? void 0 : { include })
|
|
5444
|
+
};
|
|
5445
|
+
}
|
|
5446
|
+
return {
|
|
5447
|
+
data: await rawRequest(ctx, {
|
|
5448
|
+
method: "GET",
|
|
5449
|
+
path: `/v1/emails/${encodeURIComponent(emailId)}`,
|
|
5450
|
+
query: { include, emailVersionId, runId }
|
|
5451
|
+
})
|
|
5452
|
+
};
|
|
5453
|
+
}
|
|
5454
|
+
});
|
|
5455
|
+
|
|
5456
|
+
// src/commands/emails/get-audit.ts
|
|
5457
|
+
var emailsGetAuditCommand = defineCommand({
|
|
5458
|
+
path: ["emails", "get-audit"],
|
|
5459
|
+
summary: "Read a saved email audit: one page of its findings (free; never reruns the audit)",
|
|
5460
|
+
sdkMethod: null,
|
|
5461
|
+
isRawTransport: true,
|
|
5462
|
+
route: { method: "GET", path: "/v1/emails/audits/{auditId}" },
|
|
5463
|
+
commandClass: "read",
|
|
5464
|
+
args: [
|
|
5465
|
+
{
|
|
5466
|
+
name: "auditId",
|
|
5467
|
+
summary: "The auditId `emails audit` returned (reports are kept 7 days)",
|
|
5468
|
+
isRequired: true
|
|
5469
|
+
}
|
|
5470
|
+
],
|
|
5471
|
+
// Its own page size: a saved audit pages 1-50 findings (default 10), not
|
|
5472
|
+
// the shared list's 1-100.
|
|
5473
|
+
flags: [
|
|
5474
|
+
{ flag: "--limit <n>", summary: "Findings per page, 1-50 (default 10)" },
|
|
5475
|
+
CURSOR_FLAG
|
|
5476
|
+
],
|
|
5477
|
+
examples: [
|
|
5478
|
+
"brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
|
|
5479
|
+
"brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f --limit 20"
|
|
5480
|
+
],
|
|
5481
|
+
// The next page is `--cursor <pagination.cursor>`; `pagination.hasMore`
|
|
5482
|
+
// says whether one exists.
|
|
5483
|
+
run: async ({ ctx, args, flags }) => {
|
|
5484
|
+
const limit = flagInt(flags.limit, "--limit");
|
|
5485
|
+
const body = await rawRequest(ctx, {
|
|
5486
|
+
method: "GET",
|
|
5487
|
+
path: `/v1/emails/audits/${encodeURIComponent(args.auditId ?? "")}`,
|
|
5488
|
+
query: {
|
|
5489
|
+
cursor: flagString(flags.cursor),
|
|
5490
|
+
limit: limit === void 0 ? void 0 : String(limit)
|
|
5491
|
+
}
|
|
4458
5492
|
});
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
5493
|
+
return { data: body };
|
|
5494
|
+
}
|
|
5495
|
+
});
|
|
5496
|
+
|
|
5497
|
+
// src/commands/emails/get-client-preview.ts
|
|
5498
|
+
var emailsGetClientPreviewCommand = defineCommand({
|
|
5499
|
+
path: ["emails", "get-client-preview"],
|
|
5500
|
+
summary: "Poll a client-preview rendering job: per-client screenshot links once it settles (free; never re-renders)",
|
|
5501
|
+
sdkMethod: null,
|
|
5502
|
+
isRawTransport: true,
|
|
5503
|
+
route: { method: "GET", path: "/v1/emails/client-previews/{previewId}" },
|
|
5504
|
+
commandClass: "read",
|
|
5505
|
+
args: [
|
|
5506
|
+
{
|
|
5507
|
+
name: "previewId",
|
|
5508
|
+
summary: "The previewId `emails preview-clients` returned",
|
|
5509
|
+
isRequired: true
|
|
4468
5510
|
}
|
|
4469
|
-
|
|
5511
|
+
],
|
|
5512
|
+
examples: [
|
|
5513
|
+
"brew-cli emails get-client-preview prv_0b7f3c1e-9a2d-4e8b-b6c5-3d1f2a9e8c47",
|
|
5514
|
+
"brew-cli emails get-client-preview prv_0b7f3c1e-9a2d-4e8b-b6c5-3d1f2a9e8c47 --json | jq '.previews[] | {label, status, imageUrl}'"
|
|
5515
|
+
],
|
|
5516
|
+
// While `status` is `queued` or `running`, poll again after
|
|
5517
|
+
// `nextPollAfterMs`. It settles as `completed`, `partially_completed` or
|
|
5518
|
+
// `failed`; each client then carries its `imageUrl`, or a `reason` and
|
|
5519
|
+
// whether it is `retryable`.
|
|
5520
|
+
run: async ({ ctx, args }) => {
|
|
5521
|
+
const body = await rawRequest(ctx, {
|
|
5522
|
+
method: "GET",
|
|
5523
|
+
path: `/v1/emails/client-previews/${encodeURIComponent(args.previewId ?? "")}`
|
|
5524
|
+
});
|
|
5525
|
+
return { data: body };
|
|
4470
5526
|
}
|
|
4471
5527
|
});
|
|
4472
5528
|
|
|
4473
5529
|
// src/commands/emails/get-inbox-placement-results.ts
|
|
4474
5530
|
var emailsGetInboxPlacementResultsCommand = defineCommand({
|
|
4475
5531
|
path: ["emails", "get-inbox-placement-results"],
|
|
4476
|
-
summary: "Inbox placement results: one test with --test-id
|
|
4477
|
-
sdkMethod: "emails.
|
|
5532
|
+
summary: "Inbox placement results: the recent tests, or one test with --test-id",
|
|
5533
|
+
sdkMethod: "emails.inboxPlacementTests.list",
|
|
4478
5534
|
route: { method: "GET", path: "/v1/emails/{emailId}/inbox-placement-tests" },
|
|
4479
5535
|
commandClass: "read",
|
|
4480
5536
|
args: [
|
|
@@ -4486,22 +5542,38 @@ var emailsGetInboxPlacementResultsCommand = defineCommand({
|
|
|
4486
5542
|
],
|
|
4487
5543
|
flags: [
|
|
4488
5544
|
{
|
|
5545
|
+
// The list no longer filters by test id: --test-id reads the real
|
|
5546
|
+
// detail route, the same one `emails inbox-placement-tests get` binds.
|
|
4489
5547
|
flag: "--test-id <id>",
|
|
4490
5548
|
summary: "One test: live status + per-provider placement (re-poll ~30s until completed)"
|
|
4491
|
-
}
|
|
5549
|
+
},
|
|
5550
|
+
LIMIT_FLAG,
|
|
5551
|
+
CURSOR_FLAG,
|
|
5552
|
+
INPUT_FLAG
|
|
4492
5553
|
],
|
|
4493
5554
|
examples: [
|
|
4494
5555
|
"brew-cli emails get-inbox-placement-results eml_2SmZOWV3ZQ7W5x6g3m4p",
|
|
4495
5556
|
"brew-cli emails get-inbox-placement-results eml_2SmZOWV3ZQ7W5x6g3m4p --test-id ibp_2f1c9d8a"
|
|
4496
5557
|
],
|
|
4497
|
-
run: async ({ ctx, args, flags }) =>
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
}
|
|
4503
|
-
|
|
4504
|
-
|
|
5558
|
+
run: async ({ ctx, args, flags }) => {
|
|
5559
|
+
const emailId = args.emailId ?? "";
|
|
5560
|
+
const testId = flagString(flags.testId);
|
|
5561
|
+
const inboxPlacementTests = ctx.client().emails.inboxPlacementTests;
|
|
5562
|
+
if (testId !== void 0) {
|
|
5563
|
+
return { data: await inboxPlacementTests.get(emailId, testId) };
|
|
5564
|
+
}
|
|
5565
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
5566
|
+
const input = mergeInput(base, {
|
|
5567
|
+
emailId,
|
|
5568
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
5569
|
+
cursor: flagString(flags.cursor)
|
|
5570
|
+
});
|
|
5571
|
+
return {
|
|
5572
|
+
data: await inboxPlacementTests.list(
|
|
5573
|
+
asSdkInput(input)
|
|
5574
|
+
)
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
4505
5577
|
});
|
|
4506
5578
|
|
|
4507
5579
|
// src/commands/emails/groups/create.ts
|
|
@@ -4558,6 +5630,29 @@ var emailsGroupsDeleteCommand = defineCommand({
|
|
|
4558
5630
|
})
|
|
4559
5631
|
});
|
|
4560
5632
|
|
|
5633
|
+
// src/commands/emails/groups/get.ts
|
|
5634
|
+
var emailsGroupsGetCommand = defineCommand({
|
|
5635
|
+
path: ["emails", "groups", "get"],
|
|
5636
|
+
summary: "Fetch one email group by id \u2014 the bare row",
|
|
5637
|
+
sdkMethod: "emailGroups.get",
|
|
5638
|
+
route: { method: "GET", path: "/v1/email-groups/{groupId}" },
|
|
5639
|
+
commandClass: "read",
|
|
5640
|
+
args: [
|
|
5641
|
+
{
|
|
5642
|
+
name: "groupId",
|
|
5643
|
+
summary: "Group id (`grp_\u2026`, or the literal `ungrouped`)",
|
|
5644
|
+
isRequired: true
|
|
5645
|
+
}
|
|
5646
|
+
],
|
|
5647
|
+
examples: [
|
|
5648
|
+
"brew-cli emails groups get grp_2f1c9d8a",
|
|
5649
|
+
"brew-cli emails groups get ungrouped"
|
|
5650
|
+
],
|
|
5651
|
+
run: async ({ ctx, args }) => ({
|
|
5652
|
+
data: await ctx.client().emailGroups.get(args.groupId ?? "")
|
|
5653
|
+
})
|
|
5654
|
+
});
|
|
5655
|
+
|
|
4561
5656
|
// src/commands/emails/groups/list.ts
|
|
4562
5657
|
var emailsGroupsListCommand = defineCommand({
|
|
4563
5658
|
path: ["emails", "groups", "list"],
|
|
@@ -4715,8 +5810,16 @@ var emailsImportFigmaCommand = defineCommand({
|
|
|
4715
5810
|
summary: "Representation returned in content: jsx (default) or html"
|
|
4716
5811
|
},
|
|
4717
5812
|
{
|
|
4718
|
-
flag: "--subject-line <text>",
|
|
4719
|
-
summary: "The design's default inbox subject line"
|
|
5813
|
+
flag: "--subject-line <text>",
|
|
5814
|
+
summary: "The design's default inbox subject line"
|
|
5815
|
+
},
|
|
5816
|
+
{
|
|
5817
|
+
flag: "--group-id <groupId>",
|
|
5818
|
+
summary: "File the design under an existing group (grp_\u2026), or ungrouped"
|
|
5819
|
+
},
|
|
5820
|
+
{
|
|
5821
|
+
flag: "--group-name <name>",
|
|
5822
|
+
summary: "File the design under a group found (or created) by this name; not with --group-id"
|
|
4720
5823
|
},
|
|
4721
5824
|
IDEMPOTENCY_FLAG
|
|
4722
5825
|
],
|
|
@@ -4734,13 +5837,20 @@ var emailsImportFigmaCommand = defineCommand({
|
|
|
4734
5837
|
const title = flagString(flags.title);
|
|
4735
5838
|
const format = flagString(flags.format);
|
|
4736
5839
|
const subjectLine = flagString(flags.subjectLine);
|
|
5840
|
+
const groupId = flagString(flags.groupId);
|
|
5841
|
+
const groupName = flagString(flags.groupName);
|
|
5842
|
+
if (groupId !== void 0 && groupName !== void 0) {
|
|
5843
|
+
throw new CliUsageError("Pass --group-id or --group-name, not both.");
|
|
5844
|
+
}
|
|
4737
5845
|
return {
|
|
4738
5846
|
data: await ctx.client().emails.importFigma(
|
|
4739
5847
|
asSdkInput({
|
|
4740
5848
|
figmaUrl,
|
|
4741
5849
|
...title === void 0 ? {} : { title },
|
|
4742
5850
|
...format === void 0 ? {} : { format },
|
|
4743
|
-
...subjectLine === void 0 ? {} : { subjectLine }
|
|
5851
|
+
...subjectLine === void 0 ? {} : { subjectLine },
|
|
5852
|
+
...groupId === void 0 ? {} : { groupId },
|
|
5853
|
+
...groupName === void 0 ? {} : { groupName }
|
|
4744
5854
|
}),
|
|
4745
5855
|
requestOptions(flags)
|
|
4746
5856
|
)
|
|
@@ -4748,53 +5858,108 @@ var emailsImportFigmaCommand = defineCommand({
|
|
|
4748
5858
|
}
|
|
4749
5859
|
});
|
|
4750
5860
|
|
|
5861
|
+
// src/commands/emails/inbox-placement-tests/get.ts
|
|
5862
|
+
var emailsInboxPlacementTestsGetCommand = defineCommand({
|
|
5863
|
+
path: ["emails", "inbox-placement-tests", "get"],
|
|
5864
|
+
summary: "Fetch one inbox-placement (seed) test \u2014 the bare row, re-poll ~30s until completed",
|
|
5865
|
+
sdkMethod: "emails.inboxPlacementTests.get",
|
|
5866
|
+
route: {
|
|
5867
|
+
method: "GET",
|
|
5868
|
+
path: "/v1/emails/{emailId}/inbox-placement-tests/{testId}"
|
|
5869
|
+
},
|
|
5870
|
+
commandClass: "read",
|
|
5871
|
+
args: [
|
|
5872
|
+
{
|
|
5873
|
+
name: "emailId",
|
|
5874
|
+
summary: "Design id the test ran on",
|
|
5875
|
+
isRequired: true
|
|
5876
|
+
},
|
|
5877
|
+
{
|
|
5878
|
+
name: "testId",
|
|
5879
|
+
summary: "Test id returned by `emails create-inbox-placement-test`",
|
|
5880
|
+
isRequired: true
|
|
5881
|
+
}
|
|
5882
|
+
],
|
|
5883
|
+
examples: [
|
|
5884
|
+
"brew-cli emails inbox-placement-tests get eml_2SmZOWV3ZQ7W5x6g3m4p ibp_2f1c9d8a"
|
|
5885
|
+
],
|
|
5886
|
+
run: async ({ ctx, args }) => ({
|
|
5887
|
+
data: await ctx.client().emails.inboxPlacementTests.get(args.emailId ?? "", args.testId ?? "")
|
|
5888
|
+
})
|
|
5889
|
+
});
|
|
5890
|
+
|
|
4751
5891
|
// src/commands/emails/list.ts
|
|
4752
5892
|
var emailsListCommand = defineCommand({
|
|
4753
5893
|
path: ["emails", "list"],
|
|
4754
|
-
summary: "List email designs
|
|
5894
|
+
summary: "List email designs; one design is `emails get`",
|
|
4755
5895
|
sdkMethod: "emails.list",
|
|
4756
5896
|
route: { method: "GET", path: "/v1/emails" },
|
|
4757
5897
|
commandClass: "read",
|
|
4758
5898
|
flags: [
|
|
4759
5899
|
{
|
|
4760
5900
|
flag: "--status <status>",
|
|
4761
|
-
summary: "Filter by status:
|
|
5901
|
+
summary: "Filter by status: generating | ready | failed"
|
|
4762
5902
|
},
|
|
4763
5903
|
{
|
|
4764
5904
|
flag: "--group-id <groupId>",
|
|
4765
5905
|
summary: "Filter by one group id; use ungrouped for no saved group"
|
|
4766
5906
|
},
|
|
4767
5907
|
{
|
|
4768
|
-
flag: "--sort <field>",
|
|
4769
|
-
summary: "
|
|
5908
|
+
flag: "--sort-by <field>",
|
|
5909
|
+
summary: "Timestamp the page is ordered by and that --since/--until bound: updatedAt (default) | createdAt"
|
|
5910
|
+
},
|
|
5911
|
+
{
|
|
5912
|
+
flag: "--since <iso>",
|
|
5913
|
+
summary: "Inclusive lower bound on the --sort-by timestamp (ISO-8601)"
|
|
5914
|
+
},
|
|
5915
|
+
{
|
|
5916
|
+
flag: "--until <iso>",
|
|
5917
|
+
summary: "Inclusive upper bound on the --sort-by timestamp (ISO-8601)"
|
|
5918
|
+
},
|
|
5919
|
+
{ flag: "--sort <field>", summary: "0.6 alias of --sort-by" },
|
|
5920
|
+
{
|
|
5921
|
+
flag: "--order <order>",
|
|
5922
|
+
summary: "0.6 flag: pages are newest first; only desc is accepted"
|
|
5923
|
+
},
|
|
5924
|
+
{
|
|
5925
|
+
flag: "--created-at-from <iso>",
|
|
5926
|
+
summary: "0.6 alias of --sort-by createdAt --since <iso>"
|
|
5927
|
+
},
|
|
5928
|
+
{
|
|
5929
|
+
flag: "--created-at-to <iso>",
|
|
5930
|
+
summary: "0.6 alias of --sort-by createdAt --until <iso>"
|
|
5931
|
+
},
|
|
5932
|
+
{
|
|
5933
|
+
flag: "--updated-at-from <iso>",
|
|
5934
|
+
summary: "0.6 alias of --sort-by updatedAt --since <iso>"
|
|
5935
|
+
},
|
|
5936
|
+
{
|
|
5937
|
+
flag: "--updated-at-to <iso>",
|
|
5938
|
+
summary: "0.6 alias of --sort-by updatedAt --until <iso>"
|
|
4770
5939
|
},
|
|
4771
|
-
{ flag: "--order <order>", summary: "Sort order: asc | desc" },
|
|
4772
|
-
{ flag: "--created-at-from <iso>", summary: "Created at or after (ISO)" },
|
|
4773
|
-
{ flag: "--created-at-to <iso>", summary: "Created at or before (ISO)" },
|
|
4774
|
-
{ flag: "--updated-at-from <iso>", summary: "Updated at or after (ISO)" },
|
|
4775
|
-
{ flag: "--updated-at-to <iso>", summary: "Updated at or before (ISO)" },
|
|
4776
5940
|
LIMIT_FLAG,
|
|
4777
5941
|
CURSOR_FLAG,
|
|
4778
5942
|
ALL_FLAG,
|
|
4779
5943
|
INPUT_FLAG
|
|
4780
5944
|
],
|
|
4781
5945
|
examples: [
|
|
4782
|
-
"brew-cli emails list --status
|
|
4783
|
-
"brew-cli emails list --group-id ungrouped
|
|
4784
|
-
"brew-cli emails list --
|
|
5946
|
+
"brew-cli emails list --status ready --limit 10",
|
|
5947
|
+
"brew-cli emails list --group-id ungrouped",
|
|
5948
|
+
"brew-cli emails list --sort-by createdAt --since 2026-08-01T00:00:00Z",
|
|
4785
5949
|
"brew-cli emails list --all --json"
|
|
4786
5950
|
],
|
|
4787
5951
|
run: async ({ ctx, flags }) => {
|
|
5952
|
+
const legacy = legacyWindow(
|
|
5953
|
+
flags,
|
|
5954
|
+
flagString(flags.sortBy) ?? flagString(flags.sort)
|
|
5955
|
+
);
|
|
4788
5956
|
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
4789
5957
|
const input = mergeInput(base, {
|
|
4790
5958
|
status: flagString(flags.status),
|
|
4791
5959
|
groupId: flagString(flags.groupId),
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
createdAtTo: flagString(flags.createdAtTo),
|
|
4796
|
-
updatedAtFrom: flagString(flags.updatedAtFrom),
|
|
4797
|
-
updatedAtTo: flagString(flags.updatedAtTo),
|
|
5960
|
+
sortBy: flagString(flags.sortBy) ?? flagString(flags.sort) ?? legacy.sortBy,
|
|
5961
|
+
from: flagString(flags.since) ?? legacy.from,
|
|
5962
|
+
to: flagString(flags.until) ?? legacy.to,
|
|
4798
5963
|
limit: flagInt(flags.limit, "--limit"),
|
|
4799
5964
|
cursor: flagString(flags.cursor)
|
|
4800
5965
|
});
|
|
@@ -4818,6 +5983,40 @@ var emailsListCommand = defineCommand({
|
|
|
4818
5983
|
return { data: result, human: renderEmails(result.data) };
|
|
4819
5984
|
}
|
|
4820
5985
|
});
|
|
5986
|
+
function legacyWindow(flags, explicitSortBy) {
|
|
5987
|
+
const order = flagString(flags.order);
|
|
5988
|
+
if (order !== void 0 && order !== "desc") {
|
|
5989
|
+
throw new CliUsageError(
|
|
5990
|
+
"GET /v1/emails pages newest first only; --order asc has no equivalent."
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
const created = {
|
|
5994
|
+
from: flagString(flags.createdAtFrom),
|
|
5995
|
+
to: flagString(flags.createdAtTo)
|
|
5996
|
+
};
|
|
5997
|
+
const updated = {
|
|
5998
|
+
from: flagString(flags.updatedAtFrom),
|
|
5999
|
+
to: flagString(flags.updatedAtTo)
|
|
6000
|
+
};
|
|
6001
|
+
const hasCreated = created.from !== void 0 || created.to !== void 0;
|
|
6002
|
+
const hasUpdated = updated.from !== void 0 || updated.to !== void 0;
|
|
6003
|
+
if (hasCreated && hasUpdated) {
|
|
6004
|
+
throw new CliUsageError(
|
|
6005
|
+
"The API bounds one timestamp per page: pass --created-at-* or --updated-at-*, not both (or --sort-by with --since/--until)."
|
|
6006
|
+
);
|
|
6007
|
+
}
|
|
6008
|
+
if (!(hasCreated || hasUpdated)) {
|
|
6009
|
+
return { sortBy: void 0, from: void 0, to: void 0 };
|
|
6010
|
+
}
|
|
6011
|
+
const column = hasCreated ? "createdAt" : "updatedAt";
|
|
6012
|
+
if (explicitSortBy !== void 0 && explicitSortBy !== column) {
|
|
6013
|
+
const prefix = hasCreated ? "--created-at-*" : "--updated-at-*";
|
|
6014
|
+
throw new CliUsageError(
|
|
6015
|
+
`${prefix} bounds ${column}, but the page is ordered by ${explicitSortBy}; the API bounds the --sort-by timestamp only.`
|
|
6016
|
+
);
|
|
6017
|
+
}
|
|
6018
|
+
return { sortBy: column, ...hasCreated ? created : updated };
|
|
6019
|
+
}
|
|
4821
6020
|
function renderEmails(rows) {
|
|
4822
6021
|
if (rows.length === 0) {
|
|
4823
6022
|
return "No email designs found.";
|
|
@@ -4834,7 +6033,7 @@ function renderEmails(rows) {
|
|
|
4834
6033
|
// src/commands/emails/preview-clients.ts
|
|
4835
6034
|
var emailsPreviewClientsCommand = defineCommand({
|
|
4836
6035
|
path: ["emails", "preview-clients"],
|
|
4837
|
-
summary: "
|
|
6036
|
+
summary: "Start a rendering job across real email clients (10 credits); poll it with `emails get-client-preview`",
|
|
4838
6037
|
sdkMethod: "emails.previewClients",
|
|
4839
6038
|
route: { method: "POST", path: "/v1/emails/{emailId}/client-previews" },
|
|
4840
6039
|
commandClass: "write",
|
|
@@ -4847,25 +6046,49 @@ var emailsPreviewClientsCommand = defineCommand({
|
|
|
4847
6046
|
flag: "--clients <ids...>",
|
|
4848
6047
|
summary: "Client id(s) to render, repeatable (e.g. applemail16 iphone16_18); default: a popular spread"
|
|
4849
6048
|
},
|
|
6049
|
+
{
|
|
6050
|
+
flag: "--email-version-id <id>",
|
|
6051
|
+
summary: "Render this saved version (default: the latest)"
|
|
6052
|
+
},
|
|
4850
6053
|
IDEMPOTENCY_FLAG
|
|
4851
6054
|
],
|
|
4852
6055
|
examples: [
|
|
4853
6056
|
"brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p",
|
|
4854
|
-
"brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --clients applemail16 outlook2021_win11_lm_dt"
|
|
6057
|
+
"brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --clients applemail16 outlook2021_win11_lm_dt",
|
|
6058
|
+
'PREVIEW_ID=$(brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --json | jq -r .previewId) && brew-cli emails get-client-preview "$PREVIEW_ID"'
|
|
4855
6059
|
],
|
|
6060
|
+
// The API answers 202 with the admitted job (or 200 with the existing job
|
|
6061
|
+
// for the same version and clients): `previewId`, its `status` and
|
|
6062
|
+
// per-client progress. Screenshots arrive on the job once it settles, so
|
|
6063
|
+
// `emails get-client-preview <previewId>` is how they are read.
|
|
4856
6064
|
run: async ({ ctx, args, flags }) => {
|
|
4857
6065
|
const clients = toStringArray(flags.clients);
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
}
|
|
4864
|
-
|
|
4865
|
-
)
|
|
4866
|
-
|
|
6066
|
+
const emailVersionId = flagString(flags.emailVersionId);
|
|
6067
|
+
const job = await ctx.client().emails.previewClients(
|
|
6068
|
+
asSdkInput({
|
|
6069
|
+
emailId: args.emailId ?? "",
|
|
6070
|
+
...clients === void 0 ? {} : { clients },
|
|
6071
|
+
...emailVersionId === void 0 ? {} : { emailVersionId }
|
|
6072
|
+
}),
|
|
6073
|
+
requestOptions(flags)
|
|
6074
|
+
);
|
|
6075
|
+
const hint = pollHint(job);
|
|
6076
|
+
if (hint !== void 0) {
|
|
6077
|
+
progress(ctx, hint);
|
|
6078
|
+
}
|
|
6079
|
+
return { data: job };
|
|
4867
6080
|
}
|
|
4868
6081
|
});
|
|
6082
|
+
function pollHint(job) {
|
|
6083
|
+
if (typeof job !== "object" || job === null || !("previewId" in job) || !("status" in job)) {
|
|
6084
|
+
return;
|
|
6085
|
+
}
|
|
6086
|
+
const { previewId, status } = job;
|
|
6087
|
+
if (typeof previewId !== "string" || status !== "queued" && status !== "running") {
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
return `Rendering job ${previewId} is ${status}. Poll it with: brew-cli emails get-client-preview ${previewId}`;
|
|
6091
|
+
}
|
|
4869
6092
|
|
|
4870
6093
|
// src/commands/emails/restore.ts
|
|
4871
6094
|
var emailsRestoreCommand = defineCommand({
|
|
@@ -4879,19 +6102,24 @@ var emailsRestoreCommand = defineCommand({
|
|
|
4879
6102
|
],
|
|
4880
6103
|
// --version is taken by the CLI itself, hence --to-version.
|
|
4881
6104
|
flags: [
|
|
4882
|
-
{
|
|
6105
|
+
{
|
|
6106
|
+
flag: "--to-version <emailVersionId>",
|
|
6107
|
+
summary: "Version id to restore (from `emails get <emailId> --include versions`)"
|
|
6108
|
+
},
|
|
4883
6109
|
IDEMPOTENCY_FLAG
|
|
4884
6110
|
],
|
|
4885
|
-
examples: [
|
|
6111
|
+
examples: [
|
|
6112
|
+
"brew-cli emails restore eml_2SmZOWV3ZQ7W5x6g3m4p --to-version emv_7Hq2"
|
|
6113
|
+
],
|
|
4886
6114
|
run: async ({ ctx, args, flags }) => {
|
|
4887
|
-
const
|
|
4888
|
-
if (
|
|
6115
|
+
const emailVersionId = flagString(flags.toVersion);
|
|
6116
|
+
if (emailVersionId === void 0) {
|
|
4889
6117
|
throw new CliUsageError(
|
|
4890
|
-
"--to-version is required (see `brew-cli emails get <emailId> --include versions`)."
|
|
6118
|
+
"--to-version is required (a version id; see `brew-cli emails get <emailId> --include versions`)."
|
|
4891
6119
|
);
|
|
4892
6120
|
}
|
|
4893
6121
|
const result = await ctx.client().emails.restore(
|
|
4894
|
-
{ emailId: args.emailId ?? "",
|
|
6122
|
+
{ emailId: args.emailId ?? "", emailVersionId },
|
|
4895
6123
|
requestOptions(flags)
|
|
4896
6124
|
);
|
|
4897
6125
|
return { data: result };
|
|
@@ -5061,6 +6289,26 @@ var fieldsDeleteCommand = defineCommand({
|
|
|
5061
6289
|
})
|
|
5062
6290
|
});
|
|
5063
6291
|
|
|
6292
|
+
// src/commands/fields/get.ts
|
|
6293
|
+
var fieldsGetCommand = defineCommand({
|
|
6294
|
+
path: ["fields", "get"],
|
|
6295
|
+
summary: "Fetch one contact field definition by name \u2014 the bare row",
|
|
6296
|
+
sdkMethod: "fields.get",
|
|
6297
|
+
route: { method: "GET", path: "/v1/fields/{fieldName}" },
|
|
6298
|
+
commandClass: "read",
|
|
6299
|
+
args: [
|
|
6300
|
+
{
|
|
6301
|
+
name: "fieldName",
|
|
6302
|
+
summary: "Field name (a core column or a custom field)",
|
|
6303
|
+
isRequired: true
|
|
6304
|
+
}
|
|
6305
|
+
],
|
|
6306
|
+
examples: ["brew-cli fields get loyalty_tier"],
|
|
6307
|
+
run: async ({ ctx, args }) => ({
|
|
6308
|
+
data: await ctx.client().fields.get(args.fieldName ?? "")
|
|
6309
|
+
})
|
|
6310
|
+
});
|
|
6311
|
+
|
|
5064
6312
|
// src/commands/fields/list.ts
|
|
5065
6313
|
var fieldsListCommand = defineCommand({
|
|
5066
6314
|
path: ["fields", "list"],
|
|
@@ -5068,9 +6316,221 @@ var fieldsListCommand = defineCommand({
|
|
|
5068
6316
|
sdkMethod: "fields.list",
|
|
5069
6317
|
route: { method: "GET", path: "/v1/fields" },
|
|
5070
6318
|
commandClass: "read",
|
|
5071
|
-
|
|
5072
|
-
|
|
6319
|
+
flags: [
|
|
6320
|
+
{
|
|
6321
|
+
flag: "--include <tokens>",
|
|
6322
|
+
summary: "Expansions: coverage (per-field fill stats: percent of contacts with a value, and top values)"
|
|
6323
|
+
},
|
|
6324
|
+
{
|
|
6325
|
+
flag: "--audience-id <audienceId>",
|
|
6326
|
+
summary: "Scope --include coverage to one saved audience (ignored without it)"
|
|
6327
|
+
},
|
|
6328
|
+
LIMIT_FLAG,
|
|
6329
|
+
CURSOR_FLAG,
|
|
6330
|
+
ALL_FLAG
|
|
6331
|
+
],
|
|
6332
|
+
examples: [
|
|
6333
|
+
"brew-cli fields list",
|
|
6334
|
+
"brew-cli fields list --include coverage",
|
|
6335
|
+
"brew-cli fields list --include coverage --audience-id aud_2SmZOWV3ZQ7W5x6g3m4p --all --json"
|
|
6336
|
+
],
|
|
6337
|
+
run: async ({ ctx, flags }) => {
|
|
6338
|
+
const input = {
|
|
6339
|
+
include: flagString(flags.include),
|
|
6340
|
+
audienceId: flagString(flags.audienceId),
|
|
6341
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
6342
|
+
cursor: flagString(flags.cursor)
|
|
6343
|
+
};
|
|
6344
|
+
const fields = ctx.client().fields;
|
|
6345
|
+
if (flags.all === true) {
|
|
6346
|
+
const rows = await collectAll(
|
|
6347
|
+
ctx,
|
|
6348
|
+
(cursor) => fields.list(
|
|
6349
|
+
asSdkInput({
|
|
6350
|
+
...input,
|
|
6351
|
+
...cursor === void 0 ? {} : { cursor }
|
|
6352
|
+
})
|
|
6353
|
+
)
|
|
6354
|
+
);
|
|
6355
|
+
return {
|
|
6356
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } }
|
|
6357
|
+
};
|
|
6358
|
+
}
|
|
6359
|
+
return { data: await fields.list(asSdkInput(input)) };
|
|
6360
|
+
}
|
|
6361
|
+
});
|
|
6362
|
+
|
|
6363
|
+
// src/commands/flows/get.ts
|
|
6364
|
+
var flowsGetCommand = defineCommand({
|
|
6365
|
+
path: ["flows", "get"],
|
|
6366
|
+
summary: "Fetch one public email flow by brand domain, with every step (day offset, wait, subject, template id)",
|
|
6367
|
+
sdkMethod: "flows.get",
|
|
6368
|
+
route: { method: "GET", path: "/v1/flows/{slug}" },
|
|
6369
|
+
commandClass: "read",
|
|
6370
|
+
args: [
|
|
6371
|
+
{
|
|
6372
|
+
name: "slug",
|
|
6373
|
+
summary: "The brand domain a `flows list` card carries (e.g. brew.new)",
|
|
6374
|
+
isRequired: true
|
|
6375
|
+
}
|
|
6376
|
+
],
|
|
6377
|
+
flags: [
|
|
6378
|
+
{
|
|
6379
|
+
flag: "--include <keys>",
|
|
6380
|
+
summary: "Comma-separated expansions: html (each step\u2019s rendered HTML, best-effort per step)"
|
|
6381
|
+
}
|
|
6382
|
+
],
|
|
6383
|
+
examples: [
|
|
6384
|
+
"brew-cli flows get brew.new",
|
|
6385
|
+
"brew-cli flows get brew.new --include html --json"
|
|
6386
|
+
],
|
|
6387
|
+
run: async ({ ctx, args, flags }) => {
|
|
6388
|
+
const include = flagString(flags.include);
|
|
6389
|
+
const flow = await ctx.client().flows.get(
|
|
6390
|
+
args.slug ?? "",
|
|
6391
|
+
include === void 0 ? void 0 : { include }
|
|
6392
|
+
);
|
|
6393
|
+
return { data: flow, human: renderSteps(flow) };
|
|
6394
|
+
}
|
|
6395
|
+
});
|
|
6396
|
+
function renderSteps(flow) {
|
|
6397
|
+
const header = `${flow.title} \u2014 ${flow.brand.name} (${flow.slug}), ${flow.emailCount} emails over ${flow.spanDays} days${flow.anchor === void 0 ? "" : `, day 0 = ${flow.anchor}`}`;
|
|
6398
|
+
const table = renderTable(
|
|
6399
|
+
(flow.steps ?? []).map((step) => ({
|
|
6400
|
+
order: step.order,
|
|
6401
|
+
day: step.dayOffset,
|
|
6402
|
+
wait: step.delayDays,
|
|
6403
|
+
subject: step.subject,
|
|
6404
|
+
category: step.category,
|
|
6405
|
+
emailId: step.emailId
|
|
6406
|
+
})),
|
|
6407
|
+
[
|
|
6408
|
+
{ key: "order", header: "#" },
|
|
6409
|
+
{ key: "day", header: "DAY" },
|
|
6410
|
+
{ key: "wait", header: "WAIT" },
|
|
6411
|
+
{ key: "subject", header: "SUBJECT" },
|
|
6412
|
+
{ key: "category", header: "CATEGORY" },
|
|
6413
|
+
{ key: "emailId", header: "TEMPLATE" }
|
|
6414
|
+
]
|
|
6415
|
+
);
|
|
6416
|
+
return `${header}
|
|
6417
|
+
|
|
6418
|
+
${table}`;
|
|
6419
|
+
}
|
|
6420
|
+
|
|
6421
|
+
// src/commands/flows/list.ts
|
|
6422
|
+
var flowsListCommand = defineCommand({
|
|
6423
|
+
path: ["flows", "list"],
|
|
6424
|
+
summary: "List public email flows (real multi-step sequences by brand) as cards; `flows get <slug>` reads one",
|
|
6425
|
+
sdkMethod: "flows.list",
|
|
6426
|
+
route: { method: "GET", path: "/v1/flows" },
|
|
6427
|
+
commandClass: "read",
|
|
6428
|
+
flags: [
|
|
6429
|
+
{
|
|
6430
|
+
// --brand is taken by the global brand-selection flag.
|
|
6431
|
+
flag: "--brand-domain <domain>",
|
|
6432
|
+
summary: "Filter the list by brand domain"
|
|
6433
|
+
},
|
|
6434
|
+
{
|
|
6435
|
+
flag: "--category <category>",
|
|
6436
|
+
summary: "Filter by dominant step category (welcome, newsletter, \u2026)"
|
|
6437
|
+
},
|
|
6438
|
+
{
|
|
6439
|
+
flag: "--type <type>",
|
|
6440
|
+
summary: "Filter by how the sequence starts: signup | newsletter"
|
|
6441
|
+
},
|
|
6442
|
+
{
|
|
6443
|
+
flag: "--semantic <text>",
|
|
6444
|
+
summary: "Semantic search over the sequences (relevance order)"
|
|
6445
|
+
},
|
|
6446
|
+
{
|
|
6447
|
+
flag: "--sort <order>",
|
|
6448
|
+
summary: "List order: newest (default) | emails | span | remixes"
|
|
6449
|
+
},
|
|
6450
|
+
{
|
|
6451
|
+
flag: "--slug <domain>",
|
|
6452
|
+
summary: "0.6 shim: read ONE flow with its steps as a single-row page (`flows get <slug>` is the real read)"
|
|
6453
|
+
},
|
|
6454
|
+
{
|
|
6455
|
+
flag: "--include <keys>",
|
|
6456
|
+
summary: "With --slug only: `html` adds each step's rendered HTML"
|
|
6457
|
+
},
|
|
6458
|
+
LIMIT_FLAG,
|
|
6459
|
+
CURSOR_FLAG,
|
|
6460
|
+
ALL_FLAG,
|
|
6461
|
+
INPUT_FLAG
|
|
6462
|
+
],
|
|
6463
|
+
examples: [
|
|
6464
|
+
"brew-cli flows list --type signup --sort emails",
|
|
6465
|
+
"brew-cli flows list --brand-domain brew.new --json",
|
|
6466
|
+
'brew-cli flows list --semantic "developer onboarding drip"'
|
|
6467
|
+
],
|
|
6468
|
+
run: async ({ ctx, flags }) => {
|
|
6469
|
+
const flows = ctx.client().flows;
|
|
6470
|
+
const base = await readJsonFlag(ctx, flags.input, "--input");
|
|
6471
|
+
const slug = flagString(flags.slug) ?? inputField(base, "slug");
|
|
6472
|
+
const include = flagString(flags.include) ?? inputField(base, "include");
|
|
6473
|
+
if (slug !== void 0) {
|
|
6474
|
+
const flow = await flows.get(
|
|
6475
|
+
slug,
|
|
6476
|
+
include === void 0 ? void 0 : { include }
|
|
6477
|
+
);
|
|
6478
|
+
return { data: singleRowPage(flow), human: renderFlows([flow]) };
|
|
6479
|
+
}
|
|
6480
|
+
if (include !== void 0) {
|
|
6481
|
+
throw includeRidesDetailRead("flows get", "--slug");
|
|
6482
|
+
}
|
|
6483
|
+
const input = mergeInput(base, {
|
|
6484
|
+
brand: flagString(flags.brandDomain),
|
|
6485
|
+
category: flagString(flags.category),
|
|
6486
|
+
type: flagString(flags.type),
|
|
6487
|
+
semantic: flagString(flags.semantic),
|
|
6488
|
+
sort: flagString(flags.sort),
|
|
6489
|
+
limit: flagInt(flags.limit, "--limit"),
|
|
6490
|
+
cursor: flagString(flags.cursor)
|
|
6491
|
+
});
|
|
6492
|
+
if (flags.all === true) {
|
|
6493
|
+
const rows = await collectAll(
|
|
6494
|
+
ctx,
|
|
6495
|
+
(cursor) => flows.list(
|
|
6496
|
+
asSdkInput({
|
|
6497
|
+
...input,
|
|
6498
|
+
...cursor === void 0 ? {} : { cursor }
|
|
6499
|
+
})
|
|
6500
|
+
)
|
|
6501
|
+
);
|
|
6502
|
+
return {
|
|
6503
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
6504
|
+
human: renderFlows(rows)
|
|
6505
|
+
};
|
|
6506
|
+
}
|
|
6507
|
+
const result = await flows.list(asSdkInput(input));
|
|
6508
|
+
return { data: result, human: renderFlows(result.data) };
|
|
6509
|
+
}
|
|
5073
6510
|
});
|
|
6511
|
+
function renderFlows(rows) {
|
|
6512
|
+
if (rows.length === 0) {
|
|
6513
|
+
return "No flows found.";
|
|
6514
|
+
}
|
|
6515
|
+
return renderTable(
|
|
6516
|
+
rows.map((row) => ({
|
|
6517
|
+
slug: row.slug,
|
|
6518
|
+
brand: row.brand.name,
|
|
6519
|
+
type: row.type,
|
|
6520
|
+
category: row.category,
|
|
6521
|
+
emails: row.emailCount,
|
|
6522
|
+
spanDays: row.spanDays
|
|
6523
|
+
})),
|
|
6524
|
+
[
|
|
6525
|
+
{ key: "slug", header: "SLUG" },
|
|
6526
|
+
{ key: "brand", header: "BRAND" },
|
|
6527
|
+
{ key: "type", header: "TYPE" },
|
|
6528
|
+
{ key: "category", header: "CATEGORY" },
|
|
6529
|
+
{ key: "emails", header: "EMAILS" },
|
|
6530
|
+
{ key: "spanDays", header: "SPAN (DAYS)" }
|
|
6531
|
+
]
|
|
6532
|
+
);
|
|
6533
|
+
}
|
|
5074
6534
|
|
|
5075
6535
|
// src/commands/health.ts
|
|
5076
6536
|
var healthCommand = defineCommand({
|
|
@@ -5092,9 +6552,31 @@ var integrationsListCommand = defineCommand({
|
|
|
5092
6552
|
sdkMethod: "integrations.list",
|
|
5093
6553
|
route: { method: "GET", path: "/v1/integrations" },
|
|
5094
6554
|
commandClass: "read",
|
|
6555
|
+
flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG],
|
|
5095
6556
|
examples: ["brew-cli integrations list", "brew-cli integrations list --json"],
|
|
5096
|
-
run: async ({ ctx }) => {
|
|
5097
|
-
const
|
|
6557
|
+
run: async ({ ctx, flags }) => {
|
|
6558
|
+
const limit = flagInt(flags.limit, "--limit");
|
|
6559
|
+
const cursor = flagString(flags.cursor);
|
|
6560
|
+
if (limit === void 0 && cursor === void 0 && flags.all !== true) {
|
|
6561
|
+
const result2 = await ctx.client().integrations.list();
|
|
6562
|
+
return { data: result2, human: renderIntegrations(result2.data) };
|
|
6563
|
+
}
|
|
6564
|
+
const page = (after) => rawRequest(ctx, {
|
|
6565
|
+
method: "GET",
|
|
6566
|
+
path: "/v1/integrations",
|
|
6567
|
+
query: {
|
|
6568
|
+
limit: limit === void 0 ? void 0 : String(limit),
|
|
6569
|
+
cursor: after
|
|
6570
|
+
}
|
|
6571
|
+
});
|
|
6572
|
+
if (flags.all === true) {
|
|
6573
|
+
const rows = await collectAll(ctx, (next) => page(next ?? cursor));
|
|
6574
|
+
return {
|
|
6575
|
+
data: { data: rows, pagination: { cursor: null, hasMore: false } },
|
|
6576
|
+
human: renderIntegrations(rows)
|
|
6577
|
+
};
|
|
6578
|
+
}
|
|
6579
|
+
const result = await page(cursor);
|
|
5098
6580
|
return { data: result, human: renderIntegrations(result.data) };
|
|
5099
6581
|
}
|
|
5100
6582
|
});
|
|
@@ -5198,6 +6680,35 @@ var sendsCancelCommand = defineCommand({
|
|
|
5198
6680
|
})
|
|
5199
6681
|
});
|
|
5200
6682
|
|
|
6683
|
+
// src/commands/sends/get.ts
|
|
6684
|
+
var sendsGetCommand = defineCommand({
|
|
6685
|
+
path: ["sends", "get"],
|
|
6686
|
+
summary: "Fetch one send by id \u2014 the bare row with its lifetime stats",
|
|
6687
|
+
sdkMethod: "sends.get",
|
|
6688
|
+
route: { method: "GET", path: "/v1/sends/{sendId}" },
|
|
6689
|
+
commandClass: "read",
|
|
6690
|
+
args: [{ name: "sendId", summary: "Send id to fetch", isRequired: true }],
|
|
6691
|
+
flags: [
|
|
6692
|
+
{
|
|
6693
|
+
flag: "--include <tokens>",
|
|
6694
|
+
summary: "Comma-separated expansions: events"
|
|
6695
|
+
}
|
|
6696
|
+
],
|
|
6697
|
+
examples: [
|
|
6698
|
+
"brew-cli sends get snd_9f2kX",
|
|
6699
|
+
"brew-cli sends get snd_9f2kX --include events"
|
|
6700
|
+
],
|
|
6701
|
+
run: async ({ ctx, args, flags }) => {
|
|
6702
|
+
const include = flagString(flags.include);
|
|
6703
|
+
return {
|
|
6704
|
+
data: await ctx.client().sends.get(
|
|
6705
|
+
args.sendId ?? "",
|
|
6706
|
+
include === void 0 ? void 0 : { include }
|
|
6707
|
+
)
|
|
6708
|
+
};
|
|
6709
|
+
}
|
|
6710
|
+
});
|
|
6711
|
+
|
|
5201
6712
|
// src/commands/sends/pause.ts
|
|
5202
6713
|
var sendsPauseCommand = defineCommand({
|
|
5203
6714
|
path: ["sends", "pause"],
|
|
@@ -5216,7 +6727,7 @@ var sendsPauseCommand = defineCommand({
|
|
|
5216
6727
|
// src/commands/sends/resume.ts
|
|
5217
6728
|
var sendsResumeCommand = defineCommand({
|
|
5218
6729
|
path: ["sends", "resume"],
|
|
5219
|
-
summary: "Resume a paused gradual send (the unsent tail is re-spread)",
|
|
6730
|
+
summary: "Resume a paused gradual send (the unsent tail is re-spread); the send reports `running` again",
|
|
5220
6731
|
sdkMethod: "sends.resume",
|
|
5221
6732
|
route: { method: "POST", path: "/v1/sends/{sendId}/resume" },
|
|
5222
6733
|
commandClass: "write",
|
|
@@ -5228,6 +6739,41 @@ var sendsResumeCommand = defineCommand({
|
|
|
5228
6739
|
})
|
|
5229
6740
|
});
|
|
5230
6741
|
|
|
6742
|
+
// src/commands/templates/get.ts
|
|
6743
|
+
var templatesGetCommand = defineCommand({
|
|
6744
|
+
path: ["templates", "get"],
|
|
6745
|
+
summary: "Fetch one public template: its links and the referenceEmailId to remix; --include html adds its HTML",
|
|
6746
|
+
sdkMethod: null,
|
|
6747
|
+
isRawTransport: true,
|
|
6748
|
+
route: { method: "GET", path: "/v1/templates/{templateId}" },
|
|
6749
|
+
commandClass: "read",
|
|
6750
|
+
args: [
|
|
6751
|
+
{
|
|
6752
|
+
name: "templateId",
|
|
6753
|
+
summary: "Template id: the TEMPLATE column (emailId) of `templates list`",
|
|
6754
|
+
isRequired: true
|
|
6755
|
+
}
|
|
6756
|
+
],
|
|
6757
|
+
flags: [
|
|
6758
|
+
{
|
|
6759
|
+
flag: "--include <tokens>",
|
|
6760
|
+
summary: "Expansions: html (the rendered HTML; a large page arrives as a content.url download link instead)"
|
|
6761
|
+
}
|
|
6762
|
+
],
|
|
6763
|
+
examples: [
|
|
6764
|
+
"brew-cli templates get seed-vercel-newsletter",
|
|
6765
|
+
"brew-cli templates get seed-vercel-newsletter --include html --json"
|
|
6766
|
+
],
|
|
6767
|
+
run: async ({ ctx, args, flags }) => {
|
|
6768
|
+
const body = await rawRequest(ctx, {
|
|
6769
|
+
method: "GET",
|
|
6770
|
+
path: `/v1/templates/${encodeURIComponent(args.templateId ?? "")}`,
|
|
6771
|
+
query: { include: flagString(flags.include) }
|
|
6772
|
+
});
|
|
6773
|
+
return { data: body };
|
|
6774
|
+
}
|
|
6775
|
+
});
|
|
6776
|
+
|
|
5231
6777
|
// src/commands/templates/list.ts
|
|
5232
6778
|
var templatesListCommand = defineCommand({
|
|
5233
6779
|
path: ["templates", "list"],
|
|
@@ -5535,6 +7081,7 @@ var ALL_COMMANDS = [
|
|
|
5535
7081
|
configGetCommand,
|
|
5536
7082
|
configSetCommand,
|
|
5537
7083
|
configUnsetCommand,
|
|
7084
|
+
contactsListCommand,
|
|
5538
7085
|
contactsSearchCommand,
|
|
5539
7086
|
contactsGetCommand,
|
|
5540
7087
|
contactsCountCommand,
|
|
@@ -5546,10 +7093,12 @@ var ALL_COMMANDS = [
|
|
|
5546
7093
|
contactsValidateCommand,
|
|
5547
7094
|
contactsImportCsvCommand,
|
|
5548
7095
|
fieldsListCommand,
|
|
7096
|
+
fieldsGetCommand,
|
|
5549
7097
|
fieldsCreateCommand,
|
|
5550
7098
|
fieldsDeleteCommand,
|
|
5551
7099
|
emailsListCommand,
|
|
5552
7100
|
emailsGroupsListCommand,
|
|
7101
|
+
emailsGroupsGetCommand,
|
|
5553
7102
|
emailsGroupsCreateCommand,
|
|
5554
7103
|
emailsGroupsUpdateCommand,
|
|
5555
7104
|
emailsGroupsDeleteCommand,
|
|
@@ -5563,10 +7112,15 @@ var ALL_COMMANDS = [
|
|
|
5563
7112
|
emailsDeleteCommand,
|
|
5564
7113
|
emailsExportCommand,
|
|
5565
7114
|
emailsAuditCommand,
|
|
7115
|
+
emailsGetAuditCommand,
|
|
5566
7116
|
emailsPreviewClientsCommand,
|
|
7117
|
+
emailsGetClientPreviewCommand,
|
|
5567
7118
|
emailsCreateInboxPlacementTestCommand,
|
|
5568
7119
|
emailsGetInboxPlacementResultsCommand,
|
|
7120
|
+
emailsInboxPlacementTestsGetCommand,
|
|
5569
7121
|
emailsSendCommand,
|
|
7122
|
+
sendsListCommand,
|
|
7123
|
+
sendsGetCommand,
|
|
5570
7124
|
sendsCancelCommand,
|
|
5571
7125
|
sendsPauseCommand,
|
|
5572
7126
|
sendsResumeCommand,
|
|
@@ -5588,6 +7142,7 @@ var ALL_COMMANDS = [
|
|
|
5588
7142
|
automationsTestCommand,
|
|
5589
7143
|
automationsRunCommand,
|
|
5590
7144
|
automationsTriggersListCommand,
|
|
7145
|
+
automationsTriggersGetCommand,
|
|
5591
7146
|
automationsTriggersReadyCommand,
|
|
5592
7147
|
automationsTriggersContractGetCommand,
|
|
5593
7148
|
automationsTriggersContractPutCommand,
|
|
@@ -5599,12 +7154,21 @@ var ALL_COMMANDS = [
|
|
|
5599
7154
|
automationsTriggersDeleteCommand,
|
|
5600
7155
|
automationsTriggersFireCommand,
|
|
5601
7156
|
automationsRunsListCommand,
|
|
7157
|
+
automationsRunsGetCommand,
|
|
7158
|
+
automationsRunsCancelCommand,
|
|
5602
7159
|
automationsAudienceRunsListCommand,
|
|
7160
|
+
automationsAudienceRunsGetCommand,
|
|
7161
|
+
automationsAudienceRunsPauseCommand,
|
|
7162
|
+
automationsAudienceRunsResumeCommand,
|
|
7163
|
+
automationsAudienceRunsCancelCommand,
|
|
5603
7164
|
automationsAudienceRunsControlCommand,
|
|
7165
|
+
automationsTriggerInstancesListCommand,
|
|
7166
|
+
automationsTriggerInstancesGetCommand,
|
|
5604
7167
|
analyticsOverviewCommand,
|
|
5605
7168
|
analyticsCampaignsCommand,
|
|
5606
7169
|
analyticsAutomationsCommand,
|
|
5607
7170
|
analyticsEventsCommand,
|
|
7171
|
+
analyticsEventCountsCommand,
|
|
5608
7172
|
analyticsSendsListCommand,
|
|
5609
7173
|
analyticsSendsGetCommand,
|
|
5610
7174
|
analyticsTriggerInstancesListCommand,
|
|
@@ -5624,12 +7188,20 @@ var ALL_COMMANDS = [
|
|
|
5624
7188
|
domainsHealthCommand,
|
|
5625
7189
|
domainsUpdateCommand,
|
|
5626
7190
|
domainsDeleteCommand,
|
|
7191
|
+
domainsUnsubscribesListCommand,
|
|
7192
|
+
domainsUnsubscribesAddCommand,
|
|
7193
|
+
domainsUnsubscribesRemoveCommand,
|
|
7194
|
+
domainsUnsubscribesImportCommand,
|
|
7195
|
+
domainsUnsubscribesExportCommand,
|
|
5627
7196
|
contentGenerateImageCommand,
|
|
5628
7197
|
contentGifCommand,
|
|
5629
7198
|
contentTransformCommand,
|
|
5630
7199
|
contentHtmlToPngCommand,
|
|
5631
7200
|
contentAddImageCommand,
|
|
5632
7201
|
templatesListCommand,
|
|
7202
|
+
templatesGetCommand,
|
|
7203
|
+
flowsListCommand,
|
|
7204
|
+
flowsGetCommand,
|
|
5633
7205
|
integrationsListCommand,
|
|
5634
7206
|
chatsGetCommand,
|
|
5635
7207
|
healthCommand,
|
|
@@ -5642,7 +7214,8 @@ var ALL_COMMANDS = [
|
|
|
5642
7214
|
|
|
5643
7215
|
// src/cli.ts
|
|
5644
7216
|
var GROUP_SUMMARIES = {
|
|
5645
|
-
analytics: "
|
|
7217
|
+
analytics: "Reports: overview, events, and automation analytics",
|
|
7218
|
+
"audience-runs": "Manual-audience launches: read, pause, resume, cancel",
|
|
5646
7219
|
"api-keys": "Manage organization API keys",
|
|
5647
7220
|
audiences: "Manage audience segments",
|
|
5648
7221
|
automations: "Manage automation graphs, triggers, and runs",
|
|
@@ -5656,15 +7229,17 @@ var GROUP_SUMMARIES = {
|
|
|
5656
7229
|
domains: "Manage sending domains",
|
|
5657
7230
|
emails: "Manage email designs and send campaigns",
|
|
5658
7231
|
fields: "Manage custom contact fields",
|
|
7232
|
+
flows: "Browse public email flows (real multi-step sequences by brand)",
|
|
5659
7233
|
groups: "Manage email folders (groups)",
|
|
5660
7234
|
integrations: "Read the connected-integration catalog",
|
|
5661
|
-
|
|
7235
|
+
"inbox-placement-tests": "Inbox placement (seed) test results",
|
|
7236
|
+
sends: "Read sends, and control one in flight or scheduled",
|
|
5662
7237
|
templates: "Browse the template gallery",
|
|
5663
7238
|
contract: "Stored payload contracts (get, put, validate)",
|
|
5664
7239
|
contracts: "Payload-contract helpers",
|
|
5665
7240
|
triggers: "Manage trigger events",
|
|
5666
|
-
runs: "Automation run history",
|
|
5667
|
-
"trigger-instances": "Fired trigger instances"
|
|
7241
|
+
runs: "Automation run history, and cancel one in-flight run",
|
|
7242
|
+
"trigger-instances": "Fired trigger instances (the inbound-fire audit log)"
|
|
5668
7243
|
};
|
|
5669
7244
|
var AGENT_HELP_FOOTER = `
|
|
5670
7245
|
Environment:
|