@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 +362 -130
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
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.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
|
|
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
|
|
5047
|
-
|
|
5048
|
-
|
|
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
|
|
5068
|
-
if (node.
|
|
5069
|
-
return node.
|
|
5334
|
+
function triggerFieldType(node, indent) {
|
|
5335
|
+
if (node.type === "object") {
|
|
5336
|
+
return triggerObjectLiteral(node.children ?? [], indent);
|
|
5070
5337
|
}
|
|
5071
|
-
if (node.
|
|
5072
|
-
|
|
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.
|
|
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
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
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
|
-
|
|
5112
|
-
|
|
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/
|
|
5116
|
-
|
|
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
|
|
5147
|
-
(
|
|
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
|
|
5168
|
-
"//
|
|
5404
|
+
"// Re-run `brew-cli types` after changing a trigger schema; gate",
|
|
5405
|
+
"// drift in CI with `brew-cli types --check`.",
|
|
5169
5406
|
"",
|
|
5170
|
-
|
|
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
|
|
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
|
|
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
|
|
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"}
|
|
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
|
-
|
|
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"
|