@brew.new/cli 0.8.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/dist/bin.js CHANGED
@@ -281,7 +281,7 @@ function shellQuote(token) {
281
281
 
282
282
  // src/version.ts
283
283
  var CLI_NAME = "brew-cli";
284
- var CLI_VERSION = "0.8.0" ;
284
+ var CLI_VERSION = "0.9.0" ;
285
285
  var CONFIG_KEYS = ["apiKey", "brandId", "apiUrl"];
286
286
  function isConfigKey(value) {
287
287
  return CONFIG_KEYS.includes(value);
@@ -653,6 +653,10 @@ var IDEMPOTENCY_FLAG = {
653
653
  flag: "--idempotency-key <key>",
654
654
  summary: "Idempotency-Key for safe retries (auto-generated otherwise)"
655
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
+ };
656
660
  var INPUT_FLAG = {
657
661
  flag: "--input <json>",
658
662
  summary: "Full JSON request body, or - to read stdin (flags override it)"
@@ -857,6 +861,201 @@ var analyticsCampaignsCommand = defineCommand({
857
861
  }
858
862
  });
859
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)."
1019
+ );
1020
+ }
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) };
1034
+ }
1035
+ });
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" }
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}`;
1057
+ }
1058
+
860
1059
  // src/commands/analytics/events.ts
861
1060
  var analyticsEventsCommand = defineCommand({
862
1061
  path: ["analytics", "events"],
@@ -1205,110 +1404,6 @@ var analyticsTriggerInstancesListCommand = defineCommand({
1205
1404
  }
1206
1405
  });
1207
1406
 
1208
- // src/lib/raw-request.ts
1209
- async function rawRequest(ctx, request) {
1210
- const auth = resolveAuth({
1211
- globals: ctx.globals,
1212
- env: ctx.io.env,
1213
- ...request.allowAnonymous === true ? { allowAnonymous: true } : {}
1214
- });
1215
- const hasBody = request.body !== void 0;
1216
- const idempotencyKey = resolveRawIdempotencyKey(
1217
- request.method,
1218
- request.idempotencyKey
1219
- );
1220
- const headers = buildRawHeaders({
1221
- auth,
1222
- path: request.path,
1223
- hasJsonBody: hasBody,
1224
- idempotencyKey
1225
- });
1226
- const url = new URL(`${auth.apiUrl}${request.path}`);
1227
- for (const [key, value] of Object.entries(request.query ?? {})) {
1228
- if (value !== void 0) {
1229
- url.searchParams.set(key, value);
1230
- }
1231
- }
1232
- const response = await fetch(url, {
1233
- method: request.method,
1234
- headers,
1235
- ...hasBody ? { body: JSON.stringify(request.body) } : {},
1236
- ...request.signal === void 0 ? {} : { signal: request.signal }
1237
- });
1238
- const text = await response.text();
1239
- const parsed = tryParseJson(text);
1240
- if (!response.ok) {
1241
- throw responseToApiError(response, parsed);
1242
- }
1243
- if (parsed === void 0) {
1244
- throw new CliApiError({
1245
- status: response.status,
1246
- code: "UNEXPECTED_RESPONSE",
1247
- type: "internal_error",
1248
- message: "The API returned a non-JSON success response."
1249
- });
1250
- }
1251
- return parsed;
1252
- }
1253
- function resolveRawIdempotencyKey(method, provided) {
1254
- if (provided !== void 0 && provided !== "") {
1255
- return provided;
1256
- }
1257
- return method === "POST" ? crypto.randomUUID() : void 0;
1258
- }
1259
- function buildRawHeaders(input) {
1260
- const headers = new Headers({
1261
- authorization: `Bearer ${input.auth.apiKey}`,
1262
- "user-agent": `${CLI_NAME}/${CLI_VERSION}`,
1263
- accept: "application/json, text/plain;q=0.9"
1264
- });
1265
- if (input.hasJsonBody) {
1266
- headers.set("content-type", "application/json");
1267
- }
1268
- if (input.auth.brandId !== void 0 && !isOrgLevelPath(input.path)) {
1269
- headers.set("x-brand-id", input.auth.brandId);
1270
- }
1271
- if (input.idempotencyKey !== void 0 && input.idempotencyKey !== "") {
1272
- headers.set("idempotency-key", input.idempotencyKey);
1273
- }
1274
- return headers;
1275
- }
1276
- function responseToApiError(response, parsed) {
1277
- const requestId = response.headers.get("x-request-id") ?? void 0;
1278
- const record = isRecord2(parsed) ? parsed : void 0;
1279
- const standard = record !== void 0 && isRecord2(record.error) ? record.error : void 0;
1280
- const envelope = standard ?? record;
1281
- const readField = (key) => {
1282
- const value = envelope?.[key];
1283
- return typeof value === "string" ? value : void 0;
1284
- };
1285
- const param = readField("param");
1286
- const suggestion = readField("suggestion") ?? (envelope === void 0 ? void 0 : suggestionForStatus(response.status));
1287
- const docs = readField("docs");
1288
- const details = isRecord2(envelope?.details) ? envelope.details : void 0;
1289
- return new CliApiError({
1290
- status: response.status,
1291
- code: readField("code") ?? "HTTP_ERROR",
1292
- type: readField("type") ?? errorTypeForStatus(response.status),
1293
- message: readField("message") ?? `Request failed with status ${response.status}`,
1294
- ...param === void 0 ? {} : { param },
1295
- ...suggestion === void 0 ? {} : { suggestion },
1296
- ...docs === void 0 ? {} : { docs },
1297
- ...requestId === void 0 ? {} : { requestId },
1298
- ...details === void 0 ? {} : { details },
1299
- ...parsed === void 0 ? {} : { body: parsed }
1300
- });
1301
- }
1302
- function isRecord2(value) {
1303
- return typeof value === "object" && value !== null && !Array.isArray(value);
1304
- }
1305
- function tryParseJson(text) {
1306
- try {
1307
- return JSON.parse(text);
1308
- } catch {
1309
- }
1310
- }
1311
-
1312
1407
  // src/commands/api.ts
1313
1408
  var METHODS = ["GET", "POST", "PATCH", "DELETE"];
1314
1409
  var ANONYMOUS_PATHS = ["/v1/health", "/v1/help", "/v1/llms.txt"];
@@ -1451,7 +1546,9 @@ var apiKeysCreateCommand = defineCommand({
1451
1546
  summary: "Bind the NEW key to this brand id (omit for an organization-wide key); not the acting --brand"
1452
1547
  },
1453
1548
  INPUT_FLAG,
1454
- IDEMPOTENCY_FLAG
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
1455
1552
  ],
1456
1553
  examples: [
1457
1554
  "brew-cli api-keys create --name CI --permissions emails domains",
@@ -1495,9 +1592,31 @@ var apiKeysListCommand = defineCommand({
1495
1592
  sdkMethod: "apiKeys.list",
1496
1593
  route: { method: "GET", path: "/v1/api-keys" },
1497
1594
  commandClass: "read",
1595
+ flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG],
1498
1596
  examples: ["brew-cli api-keys list", "brew-cli api-keys list --json"],
1499
- run: async ({ ctx }) => {
1500
- const result = await ctx.client().apiKeys.list();
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);
1501
1620
  return { data: result, human: renderApiKeys(result.data) };
1502
1621
  }
1503
1622
  });
@@ -3038,21 +3157,37 @@ var brandGetCommand = defineCommand({
3038
3157
  });
3039
3158
 
3040
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
+ };
3041
3164
  var brandGetImagesCommand = defineCommand({
3042
3165
  path: ["brand", "get-images"],
3043
- summary: "Browse or semantically search the brand's image library",
3044
- sdkMethod: "brand.getImages",
3166
+ summary: "Browse or semantically search the brand's assets (logos, brand images, images made with Brew)",
3167
+ sdkMethod: null,
3168
+ isRawTransport: true,
3045
3169
  route: { method: "GET", path: "/v1/brand/images" },
3046
3170
  commandClass: "read",
3047
3171
  flags: [
3048
3172
  {
3049
3173
  flag: "--query <text>",
3050
- summary: "Semantic search over image descriptions"
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"
3051
3187
  },
3052
- { flag: "--type <type>", summary: "Filter by image category" },
3053
3188
  {
3054
3189
  flag: "--aspect-ratio <ratio>",
3055
- summary: "Filter by aspect ratio (e.g. 16:9)"
3190
+ summary: "Retired by the API: rows carry width and height instead of a shape filter"
3056
3191
  },
3057
3192
  LIMIT_FLAG,
3058
3193
  CURSOR_FLAG,
@@ -3061,48 +3196,68 @@ var brandGetImagesCommand = defineCommand({
3061
3196
  ],
3062
3197
  examples: [
3063
3198
  "brew-cli brand get-images",
3064
- 'brew-cli brand get-images --query "team photo" --aspect-ratio 16:9'
3199
+ "brew-cli brand get-images --kind generated --sort oldest --all",
3200
+ 'brew-cli brand get-images --query "team photo" --kind brand'
3065
3201
  ],
3066
3202
  run: async ({ ctx, flags }) => {
3067
3203
  const base = await readJsonFlag(ctx, flags.input, "--input");
3068
3204
  const input = mergeInput(base, {
3069
3205
  q: flagString(flags.query),
3070
- type: flagString(flags.type),
3071
- aspectRatio: flagString(flags.aspectRatio),
3206
+ kind: flagString(flags.kind),
3207
+ sort: flagString(flags.sort),
3072
3208
  limit: flagInt(flags.limit, "--limit"),
3073
- 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 })
3074
3222
  });
3075
- const brand = ctx.client().brand;
3076
3223
  if (flags.all === true) {
3077
- const rows = await collectAll(
3078
- ctx,
3079
- (cursor) => brand.getImages(
3080
- asSdkInput({
3081
- ...input,
3082
- ...cursor === void 0 ? {} : { cursor }
3083
- })
3084
- )
3085
- );
3224
+ const rows = await collectAll(ctx, page);
3086
3225
  return {
3087
3226
  data: { data: rows, pagination: { cursor: null, hasMore: false } },
3088
- human: renderImages(rows)
3227
+ human: renderAssets(rows)
3089
3228
  };
3090
3229
  }
3091
- const result = await brand.getImages(
3092
- asSdkInput(input)
3093
- );
3094
- return { data: result, human: renderImages(result.data) };
3230
+ const result = await page(void 0);
3231
+ return { data: result, human: renderAssets(result.data) };
3095
3232
  }
3096
3233
  });
3097
- function renderImages(rows) {
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);
3238
+ }
3239
+ return query;
3240
+ }
3241
+ function renderAssets(rows) {
3098
3242
  if (rows.length === 0) {
3099
- return "No brand images found.";
3243
+ return "No brand assets found.";
3100
3244
  }
3101
- return renderTable(rows, [
3102
- { key: "url", header: "URL" },
3103
- { key: "category", header: "CATEGORY" },
3104
- { key: "aspectRatio", header: "ASPECT" }
3105
- ]);
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
+ );
3106
3261
  }
3107
3262
 
3108
3263
  // src/commands/brand/update.ts
@@ -3204,10 +3359,43 @@ var brandsListCommand = defineCommand({
3204
3359
  sdkMethod: "brands.list",
3205
3360
  route: { method: "GET", path: "/v1/brands" },
3206
3361
  commandClass: "read",
3207
- examples: ["brew-cli brands list --json"],
3208
- run: async ({ ctx }) => ({
3209
- data: await ctx.client().brands.list()
3210
- })
3362
+ flags: [
3363
+ {
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
3370
+ ],
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
+ }
3211
3399
  });
3212
3400
 
3213
3401
  // src/commands/chats/get.ts
@@ -3439,35 +3627,65 @@ var contactsGetCommand = defineCommand({
3439
3627
  // src/commands/contacts/import-csv.ts
3440
3628
  var contactsImportCsvCommand = defineCommand({
3441
3629
  path: ["contacts", "import-csv"],
3442
- 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)",
3443
3631
  sdkMethod: "contacts.importCsv",
3444
3632
  route: { method: "POST", path: "/v1/contacts/import-csv" },
3445
3633
  commandClass: "write",
3446
3634
  flags: [
3447
- { flag: "--file <path>", summary: "CSV file to import, or - for stdin" },
3635
+ {
3636
+ flag: "--file <path>",
3637
+ summary: "CSV file to import, or - for stdin (or csv in --input)"
3638
+ },
3448
3639
  {
3449
3640
  flag: "--mapping <pairs...>",
3450
3641
  summary: "Column mapping csvColumn=fieldName, repeatable"
3451
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,
3452
3656
  IDEMPOTENCY_FLAG
3453
3657
  ],
3454
3658
  examples: [
3455
3659
  "brew-cli contacts import-csv --file contacts.csv",
3456
- "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"
3457
3662
  ],
3458
3663
  run: async ({ ctx, flags }) => {
3459
- const csv = await readTextFlag(ctx, flags.file, "--file");
3460
- if (csv === void 0 || csv.trim() === "") {
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() === "") {
3461
3676
  throw new CliUsageError(
3462
- "--file is required (a CSV path, or - for stdin)."
3677
+ "Pass the CSV with --file (a path, or - for stdin) or as csv in --input."
3463
3678
  );
3464
3679
  }
3465
- const mapping = parseKeyValues(flags.mapping, "--mapping");
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
+ }
3466
3687
  const result = await ctx.client().contacts.importCsv(
3467
- asSdkInput({
3468
- csv,
3469
- ...mapping === void 0 ? {} : { mapping }
3470
- }),
3688
+ asSdkInput(input),
3471
3689
  requestOptions(flags)
3472
3690
  );
3473
3691
  return { data: result };
@@ -4071,14 +4289,17 @@ var contractsInferCommand = defineCommand({
4071
4289
  examples: [
4072
4290
  `brew-cli contracts infer --input '{"email":"jane@example.com","order":{"total":9.5}}'`
4073
4291
  ],
4074
- // Accepts either the bare example object or `{ example: {...} }`.
4075
- // Un-inferable spots (nulls, empty arrays) come back under `issues`.
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`.
4076
4296
  run: async ({ ctx, flags }) => {
4077
4297
  const input = mergeInput(
4078
4298
  await readJsonFlag(ctx, flags.input, "--input"),
4079
4299
  {}
4080
4300
  );
4081
- const example = input.example ?? input;
4301
+ const isEnvelope = input.example !== void 0;
4302
+ const example = isEnvelope ? input.example : input;
4082
4303
  if (typeof example !== "object" || example === null || Array.isArray(example) || Object.keys(example).length === 0) {
4083
4304
  throw new CliUsageError(
4084
4305
  "--input with a non-empty example object is required (the JSON your system sends)."
@@ -4087,7 +4308,10 @@ var contractsInferCommand = defineCommand({
4087
4308
  const body = await rawRequest(ctx, {
4088
4309
  method: "POST",
4089
4310
  path: "/v1/payload-contracts/infer",
4090
- body: { example }
4311
+ body: {
4312
+ example,
4313
+ ...isEnvelope && input.subjectKind !== void 0 ? { subjectKind: input.subjectKind } : {}
4314
+ }
4091
4315
  });
4092
4316
  return { data: body };
4093
4317
  }
@@ -4139,6 +4363,10 @@ var SDK_SKIP_LIST = [
4139
4363
  sdkPath: "automations.triggers.validatePayload",
4140
4364
  reason: "covered by `automations triggers contract validate` (raw route, bound pre-SDK-v9)"
4141
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
+ },
4142
4370
  {
4143
4371
  sdkPath: "payloadContracts.infer",
4144
4372
  reason: "covered by `contracts infer` (raw route, bound pre-SDK-v9)"
@@ -4513,6 +4741,194 @@ function renderDomains(rows) {
4513
4741
  ]);
4514
4742
  }
4515
4743
 
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" },
4751
+ commandClass: "write",
4752
+ args: [
4753
+ { name: "domainId", summary: "Marketing domain id", isRequired: true }
4754
+ ],
4755
+ flags: [
4756
+ {
4757
+ flag: "--email <addresses...>",
4758
+ summary: "Address to suppress, repeatable (up to 1,000)"
4759
+ },
4760
+ IDEMPOTENCY_FLAG
4761
+ ],
4762
+ examples: [
4763
+ "brew-cli domains unsubscribes add dom_123 --email ada@example.com --email bo@example.com"
4764
+ ],
4765
+ run: async ({ ctx, args, flags }) => {
4766
+ const emails = toStringArray(flags.email);
4767
+ if (emails === void 0) {
4768
+ throw new CliUsageError("Pass at least one --email.");
4769
+ }
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 };
4777
+ }
4778
+ });
4779
+
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",
4791
+ args: [
4792
+ { name: "domainId", summary: "Marketing domain id", isRequired: true }
4793
+ ],
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
+ }
4812
+ });
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
+ },
4824
+ commandClass: "write",
4825
+ args: [
4826
+ { name: "domainId", summary: "Marketing domain id", isRequired: true }
4827
+ ],
4828
+ flags: [
4829
+ { flag: "--file <path>", summary: "CSV file, or - for stdin" },
4830
+ {
4831
+ flag: "--column <header>",
4832
+ summary: "The column holding the addresses (by header)"
4833
+ },
4834
+ IDEMPOTENCY_FLAG
4835
+ ],
4836
+ examples: [
4837
+ "brew-cli domains unsubscribes import dom_123 --file optouts.csv --column Email"
4838
+ ],
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
+
4516
4932
  // src/commands/domains/update.ts
