@brew.new/cli 0.4.0 → 0.5.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 +313 -130
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
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.
|
|
218
|
+
var CLI_VERSION = "0.5.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
|
|
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,6 +3548,40 @@ 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
|
+
|
|
3332
3585
|
// src/skip-list.ts
|
|
3333
3586
|
var SDK_SKIP_LIST = [
|
|
3334
3587
|
{
|
|
@@ -4994,36 +5247,6 @@ function renderTemplates(rows) {
|
|
|
4994
5247
|
{ key: "brand", header: "BRAND" }
|
|
4995
5248
|
]);
|
|
4996
5249
|
}
|
|
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
5250
|
var HEADER_PREFIX = "// brew:contracts sha256:";
|
|
5028
5251
|
function pascalCase(value) {
|
|
5029
5252
|
const cleaned = value.replace(/[^a-zA-Z0-9]+/g, " ").trim();
|
|
@@ -5043,77 +5266,56 @@ var IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
|
5043
5266
|
function propertyKey(key) {
|
|
5044
5267
|
return IDENTIFIER_RE.test(key) ? key : JSON.stringify(key);
|
|
5045
5268
|
}
|
|
5046
|
-
function
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5269
|
+
function scalarTsType(type, node) {
|
|
5270
|
+
switch (type) {
|
|
5271
|
+
case "string":
|
|
5272
|
+
return "string";
|
|
5273
|
+
case "int":
|
|
5274
|
+
case "float":
|
|
5275
|
+
return "number";
|
|
5276
|
+
case "boolean":
|
|
5277
|
+
return "boolean";
|
|
5278
|
+
case "date":
|
|
5279
|
+
return "string";
|
|
5280
|
+
case "enum":
|
|
5281
|
+
return node.enumValues && node.enumValues.length > 0 ? node.enumValues.map((value) => JSON.stringify(value)).join(" | ") : "string";
|
|
5282
|
+
default:
|
|
5283
|
+
return "unknown";
|
|
5052
5284
|
}
|
|
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
5285
|
}
|
|
5067
|
-
function
|
|
5068
|
-
if (node.
|
|
5069
|
-
return node.
|
|
5286
|
+
function triggerFieldType(node, indent) {
|
|
5287
|
+
if (node.type === "object") {
|
|
5288
|
+
return triggerObjectLiteral(node.children ?? [], indent);
|
|
5070
5289
|
}
|
|
5071
|
-
if (node.
|
|
5072
|
-
|
|
5290
|
+
if (node.type === "array") {
|
|
5291
|
+
if (node.children && node.children.length > 0) {
|
|
5292
|
+
return `Array<${triggerObjectLiteral(node.children, indent)}>`;
|
|
5293
|
+
}
|
|
5294
|
+
const element = node.itemType ? scalarTsType(node.itemType, node) : "unknown";
|
|
5295
|
+
return `Array<${element}>`;
|
|
5073
5296
|
}
|
|
5074
|
-
return node.
|
|
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)}`;
|
|
5297
|
+
return scalarTsType(node.type, node);
|
|
5095
5298
|
}
|
|
5096
|
-
function
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
continue;
|
|
5108
|
-
}
|
|
5109
|
-
payloadNodes.push(root);
|
|
5299
|
+
function triggerObjectLiteral(nodes, indent) {
|
|
5300
|
+
if (nodes.length === 0) {
|
|
5301
|
+
return indent === "" ? "Record<string, never>" : "Record<string, unknown>";
|
|
5302
|
+
}
|
|
5303
|
+
const inner = `${indent} `;
|
|
5304
|
+
const lines = ["{"];
|
|
5305
|
+
for (const node of nodes) {
|
|
5306
|
+
const optional = node.required ? "" : "?";
|
|
5307
|
+
lines.push(
|
|
5308
|
+
`${inner}${propertyKey(node.key)}${optional}: ${triggerFieldType(node, inner)}`
|
|
5309
|
+
);
|
|
5110
5310
|
}
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
}
|
|
5311
|
+
lines.push(`${indent}}`);
|
|
5312
|
+
return lines.join("\n");
|
|
5313
|
+
}
|
|
5314
|
+
function emitTriggerType(trigger, name) {
|
|
5315
|
+
const fields = trigger.payloadSchema?.fields ?? [];
|
|
5114
5316
|
return [
|
|
5115
|
-
`/** Fire: POST /v1/
|
|
5116
|
-
|
|
5317
|
+
`/** Fire: POST /v1/automations/triggers/${trigger.triggerEventId}/fire \u2014 body { payload: ${name} } */`,
|
|
5318
|
+
`export type ${name} = ${triggerObjectLiteral(fields, "")}`
|
|
5117
5319
|
].join("\n");
|
|
5118
5320
|
}
|
|
5119
5321
|
function byCodepoint(a, b) {
|
|
@@ -5143,31 +5345,18 @@ function buildFileText(args) {
|
|
|
5143
5345
|
const triggers = [...args.triggers].sort(
|
|
5144
5346
|
(a, b) => byCodepoint(a.triggerEventId, b.triggerEventId)
|
|
5145
5347
|
);
|
|
5146
|
-
const
|
|
5147
|
-
(
|
|
5348
|
+
const names = uniqueNames(
|
|
5349
|
+
triggers.map((t) => ({ id: t.triggerEventId, label: t.title }))
|
|
5148
5350
|
);
|
|
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
5351
|
const triggerBlocks = triggers.map(
|
|
5157
5352
|
(t, i) => emitTriggerType(t, names[i] ?? typeName(t.title))
|
|
5158
5353
|
);
|
|
5159
|
-
const transactionalBlocks = transactionals.map(
|
|
5160
|
-
(t, i) => emitTransactionalType(
|
|
5161
|
-
t,
|
|
5162
|
-
names[triggers.length + i] ?? typeName(t.transactionId)
|
|
5163
|
-
)
|
|
5164
|
-
);
|
|
5165
5354
|
const body = [
|
|
5166
5355
|
"// Generated by `brew-cli types` \u2014 do not edit by hand.",
|
|
5167
|
-
"// Re-run `brew-cli types` after changing a trigger schema
|
|
5168
|
-
"//
|
|
5356
|
+
"// Re-run `brew-cli types` after changing a trigger schema; gate",
|
|
5357
|
+
"// drift in CI with `brew-cli types --check`.",
|
|
5169
5358
|
"",
|
|
5170
|
-
|
|
5359
|
+
triggerBlocks.join("\n\n"),
|
|
5171
5360
|
""
|
|
5172
5361
|
].join("\n");
|
|
5173
5362
|
const hash = createHash("sha256").update(body).digest("hex");
|
|
@@ -5176,7 +5365,7 @@ ${body}`;
|
|
|
5176
5365
|
}
|
|
5177
5366
|
var typesCommand = defineCommand({
|
|
5178
5367
|
path: ["types"],
|
|
5179
|
-
summary: "Generate TypeScript payload contracts
|
|
5368
|
+
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
5369
|
sdkMethod: null,
|
|
5181
5370
|
derivedFrom: "automations.triggers.list",
|
|
5182
5371
|
route: { method: "GET", path: "/v1/automations/triggers" },
|
|
@@ -5187,10 +5376,6 @@ var typesCommand = defineCommand({
|
|
|
5187
5376
|
summary: "Output file (default brew-contracts.ts)",
|
|
5188
5377
|
defaultValue: "brew-contracts.ts"
|
|
5189
5378
|
},
|
|
5190
|
-
{
|
|
5191
|
-
flag: "--transaction <transactionIds...>",
|
|
5192
|
-
summary: "Transactional object ids (txn_\u2026) to include, contract derived from each pinned template"
|
|
5193
|
-
},
|
|
5194
5379
|
{
|
|
5195
5380
|
flag: "--check",
|
|
5196
5381
|
summary: "Verify the output file is up to date instead of writing; exits 1 on drift"
|
|
@@ -5198,7 +5383,7 @@ var typesCommand = defineCommand({
|
|
|
5198
5383
|
],
|
|
5199
5384
|
examples: [
|
|
5200
5385
|
"brew-cli types",
|
|
5201
|
-
"brew-cli types --out src/brew-contracts.ts
|
|
5386
|
+
"brew-cli types --out src/brew-contracts.ts",
|
|
5202
5387
|
"brew-cli types --check"
|
|
5203
5388
|
],
|
|
5204
5389
|
run: async ({ ctx, flags }) => {
|
|
@@ -5217,12 +5402,7 @@ var typesCommand = defineCommand({
|
|
|
5217
5402
|
}
|
|
5218
5403
|
cursor = listResponse.pagination.cursor;
|
|
5219
5404
|
}
|
|
5220
|
-
const
|
|
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 });
|
|
5405
|
+
const text = buildFileText({ triggers });
|
|
5226
5406
|
const outPath = typeof flags.out === "string" ? flags.out : "brew-contracts.ts";
|
|
5227
5407
|
if (flags.check === true) {
|
|
5228
5408
|
let existing = null;
|
|
@@ -5249,10 +5429,9 @@ var typesCommand = defineCommand({
|
|
|
5249
5429
|
return {
|
|
5250
5430
|
data: {
|
|
5251
5431
|
out: outPath,
|
|
5252
|
-
transactionals: transactionals.length,
|
|
5253
5432
|
triggers: triggers.length
|
|
5254
5433
|
},
|
|
5255
|
-
human: `Wrote ${outPath} (${triggers.length} trigger${triggers.length === 1 ? "" : "s"}
|
|
5434
|
+
human: `Wrote ${outPath} (${triggers.length} trigger${triggers.length === 1 ? "" : "s"}).`
|
|
5256
5435
|
};
|
|
5257
5436
|
}
|
|
5258
5437
|
});
|
|
@@ -5343,7 +5522,6 @@ var ALL_COMMANDS = [
|
|
|
5343
5522
|
sendsCancelCommand,
|
|
5344
5523
|
sendsPauseCommand,
|
|
5345
5524
|
sendsResumeCommand,
|
|
5346
|
-
transactionalGetCommand,
|
|
5347
5525
|
typesCommand,
|
|
5348
5526
|
audiencesListCommand,
|
|
5349
5527
|
audiencesGetCommand,
|
|
@@ -5363,6 +5541,10 @@ var ALL_COMMANDS = [
|
|
|
5363
5541
|
automationsRunCommand,
|
|
5364
5542
|
automationsTriggersListCommand,
|
|
5365
5543
|
automationsTriggersReadyCommand,
|
|
5544
|
+
automationsTriggersContractGetCommand,
|
|
5545
|
+
automationsTriggersContractPutCommand,
|
|
5546
|
+
automationsTriggersContractValidateCommand,
|
|
5547
|
+
contractsInferCommand,
|
|
5366
5548
|
automationsTriggersCreateCommand,
|
|
5367
5549
|
automationsTriggersUpdateCommand,
|
|
5368
5550
|
automationsTriggersDeleteCommand,
|
|
@@ -5429,7 +5611,8 @@ var GROUP_SUMMARIES = {
|
|
|
5429
5611
|
integrations: "Read the connected-integration catalog",
|
|
5430
5612
|
sends: "Control in-flight or scheduled sends",
|
|
5431
5613
|
templates: "Browse the template gallery",
|
|
5432
|
-
|
|
5614
|
+
contract: "Stored payload contracts (get, put, validate)",
|
|
5615
|
+
contracts: "Payload-contract helpers",
|
|
5433
5616
|
triggers: "Manage trigger events",
|
|
5434
5617
|
runs: "Automation run history",
|
|
5435
5618
|
"trigger-instances": "Fired trigger instances"
|