@koda-sl/baker-cli 0.345.0-dev.9f4314fa9 → 0.345.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/{chunk-D5P4COPD.js → chunk-FFOURYP5.js} +4 -4
- package/dist/chunk-FFOURYP5.js.map +1 -0
- package/dist/cli.js +292 -299
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-D5P4COPD.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
validateCanvasDeep,
|
|
68
68
|
withoutCastName,
|
|
69
69
|
ytDlpBlockSignal
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-FFOURYP5.js";
|
|
71
71
|
import {
|
|
72
72
|
csvOrJson,
|
|
73
73
|
daysAgoIso,
|
|
@@ -31032,278 +31032,6 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
31032
31032
|
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
31033
31033
|
}
|
|
31034
31034
|
|
|
31035
|
-
// src/commands/analytics/render.ts
|
|
31036
|
-
var SPARKLINE_POINTS = 30;
|
|
31037
|
-
var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
31038
|
-
// The Convex row id. It exists so a dashboard can link to the row; an agent
|
|
31039
|
-
// addresses a landing by `landingId`, which is the id in its `_definition.md`.
|
|
31040
|
-
"landingRef"
|
|
31041
|
-
]);
|
|
31042
|
-
function isAbsent(value) {
|
|
31043
|
-
if (value === "") return true;
|
|
31044
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
31045
|
-
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
31046
|
-
return false;
|
|
31047
|
-
}
|
|
31048
|
-
function resample(series, points) {
|
|
31049
|
-
if (series.length <= points || points < 1) return [...series];
|
|
31050
|
-
const out = [];
|
|
31051
|
-
for (let i = 0; i < points; i += 1) {
|
|
31052
|
-
const from = Math.floor(i * series.length / points);
|
|
31053
|
-
const to = Math.floor((i + 1) * series.length / points);
|
|
31054
|
-
let sum = 0;
|
|
31055
|
-
for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
|
|
31056
|
-
out.push(sum);
|
|
31057
|
-
}
|
|
31058
|
-
return out;
|
|
31059
|
-
}
|
|
31060
|
-
function pruneValue(value, full) {
|
|
31061
|
-
if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
|
|
31062
|
-
if (typeof value === "object" && value !== null) {
|
|
31063
|
-
return pruneRow(value, full);
|
|
31064
|
-
}
|
|
31065
|
-
return value;
|
|
31066
|
-
}
|
|
31067
|
-
function pruneRow(row, full) {
|
|
31068
|
-
const out = {};
|
|
31069
|
-
for (const [key, value] of Object.entries(row)) {
|
|
31070
|
-
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
31071
|
-
if (key === "sparkline" && Array.isArray(value)) {
|
|
31072
|
-
if (!full) continue;
|
|
31073
|
-
out[key] = resample(value, SPARKLINE_POINTS);
|
|
31074
|
-
continue;
|
|
31075
|
-
}
|
|
31076
|
-
if (isAbsent(value)) continue;
|
|
31077
|
-
out[key] = pruneValue(value, full);
|
|
31078
|
-
}
|
|
31079
|
-
return out;
|
|
31080
|
-
}
|
|
31081
|
-
function pruneForAgent(data, full) {
|
|
31082
|
-
return pruneRow(data, full);
|
|
31083
|
-
}
|
|
31084
|
-
function isTabular(rows) {
|
|
31085
|
-
return rows.every(
|
|
31086
|
-
(row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
|
|
31087
|
-
(value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
|
|
31088
|
-
)
|
|
31089
|
-
);
|
|
31090
|
-
}
|
|
31091
|
-
function cell2(value, key) {
|
|
31092
|
-
if (value === null || value === void 0) return "";
|
|
31093
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
31094
|
-
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
31095
|
-
if (key?.endsWith("Ms")) return String(Math.round(value));
|
|
31096
|
-
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
31097
|
-
}
|
|
31098
|
-
return String(value);
|
|
31099
|
-
}
|
|
31100
|
-
var IDENTITY_COLUMNS = [
|
|
31101
|
-
"landingId",
|
|
31102
|
-
"name",
|
|
31103
|
-
"slug",
|
|
31104
|
-
"path",
|
|
31105
|
-
"flowSlug",
|
|
31106
|
-
"stepId",
|
|
31107
|
-
"value",
|
|
31108
|
-
"key",
|
|
31109
|
-
"bucket",
|
|
31110
|
-
"tag",
|
|
31111
|
-
"eventName",
|
|
31112
|
-
"release",
|
|
31113
|
-
"place",
|
|
31114
|
-
"bot",
|
|
31115
|
-
"source",
|
|
31116
|
-
"medium",
|
|
31117
|
-
"campaign",
|
|
31118
|
-
"platform",
|
|
31119
|
-
"sessionId",
|
|
31120
|
-
"eventId"
|
|
31121
|
-
];
|
|
31122
|
-
function byIdentityFirst(a, b) {
|
|
31123
|
-
const ia = IDENTITY_COLUMNS.indexOf(a);
|
|
31124
|
-
const ib = IDENTITY_COLUMNS.indexOf(b);
|
|
31125
|
-
if (ia !== -1 || ib !== -1)
|
|
31126
|
-
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
31127
|
-
return 0;
|
|
31128
|
-
}
|
|
31129
|
-
var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
|
|
31130
|
-
function byBlockOrder(a, b) {
|
|
31131
|
-
const rank = (key) => {
|
|
31132
|
-
const at = BLOCK_ORDER.indexOf(key);
|
|
31133
|
-
if (at !== -1) return at;
|
|
31134
|
-
return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
|
|
31135
|
-
};
|
|
31136
|
-
return rank(a) - rank(b);
|
|
31137
|
-
}
|
|
31138
|
-
function columnsOf(rows) {
|
|
31139
|
-
const seen = [];
|
|
31140
|
-
for (const row of rows) {
|
|
31141
|
-
for (const key of Object.keys(row)) {
|
|
31142
|
-
if (!seen.includes(key)) seen.push(key);
|
|
31143
|
-
}
|
|
31144
|
-
}
|
|
31145
|
-
return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
|
|
31146
|
-
}
|
|
31147
|
-
function table2(rows) {
|
|
31148
|
-
const cols = columnsOf(rows);
|
|
31149
|
-
if (cols.length === 0) return "";
|
|
31150
|
-
const head = `| ${cols.join(" | ")} |`;
|
|
31151
|
-
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
31152
|
-
const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
|
|
31153
|
-
return [head, rule, ...body].join("\n");
|
|
31154
|
-
}
|
|
31155
|
-
function isRowList(value) {
|
|
31156
|
-
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
31157
|
-
}
|
|
31158
|
-
function labelOf(row, index) {
|
|
31159
|
-
for (const key of IDENTITY_COLUMNS) {
|
|
31160
|
-
const value = row[key];
|
|
31161
|
-
if (typeof value === "string" && value !== "") return value;
|
|
31162
|
-
}
|
|
31163
|
-
return `#${index + 1}`;
|
|
31164
|
-
}
|
|
31165
|
-
function nestedBlock(name, rows) {
|
|
31166
|
-
const parents = rows.map(
|
|
31167
|
-
(row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
|
|
31168
|
-
);
|
|
31169
|
-
const parts = [`### ${name}`, table2(parents)];
|
|
31170
|
-
rows.forEach((row, index) => {
|
|
31171
|
-
for (const [key, value] of Object.entries(row)) {
|
|
31172
|
-
if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
|
|
31173
|
-
else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
|
|
31174
|
-
}
|
|
31175
|
-
});
|
|
31176
|
-
return parts.filter((part) => part !== "").join("\n");
|
|
31177
|
-
}
|
|
31178
|
-
function isPlainRow(value) {
|
|
31179
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31180
|
-
}
|
|
31181
|
-
function block(name, value) {
|
|
31182
|
-
if (Array.isArray(value)) {
|
|
31183
|
-
if (value.length === 0) return "";
|
|
31184
|
-
if (isTabular(value)) return `### ${name}
|
|
31185
|
-
${table2(value)}`;
|
|
31186
|
-
if (isRowList(value)) return nestedBlock(name, value);
|
|
31187
|
-
return `### ${name}
|
|
31188
|
-
${JSON.stringify(value)}`;
|
|
31189
|
-
}
|
|
31190
|
-
if (typeof value === "object" && value !== null) {
|
|
31191
|
-
const entries = Object.entries(value);
|
|
31192
|
-
if (entries.length === 0) return "";
|
|
31193
|
-
if (entries.every(([, v]) => v === null || typeof v !== "object")) {
|
|
31194
|
-
return `### ${name}
|
|
31195
|
-
${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
|
|
31196
|
-
}
|
|
31197
|
-
return `### ${name}
|
|
31198
|
-
${JSON.stringify(value)}`;
|
|
31199
|
-
}
|
|
31200
|
-
return `### ${name}
|
|
31201
|
-
${cell2(value)}`;
|
|
31202
|
-
}
|
|
31203
|
-
function renderMarkdown3(envelope) {
|
|
31204
|
-
const parts = [];
|
|
31205
|
-
for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
|
|
31206
|
-
for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
|
|
31207
|
-
for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
|
|
31208
|
-
const rendered = block(name, value);
|
|
31209
|
-
if (rendered !== "") parts.push(rendered);
|
|
31210
|
-
}
|
|
31211
|
-
return `${parts.join("\n\n")}
|
|
31212
|
-
`;
|
|
31213
|
-
}
|
|
31214
|
-
function missingBreakdownHint(data, asked) {
|
|
31215
|
-
if (asked.eventName === void 0) return [];
|
|
31216
|
-
const breakdown = data.eventBreakdown;
|
|
31217
|
-
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
31218
|
-
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
|
|
31219
|
-
return [
|
|
31220
|
-
`No rows came back for --event ${asked.eventName}${asked.property ? ` --property ${asked.property}` : ""}. That event or property does not exist on these pages${known.length > 0 ? `; the ones that do are: ${known.slice(0, 12).join(", ")}${known.length > 12 ? ", \u2026" : ""}` : ""}.`
|
|
31221
|
-
];
|
|
31222
|
-
}
|
|
31223
|
-
var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
|
|
31224
|
-
function isAnalyticsOutputFormat(value) {
|
|
31225
|
-
return ANALYTICS_OUTPUT_FORMATS.includes(value);
|
|
31226
|
-
}
|
|
31227
|
-
function writeAnalyticsReport(envelope, format) {
|
|
31228
|
-
if (format === "md") {
|
|
31229
|
-
process.stdout.write(renderMarkdown3(envelope));
|
|
31230
|
-
return;
|
|
31231
|
-
}
|
|
31232
|
-
process.stdout.write(`${JSON.stringify(envelope)}
|
|
31233
|
-
`);
|
|
31234
|
-
}
|
|
31235
|
-
var ROWS_BEFORE_FORMAT_HINT = 25;
|
|
31236
|
-
function rowCount(data) {
|
|
31237
|
-
let total = 0;
|
|
31238
|
-
for (const value of Object.values(data)) {
|
|
31239
|
-
if (Array.isArray(value)) total += value.length;
|
|
31240
|
-
}
|
|
31241
|
-
return total;
|
|
31242
|
-
}
|
|
31243
|
-
function formatHint(data, format) {
|
|
31244
|
-
if (format === "md") return [];
|
|
31245
|
-
const rows = rowCount(data);
|
|
31246
|
-
if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
|
|
31247
|
-
return [
|
|
31248
|
-
`This report is ${rows} rows. If you are going to read the numbers rather than pick one field out of them, --output md returns the same answer as tables, typically a third to a half smaller.`
|
|
31249
|
-
];
|
|
31250
|
-
}
|
|
31251
|
-
|
|
31252
|
-
// src/commands/analytics/conversionsMarkdown.ts
|
|
31253
|
-
function doorsCell(doors) {
|
|
31254
|
-
return doors.map((door) => `${door.door}=${door.events}/${door.sessions}`).join(" ");
|
|
31255
|
-
}
|
|
31256
|
-
function eventKeysCell(eventKeys) {
|
|
31257
|
-
const formKeys = eventKeys.filter((key) => key.startsWith("form:")).length;
|
|
31258
|
-
const others = eventKeys.filter((key) => !key.startsWith("form:"));
|
|
31259
|
-
return [...others, ...formKeys > 0 ? [`${formKeys} Form ending(s)`] : []].join(" + ");
|
|
31260
|
-
}
|
|
31261
|
-
function trafficByForm(candidates) {
|
|
31262
|
-
const byForm = /* @__PURE__ */ new Map();
|
|
31263
|
-
for (const row of candidates) {
|
|
31264
|
-
const form = byForm.get(row.flowSlug) ?? { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
31265
|
-
form["endings seen"] += 1;
|
|
31266
|
-
if (row.isCounted) form["endings counted"] += 1;
|
|
31267
|
-
form.events += row.events;
|
|
31268
|
-
if (row.lastSeen && row.lastSeen.slice(0, 10) > form.lastSeen) form.lastSeen = row.lastSeen.slice(0, 10);
|
|
31269
|
-
byForm.set(row.flowSlug, form);
|
|
31270
|
-
}
|
|
31271
|
-
return byForm;
|
|
31272
|
-
}
|
|
31273
|
-
var NO_TRAFFIC = { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
31274
|
-
var FORM_KEYS_HINT = "A Form's candidates are one row per Form: `baker analytics conversions --flow <slug>` lists that Form's event keys, and `--candidates --output json` lists every key.";
|
|
31275
|
-
function renderConversionsMarkdown(envelope) {
|
|
31276
|
-
const { definitions, flow, flows, candidates } = envelope.data;
|
|
31277
|
-
const data = {
|
|
31278
|
-
definitions: definitions.map(({ name, eventKeys, ...row }) => ({ name, eventKeys: eventKeysCell(eventKeys), ...row }))
|
|
31279
|
-
};
|
|
31280
|
-
if (flow) {
|
|
31281
|
-
data.flow = { slug: flow.slug, noConversionReason: flow.noConversionReason };
|
|
31282
|
-
data.flowEndings = flow.endings;
|
|
31283
|
-
}
|
|
31284
|
-
const traffic = candidates ? trafficByForm(candidates.filter((row) => row.flowSlug !== "")) : /* @__PURE__ */ new Map();
|
|
31285
|
-
if (flows) {
|
|
31286
|
-
data.flows = flows.map((row) => ({
|
|
31287
|
-
slug: row.slug,
|
|
31288
|
-
counted: row.counted.map((entry) => `${entry.name} @ ${entry.step}`).join("; "),
|
|
31289
|
-
noConversion: row.noConversion,
|
|
31290
|
-
...candidates ? traffic.get(row.slug) ?? NO_TRAFFIC : {}
|
|
31291
|
-
}));
|
|
31292
|
-
}
|
|
31293
|
-
const hints2 = [...envelope.hints ?? []];
|
|
31294
|
-
if (candidates) {
|
|
31295
|
-
const listed2 = new Set(flows?.map((row) => row.slug));
|
|
31296
|
-
const unlisted = [...traffic].filter(([slug]) => !listed2.has(slug));
|
|
31297
|
-
if (unlisted.length > 0) data.formCandidates = unlisted.map(([form, row]) => ({ form, ...row }));
|
|
31298
|
-
data.candidates = candidates.filter((row) => row.flowSlug === "").map(({ doors, flowSlug: _flowSlug, nodeType: _nodeType, ...row }) => ({
|
|
31299
|
-
...row,
|
|
31300
|
-
"doors (events/sessions)": doorsCell(doors)
|
|
31301
|
-
}));
|
|
31302
|
-
if (traffic.size > 0) hints2.push(FORM_KEYS_HINT);
|
|
31303
|
-
}
|
|
31304
|
-
return renderMarkdown3({ data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
31305
|
-
}
|
|
31306
|
-
|
|
31307
31035
|
// src/commands/analytics/errorEnvelope.ts
|
|
31308
31036
|
function analyticsErrorEnvelope(err) {
|
|
31309
31037
|
if (err instanceof ApiError) {
|
|
@@ -31795,6 +31523,223 @@ var ANALYTICS_PRESET_INFO = [
|
|
|
31795
31523
|
}
|
|
31796
31524
|
];
|
|
31797
31525
|
|
|
31526
|
+
// src/commands/analytics/render.ts
|
|
31527
|
+
var SPARKLINE_POINTS = 30;
|
|
31528
|
+
var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
31529
|
+
// The Convex row id. It exists so a dashboard can link to the row; an agent
|
|
31530
|
+
// addresses a landing by `landingId`, which is the id in its `_definition.md`.
|
|
31531
|
+
"landingRef"
|
|
31532
|
+
]);
|
|
31533
|
+
function isAbsent(value) {
|
|
31534
|
+
if (value === "") return true;
|
|
31535
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
31536
|
+
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
31537
|
+
return false;
|
|
31538
|
+
}
|
|
31539
|
+
function resample(series, points) {
|
|
31540
|
+
if (series.length <= points || points < 1) return [...series];
|
|
31541
|
+
const out = [];
|
|
31542
|
+
for (let i = 0; i < points; i += 1) {
|
|
31543
|
+
const from = Math.floor(i * series.length / points);
|
|
31544
|
+
const to = Math.floor((i + 1) * series.length / points);
|
|
31545
|
+
let sum = 0;
|
|
31546
|
+
for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
|
|
31547
|
+
out.push(sum);
|
|
31548
|
+
}
|
|
31549
|
+
return out;
|
|
31550
|
+
}
|
|
31551
|
+
function pruneValue(value, full) {
|
|
31552
|
+
if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
|
|
31553
|
+
if (typeof value === "object" && value !== null) {
|
|
31554
|
+
return pruneRow(value, full);
|
|
31555
|
+
}
|
|
31556
|
+
return value;
|
|
31557
|
+
}
|
|
31558
|
+
function pruneRow(row, full) {
|
|
31559
|
+
const out = {};
|
|
31560
|
+
for (const [key, value] of Object.entries(row)) {
|
|
31561
|
+
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
31562
|
+
if (key === "sparkline" && Array.isArray(value)) {
|
|
31563
|
+
if (!full) continue;
|
|
31564
|
+
out[key] = resample(value, SPARKLINE_POINTS);
|
|
31565
|
+
continue;
|
|
31566
|
+
}
|
|
31567
|
+
if (isAbsent(value)) continue;
|
|
31568
|
+
out[key] = pruneValue(value, full);
|
|
31569
|
+
}
|
|
31570
|
+
return out;
|
|
31571
|
+
}
|
|
31572
|
+
function pruneForAgent(data, full) {
|
|
31573
|
+
return pruneRow(data, full);
|
|
31574
|
+
}
|
|
31575
|
+
function isTabular(rows) {
|
|
31576
|
+
return rows.every(
|
|
31577
|
+
(row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
|
|
31578
|
+
(value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
|
|
31579
|
+
)
|
|
31580
|
+
);
|
|
31581
|
+
}
|
|
31582
|
+
function cell2(value, key) {
|
|
31583
|
+
if (value === null || value === void 0) return "";
|
|
31584
|
+
if (Array.isArray(value)) return value.join(" ");
|
|
31585
|
+
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
31586
|
+
if (key?.endsWith("Ms")) return String(Math.round(value));
|
|
31587
|
+
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
31588
|
+
}
|
|
31589
|
+
return String(value);
|
|
31590
|
+
}
|
|
31591
|
+
var IDENTITY_COLUMNS = [
|
|
31592
|
+
"landingId",
|
|
31593
|
+
"name",
|
|
31594
|
+
"slug",
|
|
31595
|
+
"path",
|
|
31596
|
+
"flowSlug",
|
|
31597
|
+
"stepId",
|
|
31598
|
+
"value",
|
|
31599
|
+
"key",
|
|
31600
|
+
"bucket",
|
|
31601
|
+
"tag",
|
|
31602
|
+
"eventName",
|
|
31603
|
+
"release",
|
|
31604
|
+
"place",
|
|
31605
|
+
"bot",
|
|
31606
|
+
"source",
|
|
31607
|
+
"medium",
|
|
31608
|
+
"campaign",
|
|
31609
|
+
"platform",
|
|
31610
|
+
"sessionId",
|
|
31611
|
+
"eventId"
|
|
31612
|
+
];
|
|
31613
|
+
function byIdentityFirst(a, b) {
|
|
31614
|
+
const ia = IDENTITY_COLUMNS.indexOf(a);
|
|
31615
|
+
const ib = IDENTITY_COLUMNS.indexOf(b);
|
|
31616
|
+
if (ia !== -1 || ib !== -1)
|
|
31617
|
+
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
31618
|
+
return 0;
|
|
31619
|
+
}
|
|
31620
|
+
var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
|
|
31621
|
+
function byBlockOrder(a, b) {
|
|
31622
|
+
const rank = (key) => {
|
|
31623
|
+
const at = BLOCK_ORDER.indexOf(key);
|
|
31624
|
+
if (at !== -1) return at;
|
|
31625
|
+
return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
|
|
31626
|
+
};
|
|
31627
|
+
return rank(a) - rank(b);
|
|
31628
|
+
}
|
|
31629
|
+
function columnsOf(rows) {
|
|
31630
|
+
const seen = [];
|
|
31631
|
+
for (const row of rows) {
|
|
31632
|
+
for (const key of Object.keys(row)) {
|
|
31633
|
+
if (!seen.includes(key)) seen.push(key);
|
|
31634
|
+
}
|
|
31635
|
+
}
|
|
31636
|
+
return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
|
|
31637
|
+
}
|
|
31638
|
+
function table2(rows) {
|
|
31639
|
+
const cols = columnsOf(rows);
|
|
31640
|
+
if (cols.length === 0) return "";
|
|
31641
|
+
const head = `| ${cols.join(" | ")} |`;
|
|
31642
|
+
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
31643
|
+
const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
|
|
31644
|
+
return [head, rule, ...body].join("\n");
|
|
31645
|
+
}
|
|
31646
|
+
function isRowList(value) {
|
|
31647
|
+
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
31648
|
+
}
|
|
31649
|
+
function labelOf(row, index) {
|
|
31650
|
+
for (const key of IDENTITY_COLUMNS) {
|
|
31651
|
+
const value = row[key];
|
|
31652
|
+
if (typeof value === "string" && value !== "") return value;
|
|
31653
|
+
}
|
|
31654
|
+
return `#${index + 1}`;
|
|
31655
|
+
}
|
|
31656
|
+
function nestedBlock(name, rows) {
|
|
31657
|
+
const parents = rows.map(
|
|
31658
|
+
(row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
|
|
31659
|
+
);
|
|
31660
|
+
const parts = [`### ${name}`, table2(parents)];
|
|
31661
|
+
rows.forEach((row, index) => {
|
|
31662
|
+
for (const [key, value] of Object.entries(row)) {
|
|
31663
|
+
if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
|
|
31664
|
+
else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
|
|
31665
|
+
}
|
|
31666
|
+
});
|
|
31667
|
+
return parts.filter((part) => part !== "").join("\n");
|
|
31668
|
+
}
|
|
31669
|
+
function isPlainRow(value) {
|
|
31670
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31671
|
+
}
|
|
31672
|
+
function block(name, value) {
|
|
31673
|
+
if (Array.isArray(value)) {
|
|
31674
|
+
if (value.length === 0) return "";
|
|
31675
|
+
if (isTabular(value)) return `### ${name}
|
|
31676
|
+
${table2(value)}`;
|
|
31677
|
+
if (isRowList(value)) return nestedBlock(name, value);
|
|
31678
|
+
return `### ${name}
|
|
31679
|
+
${JSON.stringify(value)}`;
|
|
31680
|
+
}
|
|
31681
|
+
if (typeof value === "object" && value !== null) {
|
|
31682
|
+
const entries = Object.entries(value);
|
|
31683
|
+
if (entries.length === 0) return "";
|
|
31684
|
+
if (entries.every(([, v]) => v === null || typeof v !== "object")) {
|
|
31685
|
+
return `### ${name}
|
|
31686
|
+
${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
|
|
31687
|
+
}
|
|
31688
|
+
return `### ${name}
|
|
31689
|
+
${JSON.stringify(value)}`;
|
|
31690
|
+
}
|
|
31691
|
+
return `### ${name}
|
|
31692
|
+
${cell2(value)}`;
|
|
31693
|
+
}
|
|
31694
|
+
function renderMarkdown3(envelope) {
|
|
31695
|
+
const parts = [];
|
|
31696
|
+
for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
|
|
31697
|
+
for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
|
|
31698
|
+
for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
|
|
31699
|
+
const rendered = block(name, value);
|
|
31700
|
+
if (rendered !== "") parts.push(rendered);
|
|
31701
|
+
}
|
|
31702
|
+
return `${parts.join("\n\n")}
|
|
31703
|
+
`;
|
|
31704
|
+
}
|
|
31705
|
+
function missingBreakdownHint(data, asked) {
|
|
31706
|
+
if (asked.eventName === void 0) return [];
|
|
31707
|
+
const breakdown = data.eventBreakdown;
|
|
31708
|
+
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
31709
|
+
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
|
|
31710
|
+
return [
|
|
31711
|
+
`No rows came back for --event ${asked.eventName}${asked.property ? ` --property ${asked.property}` : ""}. That event or property does not exist on these pages${known.length > 0 ? `; the ones that do are: ${known.slice(0, 12).join(", ")}${known.length > 12 ? ", \u2026" : ""}` : ""}.`
|
|
31712
|
+
];
|
|
31713
|
+
}
|
|
31714
|
+
var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
|
|
31715
|
+
function isAnalyticsOutputFormat(value) {
|
|
31716
|
+
return ANALYTICS_OUTPUT_FORMATS.includes(value);
|
|
31717
|
+
}
|
|
31718
|
+
function writeAnalyticsReport(envelope, format) {
|
|
31719
|
+
if (format === "md") {
|
|
31720
|
+
process.stdout.write(renderMarkdown3(envelope));
|
|
31721
|
+
return;
|
|
31722
|
+
}
|
|
31723
|
+
process.stdout.write(`${JSON.stringify(envelope)}
|
|
31724
|
+
`);
|
|
31725
|
+
}
|
|
31726
|
+
var ROWS_BEFORE_FORMAT_HINT = 25;
|
|
31727
|
+
function rowCount(data) {
|
|
31728
|
+
let total = 0;
|
|
31729
|
+
for (const value of Object.values(data)) {
|
|
31730
|
+
if (Array.isArray(value)) total += value.length;
|
|
31731
|
+
}
|
|
31732
|
+
return total;
|
|
31733
|
+
}
|
|
31734
|
+
function formatHint(data, format) {
|
|
31735
|
+
if (format === "md") return [];
|
|
31736
|
+
const rows = rowCount(data);
|
|
31737
|
+
if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
|
|
31738
|
+
return [
|
|
31739
|
+
`This report is ${rows} rows. If you are going to read the numbers rather than pick one field out of them, --output md returns the same answer as tables, typically a third to a half smaller.`
|
|
31740
|
+
];
|
|
31741
|
+
}
|
|
31742
|
+
|
|
31798
31743
|
// src/commands/analytics/sends.ts
|
|
31799
31744
|
import { defineCommand as defineCommand97 } from "citty";
|
|
31800
31745
|
var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
@@ -32969,7 +32914,17 @@ async function runPreset(args5, options) {
|
|
|
32969
32914
|
const response = await apiPost("/api/analytics/query", requestBody(args5, options));
|
|
32970
32915
|
const requestedPlatform = args5.platform === void 0 ? "" : String(args5.platform);
|
|
32971
32916
|
const adPlatformScope = isAdPlatform(requestedPlatform) ? requestedPlatform : void 0;
|
|
32972
|
-
const format =
|
|
32917
|
+
const format = args5.output === void 0 ? "json" : String(args5.output);
|
|
32918
|
+
if (!isAnalyticsOutputFormat(format)) {
|
|
32919
|
+
writeJsonEnvelope({
|
|
32920
|
+
ok: false,
|
|
32921
|
+
error: {
|
|
32922
|
+
code: "VALIDATION_ERROR",
|
|
32923
|
+
message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
|
|
32924
|
+
}
|
|
32925
|
+
});
|
|
32926
|
+
process.exit(1);
|
|
32927
|
+
}
|
|
32973
32928
|
const data = pruneForAgent(response.data, args5.full === true);
|
|
32974
32929
|
const feed = "stream" in data ? shapeFeed(data.stream, args5.everything === true) : void 0;
|
|
32975
32930
|
if (feed !== void 0) data.stream = feed.rows;
|
|
@@ -32999,20 +32954,6 @@ async function runPreset(args5, options) {
|
|
|
32999
32954
|
handleError3(err);
|
|
33000
32955
|
}
|
|
33001
32956
|
}
|
|
33002
|
-
function outputFormatOrExit(raw) {
|
|
33003
|
-
const format = raw === void 0 ? "json" : String(raw);
|
|
33004
|
-
if (!isAnalyticsOutputFormat(format)) {
|
|
33005
|
-
writeJsonEnvelope({
|
|
33006
|
-
ok: false,
|
|
33007
|
-
error: {
|
|
33008
|
-
code: "VALIDATION_ERROR",
|
|
33009
|
-
message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
|
|
33010
|
-
}
|
|
33011
|
-
});
|
|
33012
|
-
process.exit(1);
|
|
33013
|
-
}
|
|
33014
|
-
return format;
|
|
33015
|
-
}
|
|
33016
32957
|
function presetCommand(options) {
|
|
33017
32958
|
registerSchema({
|
|
33018
32959
|
command: `analytics.${options.name}`,
|
|
@@ -33514,8 +33455,7 @@ var conversionsCommand3 = (() => {
|
|
|
33514
33455
|
type: "string",
|
|
33515
33456
|
description: "Lookback for the counts and for --candidates. Default 30",
|
|
33516
33457
|
required: false
|
|
33517
|
-
}
|
|
33518
|
-
output: SHARED_ARGS.output
|
|
33458
|
+
}
|
|
33519
33459
|
};
|
|
33520
33460
|
registerSchema({
|
|
33521
33461
|
command: "analytics.conversions",
|
|
@@ -33530,7 +33470,6 @@ var conversionsCommand3 = (() => {
|
|
|
33530
33470
|
args: args5,
|
|
33531
33471
|
run: async ({ args: raw }) => {
|
|
33532
33472
|
try {
|
|
33533
|
-
const format = outputFormatOrExit(raw.output);
|
|
33534
33473
|
const args6 = parseConversionsArgs(raw, process.argv);
|
|
33535
33474
|
for (const eventKey of args6.eventKeys) refuseUnmatchableKey(eventKey);
|
|
33536
33475
|
const before = await apiPost("/api/analytics/conversions", {});
|
|
@@ -33540,13 +33479,13 @@ var conversionsCommand3 = (() => {
|
|
|
33540
33479
|
preset: "conversions",
|
|
33541
33480
|
days: args6.days
|
|
33542
33481
|
});
|
|
33543
|
-
|
|
33544
|
-
|
|
33545
|
-
|
|
33546
|
-
|
|
33482
|
+
writeJsonEnvelope(
|
|
33483
|
+
conversionsEnvelope(
|
|
33484
|
+
args6,
|
|
33485
|
+
mergeStoredWithCounts(stored, report.data.conversions ?? []),
|
|
33486
|
+
report.data.eventCatalog ?? []
|
|
33487
|
+
)
|
|
33547
33488
|
);
|
|
33548
|
-
if (format === "md") process.stdout.write(renderConversionsMarkdown(envelope));
|
|
33549
|
-
else writeJsonEnvelope(envelope);
|
|
33550
33489
|
} catch (err) {
|
|
33551
33490
|
if (err instanceof ConversionArgsError) {
|
|
33552
33491
|
handleError3(new ApiError("VALIDATION_ERROR", err.message));
|
|
@@ -67754,6 +67693,7 @@ function commandFor(root, argv) {
|
|
|
67754
67693
|
const { command, resolved } = resolveCommand2(root, argv);
|
|
67755
67694
|
return resolved ? command : null;
|
|
67756
67695
|
}
|
|
67696
|
+
var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
|
|
67757
67697
|
function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
67758
67698
|
const list = unknown.join(", ");
|
|
67759
67699
|
return {
|
|
@@ -67763,7 +67703,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
|
67763
67703
|
message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
67764
67704
|
fix: {
|
|
67765
67705
|
action: hasSchema ? "check_schema" : "check_help",
|
|
67766
|
-
explanation: (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
|
|
67706
|
+
explanation: (unknown.some((flag) => flag === "--output" || flag.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
|
|
67767
67707
|
},
|
|
67768
67708
|
retryable: false
|
|
67769
67709
|
}
|
|
@@ -67802,6 +67742,58 @@ function refuseUnknownFlags(root, argv) {
|
|
|
67802
67742
|
process.exit(1);
|
|
67803
67743
|
}
|
|
67804
67744
|
|
|
67745
|
+
// src/output-flag.ts
|
|
67746
|
+
var FLAG = "--output";
|
|
67747
|
+
var ENVELOPE = "json";
|
|
67748
|
+
var PRINTS_NO_ENVELOPE = /* @__PURE__ */ new Set([
|
|
67749
|
+
"analytics sending-events",
|
|
67750
|
+
"canvas run",
|
|
67751
|
+
"canvas rerun",
|
|
67752
|
+
"canvas sync-definition"
|
|
67753
|
+
]);
|
|
67754
|
+
function declaredArg(command, name) {
|
|
67755
|
+
const args5 = command.args;
|
|
67756
|
+
if (!args5 || typeof args5 !== "object" || !(name in args5)) {
|
|
67757
|
+
return null;
|
|
67758
|
+
}
|
|
67759
|
+
const def = args5[name];
|
|
67760
|
+
return def && typeof def === "object" ? def : {};
|
|
67761
|
+
}
|
|
67762
|
+
function envelopeRequests(argv) {
|
|
67763
|
+
const end = argv.indexOf("--");
|
|
67764
|
+
const limit = end === -1 ? argv.length : end;
|
|
67765
|
+
const found = [];
|
|
67766
|
+
for (let index = 0; index < limit; index++) {
|
|
67767
|
+
const token = argv[index];
|
|
67768
|
+
if (token === `${FLAG}=${ENVELOPE}`) {
|
|
67769
|
+
found.push({ index, length: 1 });
|
|
67770
|
+
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
|
|
67771
|
+
found.push({ index, length: 2 });
|
|
67772
|
+
index++;
|
|
67773
|
+
}
|
|
67774
|
+
}
|
|
67775
|
+
return found;
|
|
67776
|
+
}
|
|
67777
|
+
function outputFlagForCommand(root, argv) {
|
|
67778
|
+
const requests = envelopeRequests(argv);
|
|
67779
|
+
if (requests.length === 0) {
|
|
67780
|
+
return argv;
|
|
67781
|
+
}
|
|
67782
|
+
const command = commandFor(root, argv);
|
|
67783
|
+
if (!command || declaredArg(command, "output") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
|
|
67784
|
+
return argv;
|
|
67785
|
+
}
|
|
67786
|
+
const jsonSwitch = declaredArg(command, "json")?.type === "boolean";
|
|
67787
|
+
const dropped = new Set(requests.flatMap(({ index, length }) => length === 2 ? [index, index + 1] : [index]));
|
|
67788
|
+
const first = requests[0]?.index;
|
|
67789
|
+
return argv.flatMap((token, index) => {
|
|
67790
|
+
if (!dropped.has(index)) {
|
|
67791
|
+
return [token];
|
|
67792
|
+
}
|
|
67793
|
+
return jsonSwitch && index === first ? ["--json"] : [];
|
|
67794
|
+
});
|
|
67795
|
+
}
|
|
67796
|
+
|
|
67805
67797
|
// src/version.ts
|
|
67806
67798
|
import { readFileSync as readFileSync21 } from "fs";
|
|
67807
67799
|
function packageJsonUrl() {
|
|
@@ -67828,7 +67820,7 @@ var main = defineCommand245({
|
|
|
67828
67820
|
Auth: Set BAKER_API_KEY (starts with bk_) and BAKER_API_URL environment variables.
|
|
67829
67821
|
Chat: Set BAKER_CHAT_ID for action and scheduled-action commands that stage changes against a chat.
|
|
67830
67822
|
Output: All commands return JSON envelopes: { ok: true, data: ... } or { ok: false, error: { code, message } }.
|
|
67831
|
-
Formats:
|
|
67823
|
+
Formats: --output json works on every command that prints the envelope. --output md|files only where 'baker schema <command>' lists output. (The research commands additionally accept csv and jsonl.)
|
|
67832
67824
|
Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
67833
67825
|
},
|
|
67834
67826
|
subCommands: {
|
|
@@ -67866,6 +67858,7 @@ process.argv = [...process.argv.slice(0, 2), ...normalizeCacheFlag(process.argv.
|
|
|
67866
67858
|
installStreamTaps();
|
|
67867
67859
|
logInvocation(process.argv.slice(2));
|
|
67868
67860
|
installExitRecord();
|
|
67861
|
+
process.argv = [...process.argv.slice(0, 2), ...outputFlagForCommand(main, process.argv.slice(2))];
|
|
67869
67862
|
refuseUnknownFlags(main, process.argv.slice(2));
|
|
67870
67863
|
process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
|
|
67871
67864
|
runMain(main);
|