4517
4933
  var domainsUpdateCommand = defineCommand({
4518
4934
  path: ["domains", "update"],
@@ -4658,19 +5074,41 @@ var emailsCloneCommand = defineCommand({
4658
5074
  flag: "--email-version-id <id>",
4659
5075
  summary: "Exact source version to clone (default: latest)"
4660
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
+ },
4661
5089
  IDEMPOTENCY_FLAG
4662
5090
  ],
4663
5091
  examples: [
4664
5092
  "brew-cli emails clone eml_2SmZOWV3ZQ7W5x6g3m4p",
4665
- "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"'
4666
5095
  ],
4667
5096
  run: async ({ ctx, args, flags }) => {
4668
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
+ }
4669
5104
  return {
4670
5105
  data: await ctx.client().emails.clone(
4671
5106
  asSdkInput({
4672
5107
  emailId: args.emailId ?? "",
4673
- ...emailVersionId === void 0 ? {} : { emailVersionId }
5108
+ ...emailVersionId === void 0 ? {} : { emailVersionId },
5109
+ ...title === void 0 ? {} : { title },
5110
+ ...groupId === void 0 ? {} : { groupId },
5111
+ ...groupName === void 0 ? {} : { groupName }
4674
5112
  }),
4675
5113
  requestOptions(flags)
4676
5114
  )
@@ -4853,12 +5291,16 @@ var emailsExportCommand = defineCommand({
4853
5291
  flags: [
4854
5292
  {
4855
5293
  flag: "--provider <provider>",
4856
- 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"
4857
5295
  },
4858
5296
  {
4859
5297
  flag: "--template-name <name>",
4860
5298
  summary: "Template name in the ESP (default: the email title)"
4861
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
+ },
4862
5304
  {
4863
5305
  flag: "--dry-run",
4864
5306
  summary: "Validate design, ownership, and ESP connection without creating a template"
@@ -4873,16 +5315,18 @@ var emailsExportCommand = defineCommand({
4873
5315
  const provider = flagString(flags.provider);
4874
5316
  if (provider === void 0) {
4875
5317
  throw new CliUsageError(
4876
- "--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."
4877
5319
  );
4878
5320
  }
4879
5321
  const templateName = flagString(flags.templateName);
5322
+ const senderEmail = flagString(flags.senderEmail);
4880
5323
  return {
4881
5324
  data: await ctx.client().emails.export(
4882
5325
  asSdkInput({
4883
5326
  emailId: args.emailId ?? "",
4884
5327
  provider,
4885
5328
  ...templateName === void 0 ? {} : { templateName },
5329
+ ...senderEmail === void 0 ? {} : { senderEmail },
4886
5330
  // The spec field is snake_case, unlike the rest of the API surface.
4887
5331
  ...flags.dryRun === true ? { dryRun: true } : {}
4888
5332
  }),
@@ -4967,20 +5411,44 @@ var emailsGetCommand = defineCommand({
4967
5411
  flags: [
4968
5412
  {
4969
5413
  flag: "--include <tokens>",
4970
- 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)"
4971
5423
  }
4972
5424
  ],
4973
5425
  examples: [
4974
5426
  "brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p",
4975
- "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"
4976
5430
  ],
4977
5431
  run: async ({ ctx, args, flags }) => {
5432
+ const emailId = args.emailId ?? "";
4978
5433
  const include = flagString(flags.include);
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
+ }
4979
5446
  return {
4980
- data: await ctx.client().emails.get(
4981
- args.emailId ?? "",
4982
- include === void 0 ? void 0 : { include }
4983
- )
5447
+ data: await rawRequest(ctx, {
5448
+ method: "GET",
5449
+ path: `/v1/emails/${encodeURIComponent(emailId)}`,
5450
+ query: { include, emailVersionId, runId }
5451
+ })
4984
5452
  };
4985
5453
  }
4986
5454
  });
@@ -5000,7 +5468,12 @@ var emailsGetAuditCommand = defineCommand({
5000
5468
  isRequired: true
5001
5469
  }
5002
5470
  ],
5003
- flags: [LIMIT_FLAG, CURSOR_FLAG],
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
+ ],
5004
5477
  examples: [
5005
5478
  "brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
5006
5479
  "brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f --limit 20"
@@ -5340,6 +5813,14 @@ var emailsImportFigmaCommand = defineCommand({
5340
5813
  flag: "--subject-line <text>",
5341
5814
  summary: "The design's default inbox subject line"
5342
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"
5823
+ },
5343
5824
  IDEMPOTENCY_FLAG
5344
5825
  ],
5345
5826
  examples: [
@@ -5356,13 +5837,20 @@ var emailsImportFigmaCommand = defineCommand({
5356
5837
  const title = flagString(flags.title);
5357
5838
  const format = flagString(flags.format);
5358
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
+ }
5359
5845
  return {
5360
5846
  data: await ctx.client().emails.importFigma(
5361
5847
  asSdkInput({
5362
5848
  figmaUrl,
5363
5849
  ...title === void 0 ? {} : { title },
5364
5850
  ...format === void 0 ? {} : { format },
5365
- ...subjectLine === void 0 ? {} : { subjectLine }
5851
+ ...subjectLine === void 0 ? {} : { subjectLine },
5852
+ ...groupId === void 0 ? {} : { groupId },
5853
+ ...groupName === void 0 ? {} : { groupName }
5366
5854
  }),
5367
5855
  requestOptions(flags)
5368
5856
  )
@@ -5828,8 +6316,48 @@ var fieldsListCommand = defineCommand({
5828
6316
  sdkMethod: "fields.list",
5829
6317
  route: { method: "GET", path: "/v1/fields" },
5830
6318
  commandClass: "read",
5831
- examples: ["brew-cli fields list"],
5832
- run: async ({ ctx }) => ({ data: await ctx.client().fields.list() })
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
+ }
5833
6361
  });
5834
6362
 
5835
6363
  // src/commands/flows/get.ts
@@ -6024,9 +6552,31 @@ var integrationsListCommand = defineCommand({
6024
6552
  sdkMethod: "integrations.list",
6025
6553
  route: { method: "GET", path: "/v1/integrations" },
6026
6554
  commandClass: "read",
6555
+ flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG],
6027
6556
  examples: ["brew-cli integrations list", "brew-cli integrations list --json"],
6028
- run: async ({ ctx }) => {
6029
- const result = await ctx.client().integrations.list();
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);
6030
6580
  return { data: result, human: renderIntegrations(result.data) };
6031
6581
  }
6032
6582
  });
@@ -6618,6 +7168,7 @@ var ALL_COMMANDS = [
6618
7168
  analyticsCampaignsCommand,
6619
7169
  analyticsAutomationsCommand,
6620
7170
  analyticsEventsCommand,
7171
+ analyticsEventCountsCommand,
6621
7172
  analyticsSendsListCommand,
6622
7173
  analyticsSendsGetCommand,
6623
7174
  analyticsTriggerInstancesListCommand,
@@ -6637,6 +7188,11 @@ var ALL_COMMANDS = [
6637
7188
  domainsHealthCommand,
6638
7189
  domainsUpdateCommand,
6639
7190
  domainsDeleteCommand,
7191
+ domainsUnsubscribesListCommand,
7192
+ domainsUnsubscribesAddCommand,
7193
+ domainsUnsubscribesRemoveCommand,
7194
+ domainsUnsubscribesImportCommand,
7195
+ domainsUnsubscribesExportCommand,
6640
7196
  contentGenerateImageCommand,
6641
7197
  contentGifCommand,
6642
7198
  contentTransformCommand,