@brew.new/cli 0.4.0 → 0.6.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
@@ -215,7 +215,7 @@ function shellQuote(token) {
215
215
 
216
216
  // src/version.ts
217
217
  var CLI_NAME = "brew-cli";
218
- var CLI_VERSION = "0.4.0" ;
218
+ var CLI_VERSION = "0.6.0" ;
219
219
  var CONFIG_KEYS = ["apiKey", "brandId", "apiUrl"];
220
220
  function isConfigKey(value) {
221
221
  return CONFIG_KEYS.includes(value);
@@ -1038,6 +1038,56 @@ function renderInstances(rows) {
1038
1038
  }
1039
1039
 
1040
1040
  // src/lib/raw-request.ts
1041
+ async function rawRequest(ctx, request) {
1042
+ const auth = resolveAuth({
1043
+ globals: ctx.globals,
1044
+ env: ctx.io.env,
1045
+ ...request.allowAnonymous === true ? { allowAnonymous: true } : {}
1046
+ });
1047
+ const hasBody = request.body !== void 0;
1048
+ const idempotencyKey = resolveRawIdempotencyKey(
1049
+ request.method,
1050
+ request.idempotencyKey
1051
+ );
1052
+ const headers = buildRawHeaders({
1053
+ auth,
1054
+ path: request.path,
1055
+ hasJsonBody: hasBody,
1056
+ idempotencyKey
1057
+ });
1058
+ const url = new URL(`${auth.apiUrl}${request.path}`);
1059
+ for (const [key, value] of Object.entries(request.query ?? {})) {
1060
+ if (value !== void 0) {
1061
+ url.searchParams.set(key, value);
1062
+ }
1063
+ }
1064
+ const response = await fetch(url, {
1065
+ method: request.method,
1066
+ headers,
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."
1081
+ });
1082
+ }
1083
+ return parsed;
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
+ }
1041
1091
  function buildRawHeaders(input) {
1042
1092
  const headers = new Headers({
1043
1093
  authorization: `Bearer ${input.auth.apiKey}`,
@@ -2033,6 +2083,175 @@ var automationsTestCommand = defineCommand({
2033
2083
  }
2034
2084
  });
2035
2085
 
2086
+ // src/commands/automations/triggers/contract.ts
2087
+ var FORMAT_FLAG = {
2088
+ flag: "--format <format>",
2089
+ summary: "Rendering: json (default, the contract object) or ts | zod | jsonschema | skill ({format, content})"
2090
+ };
2091
+ var FORMATS = /* @__PURE__ */ new Set(["json", "ts", "zod", "jsonschema", "skill"]);
2092
+ var ENFORCEMENT_MODES = /* @__PURE__ */ new Set(["off", "prune", "strict"]);
2093
+ var VALIDATE_ENFORCEMENT_MODES = /* @__PURE__ */ new Set(["prune", "strict"]);
2094
+ function formatQuery(value) {
2095
+ const format = flagString(value);
2096
+ if (format === void 0) {
2097
+ return "";
2098
+ }
2099
+ if (!FORMATS.has(format)) {
2100
+ throw new CliUsageError(
2101
+ `Unknown --format '${format}' (expected json | ts | zod | jsonschema | skill).`
2102
+ );
2103
+ }
2104
+ return `?format=${format}`;
2105
+ }
2106
+ function contentHuman(body) {
2107
+ return typeof body.content === "string" ? { human: body.content } : {};
2108
+ }
2109
+ var automationsTriggersContractGetCommand = defineCommand({
2110
+ path: ["automations", "triggers", "contract", "get"],
2111
+ summary: "Read a trigger payload contract: stored when declared, derived otherwise; --format renders ts/zod/jsonschema/skill",
2112
+ sdkMethod: null,
2113
+ isRawTransport: true,
2114
+ route: {
2115
+ method: "GET",
2116
+ path: "/v1/automations/triggers/{triggerEventId}/contract"
2117
+ },
2118
+ commandClass: "read",
2119
+ args: [
2120
+ {
2121
+ name: "triggerEventId",
2122
+ summary: "Trigger id (tri_\u2026, or an integration composite id)",
2123
+ isRequired: true
2124
+ }
2125
+ ],
2126
+ flags: [FORMAT_FLAG],
2127
+ examples: [
2128
+ "brew-cli automations triggers contract get tri_signup",
2129
+ "brew-cli automations triggers contract get tri_signup --format ts",
2130
+ "brew-cli automations triggers contract get tri_signup --format skill --json | jq -r .content"
2131
+ ],
2132
+ run: async ({ ctx, args, flags }) => {
2133
+ const body = await rawRequest(ctx, {
2134
+ method: "GET",
2135
+ path: `/v1/automations/triggers/${encodeURIComponent(args.triggerEventId ?? "")}/contract${formatQuery(flags.format)}`
2136
+ });
2137
+ return { data: body, ...contentHuman(body) };
2138
+ }
2139
+ });
2140
+ var automationsTriggersContractPutCommand = defineCommand({
2141
+ path: ["automations", "triggers", "contract", "put"],
2142
+ summary: "Declare (or replace) the stored payload contract for a trigger \u2014 tree-validated before any write; omitting --enforcement leaves the stored setting unchanged",
2143
+ sdkMethod: null,
2144
+ isRawTransport: true,
2145
+ route: {
2146
+ method: "PUT",
2147
+ path: "/v1/automations/triggers/{triggerEventId}/contract"
2148
+ },
2149
+ commandClass: "write",
2150
+ args: [
2151
+ {
2152
+ name: "triggerEventId",
2153
+ summary: "Trigger id (tri_\u2026)",
2154
+ isRequired: true
2155
+ }
2156
+ ],
2157
+ flags: [
2158
+ INPUT_FLAG,
2159
+ {
2160
+ flag: "--enforcement <mode>",
2161
+ summary: "off (advisory, the default) | prune (drop fields not on the list) | strict (reject a payload carrying them)"
2162
+ }
2163
+ ],
2164
+ examples: [
2165
+ `brew-cli automations triggers contract put tri_signup --input '{"fields":[{"key":"email","type":"string","required":true}]}'`,
2166
+ "brew-cli automations triggers contract put tri_signup --enforcement strict"
2167
+ ],
2168
+ // Trigger contracts must keep a top-level required `email` string;
2169
+ // nested object/array fields need a Liquid-enabled workspace. The
2170
+ // response is the same body a follow-up `contract get` returns.
2171
+ run: async ({ ctx, args, flags }) => {
2172
+ const input = mergeInput(
2173
+ await readJsonFlag(ctx, flags.input, "--input"),
2174
+ {}
2175
+ );
2176
+ if (input.fields !== void 0 && !Array.isArray(input.fields)) {
2177
+ throw new CliUsageError(
2178
+ "--input .fields must be an array of contract field nodes."
2179
+ );
2180
+ }
2181
+ const enforcement = flagString(flags.enforcement);
2182
+ if (enforcement !== void 0 && !ENFORCEMENT_MODES.has(enforcement)) {
2183
+ throw new CliUsageError(
2184
+ `Unknown --enforcement '${enforcement}' (expected off | prune | strict).`
2185
+ );
2186
+ }
2187
+ const requestBody = {
2188
+ ...input,
2189
+ ...enforcement !== void 0 ? { enforcement } : {}
2190
+ };
2191
+ if (Object.keys(requestBody).length === 0) {
2192
+ throw new CliUsageError(
2193
+ "Empty contract body \u2014 pass --input (fields and/or name) or --enforcement <mode>."
2194
+ );
2195
+ }
2196
+ const body = await rawRequest(ctx, {
2197
+ method: "PUT",
2198
+ path: `/v1/automations/triggers/${encodeURIComponent(args.triggerEventId ?? "")}/contract`,
2199
+ body: requestBody
2200
+ });
2201
+ return { data: body };
2202
+ }
2203
+ });
2204
+ var automationsTriggersContractValidateCommand = defineCommand({
2205
+ path: ["automations", "triggers", "contract", "validate"],
2206
+ summary: "Dry-run a payload against a trigger's contract (the fire path's validator) \u2014 never fires; invalid payloads still exit 0",
2207
+ sdkMethod: null,
2208
+ isRawTransport: true,
2209
+ route: {
2210
+ method: "POST",
2211
+ path: "/v1/automations/triggers/{triggerEventId}/contract/validate"
2212
+ },
2213
+ commandClass: "read",
2214
+ args: [
2215
+ {
2216
+ name: "triggerEventId",
2217
+ summary: "Trigger id (tri_\u2026)",
2218
+ isRequired: true
2219
+ }
2220
+ ],
2221
+ flags: [
2222
+ INPUT_FLAG,
2223
+ {
2224
+ flag: "--enforcement <mode>",
2225
+ summary: "Preview a mode other than the stored one: prune | strict"
2226
+ }
2227
+ ],
2228
+ examples: [
2229
+ `brew-cli automations triggers contract validate tri_signup --input '{"payload":{"email":"jane@example.com"}}'`
2230
+ ],
2231
+ run: async ({ ctx, args, flags }) => {
2232
+ const input = mergeInput(
2233
+ await readJsonFlag(ctx, flags.input, "--input"),
2234
+ {}
2235
+ );
2236
+ const payload = input.payload ?? input;
2237
+ const enforcement = flagString(flags.enforcement);
2238
+ if (enforcement !== void 0 && !VALIDATE_ENFORCEMENT_MODES.has(enforcement)) {
2239
+ throw new CliUsageError(
2240
+ `Unknown --enforcement '${enforcement}' (expected prune | strict).`
2241
+ );
2242
+ }
2243
+ const body = await rawRequest(ctx, {
2244
+ method: "POST",
2245
+ path: `/v1/automations/triggers/${encodeURIComponent(args.triggerEventId ?? "")}/contract/validate`,
2246
+ body: {
2247
+ payload,
2248
+ ...enforcement !== void 0 ? { enforcement } : {}
2249
+ }
2250
+ });
2251
+ return { data: body };
2252
+ }
2253
+ });
2254
+
2036
2255
  // src/commands/automations/triggers/create.ts
2037
2256
  var automationsTriggersCreateCommand = defineCommand({
2038
2257
  path: ["automations", "triggers", "create"],
@@ -2116,7 +2335,7 @@ var automationsTriggersFireCommand = defineCommand({
2116
2335
  ],
2117
2336
  flags: [INPUT_FLAG, IDEMPOTENCY_FLAG],
2118
2337
  examples: [
2119
- `brew-cli automations triggers fire tev_123 --input '{"payload":{"userId":"u_1"}}' --yes`
2338
+ `brew-cli automations triggers fire tri_signup --input '{"payload":{"email":"jane@example.com"}}' --yes`
2120
2339
  ],
2121
2340
  confirmSummary: ({ args }) => `Fire trigger ${args.triggerEventId ?? ""} \u2014 starts REAL runs on every published automation listening to it.`,
2122
2341
  run: async ({ ctx, args, flags }) => {
@@ -3329,8 +3548,90 @@ var contentTransformCommand = defineCommand({
3329
3548
  }
3330
3549
  });
3331
3550
 
3551
+ // src/commands/contracts/infer.ts
3552
+ var contractsInferCommand = defineCommand({
3553
+ path: ["contracts", "infer"],
3554
+ summary: "Draft a payload contract from a real example payload \u2014 nothing is saved; PUT the draft on a trigger",
3555
+ sdkMethod: null,
3556
+ isRawTransport: true,
3557
+ route: { method: "POST", path: "/v1/payload-contracts/infer" },
3558
+ commandClass: "read",
3559
+ flags: [INPUT_FLAG],
3560
+ examples: [
3561
+ `brew-cli contracts infer --input '{"email":"jane@example.com","order":{"total":9.5}}'`
3562
+ ],
3563
+ // Accepts either the bare example object or `{ example: {...} }`.
3564
+ // Un-inferable spots (nulls, empty arrays) come back under `issues`.
3565
+ run: async ({ ctx, flags }) => {
3566
+ const input = mergeInput(
3567
+ await readJsonFlag(ctx, flags.input, "--input"),
3568
+ {}
3569
+ );
3570
+ const example = input.example ?? input;
3571
+ if (typeof example !== "object" || example === null || Array.isArray(example) || Object.keys(example).length === 0) {
3572
+ throw new CliUsageError(
3573
+ "--input with a non-empty example object is required (the JSON your system sends)."
3574
+ );
3575
+ }
3576
+ const body = await rawRequest(ctx, {
3577
+ method: "POST",
3578
+ path: "/v1/payload-contracts/infer",
3579
+ body: { example }
3580
+ });
3581
+ return { data: body };
3582
+ }
3583
+ });
3584
+
3585
+ // src/commands/data/run.ts
3586
+ var dataRunCommand = defineCommand({
3587
+ path: ["data", "run"],
3588
+ summary: "Run a `db \u2026` command over the brand's data",
3589
+ sdkMethod: "data.run",
3590
+ route: { method: "POST", path: "/v1/data" },
3591
+ commandClass: "read",
3592
+ args: [
3593
+ {
3594
+ name: "command",
3595
+ summary: "The db command line, e.g. 'db find audiences --fields name'",
3596
+ isRequired: true
3597
+ }
3598
+ ],
3599
+ flags: [],
3600
+ examples: [
3601
+ "brew-cli data run 'db ls'",
3602
+ "brew-cli data run 'db find contacts --since 30d --fields email --limit 20'",
3603
+ "brew-cli data run 'db agg analyticsEvents --since 7d --group-by eventType --bucket day'"
3604
+ ],
3605
+ run: async ({ ctx, args }) => {
3606
+ const result = await ctx.client().data.run({
3607
+ command: args.command ?? ""
3608
+ });
3609
+ return {
3610
+ data: result,
3611
+ human: result.output,
3612
+ exitCode: result.exitCode === 0 ? 0 : 1
3613
+ };
3614
+ }
3615
+ });
3616
+
3332
3617
  // src/skip-list.ts
3333
3618
  var SDK_SKIP_LIST = [
3619
+ {
3620
+ sdkPath: "automations.triggers.getContract",
3621
+ reason: "covered by `automations triggers contract get` (raw route, bound pre-SDK-v9; SDK-method migration tracked separately)"
3622
+ },
3623
+ {
3624
+ sdkPath: "automations.triggers.putContract",
3625
+ reason: "covered by `automations triggers contract put` (raw route, bound pre-SDK-v9)"
3626
+ },
3627
+ {
3628
+ sdkPath: "automations.triggers.validatePayload",
3629
+ reason: "covered by `automations triggers contract validate` (raw route, bound pre-SDK-v9)"
3630
+ },
3631
+ {
3632
+ sdkPath: "payloadContracts.infer",
3633
+ reason: "covered by `contracts infer` (raw route, bound pre-SDK-v9)"
3634
+ },
3334
3635
  {
3335
3636
  sdkPath: "contacts.searchAll",
3336
3637
  reason: "auto-pager covered by `contacts search --all`"
@@ -4994,36 +5295,6 @@ function renderTemplates(rows) {
4994
5295
  { key: "brand", header: "BRAND" }
4995
5296
  ]);
4996
5297
  }
4997
-
4998
- // src/commands/transactional/get.ts
4999
- var transactionalGetCommand = defineCommand({
5000
- path: ["transactional", "get"],
5001
- summary: "Read a transactional email object: locked design/domain/envelope; Liquid workspaces add `variableTree` + a fireable `examplePayload`",
5002
- sdkMethod: "transactional.get",
5003
- route: { method: "GET", path: "/v1/transactional/{transactionId}" },
5004
- commandClass: "read",
5005
- args: [
5006
- {
5007
- name: "transactionId",
5008
- summary: "Transactional email id (txn_\u2026) from Email Actions \u2192 Transactional Email",
5009
- isRequired: true
5010
- }
5011
- ],
5012
- examples: ["brew-cli transactional get txn_8fK2mQ4pLx"],
5013
- // `variables` (legacy merge tags) is always present. `templating.engine`,
5014
- // `variableTree`, and `examplePayload` only appear on Liquid-enabled
5015
- // workspaces: variableTree lists every trigger.*/customer.* path the
5016
- // pinned template references, and examplePayload is a ready-to-send
5017
- // `payload` body for `emails send` (or `POST /v1/sends { transactionId,
5018
- // to, payload }`). Nested payload values are Liquid-only — the same
5019
- // shape sent to a non-Liquid workspace is rejected with 400. A `--test`
5020
- // send on `emails send` accepts the identical `payload` shape with the
5021
- // same live-fire rendering parity, so an examplePayload preview matches
5022
- // what a real fire produces.
5023
- run: async ({ ctx, args }) => ({
5024
- data: await ctx.client().transactional.get(args.transactionId ?? "")
5025
- })
5026
- });
5027
5298
  var HEADER_PREFIX = "// brew:contracts sha256:";
5028
5299
  function pascalCase(value) {
5029
5300
  const cleaned = value.replace(/[^a-zA-Z0-9]+/g, " ").trim();
@@ -5043,77 +5314,56 @@ var IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
5043
5314
  function propertyKey(key) {
5044
5315
  return IDENTIFIER_RE.test(key) ? key : JSON.stringify(key);
5045
5316
  }
5046
- function triggerFieldType(type) {
5047
- if (type === "int") {
5048
- return "number";
5317
+ function scalarTsType(type, node) {
5318
+ switch (type) {
5319
+ case "string":
5320
+ return "string";
5321
+ case "int":
5322
+ case "float":
5323
+ return "number";
5324
+ case "boolean":
5325
+ return "boolean";
5326
+ case "date":
5327
+ return "string";
5328
+ case "enum":
5329
+ return node.enumValues && node.enumValues.length > 0 ? node.enumValues.map((value) => JSON.stringify(value)).join(" | ") : "string";
5330
+ default:
5331
+ return "unknown";
5049
5332
  }
5050
- if (type === "boolean") {
5051
- return "boolean";
5052
- }
5053
- return "string";
5054
- }
5055
- function emitTriggerType(trigger, name) {
5056
- const fields = trigger.payloadSchema?.fields ?? [];
5057
- const lines = fields.map((field) => {
5058
- const optional = field.required ? "" : "?";
5059
- return ` ${propertyKey(field.key)}${optional}: ${triggerFieldType(field.type)}`;
5060
- });
5061
- const body = fields.length === 0 ? `export type ${name} = Record<string, never>` : [`export type ${name} = {`, ...lines, "}"].join("\n");
5062
- return [
5063
- `/** Fire: POST /v1/automations/triggers/${trigger.triggerEventId}/fire \u2014 body { payload: ${name} } */`,
5064
- body
5065
- ].join("\n");
5066
5333
  }
5067
- function scalarType(node) {
5068
- if (node.inferredType === "number" || node.inferredType === "boolean") {
5069
- return node.inferredType;
5334
+ function triggerFieldType(node, indent) {
5335
+ if (node.type === "object") {
5336
+ return triggerObjectLiteral(node.children ?? [], indent);
5070
5337
  }
5071
- if (node.inferredType === "string") {
5072
- return "string";
5338
+ if (node.type === "array") {
5339
+ if (node.children && node.children.length > 0) {
5340
+ return `Array<${triggerObjectLiteral(node.children, indent)}>`;
5341
+ }
5342
+ const element = node.itemType ? scalarTsType(node.itemType, node) : "unknown";
5343
+ return `Array<${element}>`;
5073
5344
  }
5074
- return node.fallback === null ? "unknown" : "string";
5075
- }
5076
- function emitTreeNode(node, indent) {
5077
- const optional = node.fallback === null ? "" : "?";
5078
- const key = `${indent}${propertyKey(node.key)}${optional}: `;
5079
- if (node.kind === "object") {
5080
- const children = node.children ?? [];
5081
- return `${key}{
5082
- ${children.map((child) => emitTreeNode(child, `${indent} `)).join("\n")}
5083
- ${indent}}`;
5084
- }
5085
- if (node.kind === "array") {
5086
- const children = node.children ?? [];
5087
- if (children.length === 0) {
5088
- return `${key}Array<unknown>`;
5089
- }
5090
- return `${key}Array<{
5091
- ${children.map((child) => emitTreeNode(child, `${indent} `)).join("\n")}
5092
- ${indent}}>`;
5093
- }
5094
- return `${key}${scalarType(node)}`;
5345
+ return scalarTsType(node.type, node);
5095
5346
  }
5096
- function emitTransactionalType(row, name) {
5097
- const roots = row.variableTree ?? [];
5098
- const payloadNodes = [];
5099
- for (const root of roots) {
5100
- if (root.namespace === "customer") {
5101
- continue;
5102
- }
5103
- if (root.key === "trigger" || root.key === "payload") {
5104
- payloadNodes.push(
5105
- ...root.children ?? []
5106
- );
5107
- continue;
5108
- }
5109
- payloadNodes.push(root);
5347
+ function triggerObjectLiteral(nodes, indent) {
5348
+ if (nodes.length === 0) {
5349
+ return indent === "" ? "Record<string, never>" : "Record<string, unknown>";
5350
+ }
5351
+ const inner = `${indent} `;
5352
+ const lines = ["{"];
5353
+ for (const node of nodes) {
5354
+ const optional = node.required ? "" : "?";
5355
+ lines.push(
5356
+ `${inner}${propertyKey(node.key)}${optional}: ${triggerFieldType(node, inner)}`
5357
+ );
5110
5358
  }
5111
- const body = payloadNodes.length === 0 ? `export type ${name} = Record<string, never>` : `export type ${name} = {
5112
- ${payloadNodes.map((node) => emitTreeNode(node, " ")).join("\n")}
5113
- }`;
5359
+ lines.push(`${indent}}`);
5360
+ return lines.join("\n");
5361
+ }
5362
+ function emitTriggerType(trigger, name) {
5363
+ const fields = trigger.payloadSchema?.fields ?? [];
5114
5364
  return [
5115
- `/** Fire: POST /v1/sends \u2014 body { transactionId: ${JSON.stringify(row.transactionId)}, to, payload: ${name} } */`,
5116
- body
5365
+ `/** Fire: POST /v1/automations/triggers/${trigger.triggerEventId}/fire \u2014 body { payload: ${name} } */`,
5366
+ `export type ${name} = ${triggerObjectLiteral(fields, "")}`
5117
5367
  ].join("\n");
5118
5368
  }
5119
5369
  function byCodepoint(a, b) {
@@ -5143,31 +5393,18 @@ function buildFileText(args) {
5143
5393
  const triggers = [...args.triggers].sort(
5144
5394
  (a, b) => byCodepoint(a.triggerEventId, b.triggerEventId)
5145
5395
  );
5146
- const transactionals = [...args.transactionals].sort(
5147
- (a, b) => byCodepoint(a.transactionId, b.transactionId)
5396
+ const names = uniqueNames(
5397
+ triggers.map((t) => ({ id: t.triggerEventId, label: t.title }))
5148
5398
  );
5149
- const names = uniqueNames([
5150
- ...triggers.map((t) => ({ id: t.triggerEventId, label: t.title })),
5151
- ...transactionals.map((t) => ({
5152
- id: t.transactionId,
5153
- label: t.subject?.trim() || t.transactionId
5154
- }))
5155
- ]);
5156
5399
  const triggerBlocks = triggers.map(
5157
5400
  (t, i) => emitTriggerType(t, names[i] ?? typeName(t.title))
5158
5401
  );
5159
- const transactionalBlocks = transactionals.map(
5160
- (t, i) => emitTransactionalType(
5161
- t,
5162
- names[triggers.length + i] ?? typeName(t.transactionId)
5163
- )
5164
- );
5165
5402
  const body = [
5166
5403
  "// Generated by `brew-cli types` \u2014 do not edit by hand.",
5167
- "// Re-run `brew-cli types` after changing a trigger schema or a",
5168
- "// transactional design; gate drift in CI with `brew-cli types --check`.",
5404
+ "// Re-run `brew-cli types` after changing a trigger schema; gate",
5405
+ "// drift in CI with `brew-cli types --check`.",
5169
5406
  "",
5170
- [...triggerBlocks, ...transactionalBlocks].join("\n\n"),
5407
+ triggerBlocks.join("\n\n"),
5171
5408
  ""
5172
5409
  ].join("\n");
5173
5410
  const hash = createHash("sha256").update(body).digest("hex");
@@ -5176,7 +5413,7 @@ ${body}`;
5176
5413
  }
5177
5414
  var typesCommand = defineCommand({
5178
5415
  path: ["types"],
5179
- summary: "Generate TypeScript payload contracts (triggers + transactional objects) into your codebase; --check is the CI drift gate (exit 1 on drift). Needs the automations scope; --transaction also needs sends",
5416
+ summary: "Generate TypeScript payload contracts for this workspace's triggers into your codebase; --check is the CI drift gate (exit 1 on drift). Needs the automations scope",
5180
5417
  sdkMethod: null,
5181
5418
  derivedFrom: "automations.triggers.list",
5182
5419
  route: { method: "GET", path: "/v1/automations/triggers" },
@@ -5187,10 +5424,6 @@ var typesCommand = defineCommand({
5187
5424
  summary: "Output file (default brew-contracts.ts)",
5188
5425
  defaultValue: "brew-contracts.ts"
5189
5426
  },
5190
- {
5191
- flag: "--transaction <transactionIds...>",
5192
- summary: "Transactional object ids (txn_\u2026) to include, contract derived from each pinned template"
5193
- },
5194
5427
  {
5195
5428
  flag: "--check",
5196
5429
  summary: "Verify the output file is up to date instead of writing; exits 1 on drift"
@@ -5198,7 +5431,7 @@ var typesCommand = defineCommand({
5198
5431
  ],
5199
5432
  examples: [
5200
5433
  "brew-cli types",
5201
- "brew-cli types --out src/brew-contracts.ts --transaction txn_8fK2mQ4pLx",
5434
+ "brew-cli types --out src/brew-contracts.ts",
5202
5435
  "brew-cli types --check"
5203
5436
  ],
5204
5437
  run: async ({ ctx, flags }) => {
@@ -5217,12 +5450,7 @@ var typesCommand = defineCommand({
5217
5450
  }
5218
5451
  cursor = listResponse.pagination.cursor;
5219
5452
  }
5220
- const transactionIds = Array.isArray(flags.transaction) ? flags.transaction : [];
5221
- const transactionals = [];
5222
- for (const transactionId of transactionIds) {
5223
- transactionals.push(await ctx.client().transactional.get(transactionId));
5224
- }
5225
- const text = buildFileText({ transactionals, triggers });
5453
+ const text = buildFileText({ triggers });
5226
5454
  const outPath = typeof flags.out === "string" ? flags.out : "brew-contracts.ts";
5227
5455
  if (flags.check === true) {
5228
5456
  let existing = null;
@@ -5249,10 +5477,9 @@ var typesCommand = defineCommand({
5249
5477
  return {
5250
5478
  data: {
5251
5479
  out: outPath,
5252
- transactionals: transactionals.length,
5253
5480
  triggers: triggers.length
5254
5481
  },
5255
- human: `Wrote ${outPath} (${triggers.length} trigger${triggers.length === 1 ? "" : "s"}, ${transactionals.length} transactional).`
5482
+ human: `Wrote ${outPath} (${triggers.length} trigger${triggers.length === 1 ? "" : "s"}).`
5256
5483
  };
5257
5484
  }
5258
5485
  });
@@ -5343,7 +5570,6 @@ var ALL_COMMANDS = [
5343
5570
  sendsCancelCommand,
5344
5571
  sendsPauseCommand,
5345
5572
  sendsResumeCommand,
5346
- transactionalGetCommand,
5347
5573
  typesCommand,
5348
5574
  audiencesListCommand,
5349
5575
  audiencesGetCommand,
@@ -5363,6 +5589,11 @@ var ALL_COMMANDS = [
5363
5589
  automationsRunCommand,
5364
5590
  automationsTriggersListCommand,
5365
5591
  automationsTriggersReadyCommand,
5592
+ automationsTriggersContractGetCommand,
5593
+ automationsTriggersContractPutCommand,
5594
+ automationsTriggersContractValidateCommand,
5595
+ contractsInferCommand,
5596
+ dataRunCommand,
5366
5597
  automationsTriggersCreateCommand,
5367
5598
  automationsTriggersUpdateCommand,
5368
5599
  automationsTriggersDeleteCommand,
@@ -5429,7 +5660,8 @@ var GROUP_SUMMARIES = {
5429
5660
  integrations: "Read the connected-integration catalog",
5430
5661
  sends: "Control in-flight or scheduled sends",
5431
5662
  templates: "Browse the template gallery",
5432
- transactional: "Read reusable transactional email objects",
5663
+ contract: "Stored payload contracts (get, put, validate)",
5664
+ contracts: "Payload-contract helpers",
5433
5665
  triggers: "Manage trigger events",
5434
5666
  runs: "Automation run history",
5435
5667
  "trigger-instances": "Fired trigger instances"