@koda-sl/baker-cli 0.313.0 → 0.315.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 +1 -1
- package/dist/cli.js +246 -88
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1382,7 +1382,7 @@ baker funnel --steps '[...]' # the whole funnel, restat
|
|
|
1382
1382
|
|
|
1383
1383
|
**Every write says what it dropped.** `--step` changes one step and leaves the rest as it stands; `--steps` replaces the whole funnel and `--preset` draws over it. Every write returns `removed[]` and a `REMOVED steps:` hint when a step went, so a restatement written from a stale read is caught in the same turn.
|
|
1384
1384
|
|
|
1385
|
-
**A step says what triggers it, and every trigger is PICKED from `--moments`.** `triggers` is a list and any one of them firing is enough. Three kinds: `{"kind":"event","eventKey":"submit:contact"}` for anything the company's Forms, pages or systems produced (`moments.events`, `moments.sources`), `{"kind":"landing","landingId":"<id>"}` for one landing being viewed (`moments.landings`), and `{"kind":"any_landing"}` for any landing — what the default first step listens for. Nothing has to be named first: the event is used by its own key, and the step shows it by its own words. `moments.events[].origin` tells a page's event (`site`) from one the client's own systems sent (`systems`); `moments.sources` lists the client's systems by the `page:<name>` key each raises, pickable before the first send arrives. A key typed from memory saves, publishes and counts nobody forever — the hint "has a trigger and nobody reached it while N people entered" is that mistake caught after the fact. A step written with `offlineConversions`, a `conversion` trigger or an `analytics` trigger is refused before any round trip, with the shape to use.
|
|
1385
|
+
**A step says what triggers it, and every trigger is PICKED from `--moments`.** `triggers` is a list and any one of them firing is enough. Three kinds: `{"kind":"event","eventKey":"submit:contact"}` for anything the company's Forms, pages or systems produced (`moments.events`, `moments.sources`), `{"kind":"landing","landingId":"<id>"}` for one landing being viewed (`moments.landings`), and `{"kind":"any_landing"}` for any landing — what the default first step listens for. Nothing has to be named first: the event is used by its own key, and the step shows it by its own words. `moments.events[].origin` tells a page's event (`site`) from one the client's own systems sent (`systems`); `moments.sources` lists the client's systems by the `page:<name>` key each raises, pickable before the first send arrives. **A Form's own endings need nothing set up first** — no Source, no conversion: a Baker page raises them natively, so every Form in the workspace lists its endings in `moments.events` — each step's completion and its `submit:` — with the `step` each happens on, at zero and `seen: false` until somebody fires one, and `countedAs` when the company already counts it. **Baker never picks which ending is the Form's outcome; the agent does**, from the step names, asking the person when they do not make it obvious — and uses the same key the Form is counted on, when it is counted. `baker funnel` also hints, in one line, every workspace Form that reaches no step. Place one with **`baker funnel --add-trigger <step-key> --event <key>`**, which adds a single way in and leaves the step's name, stage, `after[]` and other triggers untouched — `--step` takes a whole step and silently drops any trigger a restatement forgets. That is what makes a Form built minutes ago pickable. A key typed from memory saves, publishes and counts nobody forever — the hint "has a trigger and nobody reached it while N people entered" is that mistake caught after the fact. A step written with `offlineConversions`, a `conversion` trigger or an `analytics` trigger is refused before any round trip, with the shape to use.
|
|
1386
1386
|
|
|
1387
1387
|
**A landing being viewed can be a step** — where most funnels start — and never a conversion: `baker analytics conversions` refuses a `view:` key.
|
|
1388
1388
|
|
package/dist/cli.js
CHANGED
|
@@ -10756,14 +10756,14 @@ function collectionLine(collection) {
|
|
|
10756
10756
|
}
|
|
10757
10757
|
function accountsInTree(nodes) {
|
|
10758
10758
|
const accounts = /* @__PURE__ */ new Set();
|
|
10759
|
-
const
|
|
10759
|
+
const walk = (node) => {
|
|
10760
10760
|
accounts.add(node.customerId);
|
|
10761
10761
|
for (const child of node.children) {
|
|
10762
|
-
|
|
10762
|
+
walk(child);
|
|
10763
10763
|
}
|
|
10764
10764
|
};
|
|
10765
10765
|
for (const node of nodes) {
|
|
10766
|
-
|
|
10766
|
+
walk(node);
|
|
10767
10767
|
}
|
|
10768
10768
|
return accounts;
|
|
10769
10769
|
}
|
|
@@ -21390,14 +21390,14 @@ function collectionLine2(collection) {
|
|
|
21390
21390
|
}
|
|
21391
21391
|
function accountsInTree2(nodes) {
|
|
21392
21392
|
const accounts = /* @__PURE__ */ new Set();
|
|
21393
|
-
const
|
|
21393
|
+
const walk = (node) => {
|
|
21394
21394
|
accounts.add(node.accountId);
|
|
21395
21395
|
for (const child of node.children) {
|
|
21396
|
-
|
|
21396
|
+
walk(child);
|
|
21397
21397
|
}
|
|
21398
21398
|
};
|
|
21399
21399
|
for (const node of nodes) {
|
|
21400
|
-
|
|
21400
|
+
walk(node);
|
|
21401
21401
|
}
|
|
21402
21402
|
return accounts;
|
|
21403
21403
|
}
|
|
@@ -27002,14 +27002,14 @@ function collectionLine3(collection) {
|
|
|
27002
27002
|
}
|
|
27003
27003
|
function accountsInTree3(nodes) {
|
|
27004
27004
|
const accounts = /* @__PURE__ */ new Set();
|
|
27005
|
-
const
|
|
27005
|
+
const walk = (node) => {
|
|
27006
27006
|
accounts.add(node.accountId);
|
|
27007
27007
|
for (const child of node.children) {
|
|
27008
|
-
|
|
27008
|
+
walk(child);
|
|
27009
27009
|
}
|
|
27010
27010
|
};
|
|
27011
27011
|
for (const node of nodes) {
|
|
27012
|
-
|
|
27012
|
+
walk(node);
|
|
27013
27013
|
}
|
|
27014
27014
|
return accounts;
|
|
27015
27015
|
}
|
|
@@ -28827,6 +28827,51 @@ Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedi
|
|
|
28827
28827
|
// src/commands/analytics/index.ts
|
|
28828
28828
|
import { readFileSync as readFileSync12 } from "fs";
|
|
28829
28829
|
|
|
28830
|
+
// ../api/src/analytics/flowEventKeys.ts
|
|
28831
|
+
function flowNodes(node, acc = []) {
|
|
28832
|
+
if (!node || typeof node !== "object") return acc;
|
|
28833
|
+
const record = node;
|
|
28834
|
+
acc.push(record);
|
|
28835
|
+
if (Array.isArray(record.children)) for (const child of record.children) flowNodes(child, acc);
|
|
28836
|
+
return acc;
|
|
28837
|
+
}
|
|
28838
|
+
function flowEventKeys(tree, slug) {
|
|
28839
|
+
const primary = [];
|
|
28840
|
+
const secondary = [];
|
|
28841
|
+
const nodes = flowNodes(tree).filter((node) => typeof node.id === "string" && node.id !== "");
|
|
28842
|
+
if (nodes.length === 0) return [];
|
|
28843
|
+
for (const node of nodes) {
|
|
28844
|
+
const id = node.id;
|
|
28845
|
+
const triggers = flowNodeTriggers(node.nodeData);
|
|
28846
|
+
for (const triggerId of triggers.available) {
|
|
28847
|
+
const candidate = {
|
|
28848
|
+
eventKey: formEventKey(slug, id, triggerId),
|
|
28849
|
+
nodeId: id,
|
|
28850
|
+
nodeName: typeof node.name === "string" ? node.name : id,
|
|
28851
|
+
nodeType: triggers.type,
|
|
28852
|
+
triggerId,
|
|
28853
|
+
isCompletion: triggers.completion === triggerId
|
|
28854
|
+
};
|
|
28855
|
+
(candidate.isCompletion ? primary : secondary).push(candidate);
|
|
28856
|
+
}
|
|
28857
|
+
}
|
|
28858
|
+
return [
|
|
28859
|
+
...primary,
|
|
28860
|
+
...secondary,
|
|
28861
|
+
{
|
|
28862
|
+
eventKey: `submit:${slug}`,
|
|
28863
|
+
nodeId: null,
|
|
28864
|
+
nodeName: "the Form ran out of steps",
|
|
28865
|
+
nodeType: null,
|
|
28866
|
+
triggerId: null,
|
|
28867
|
+
// A Form reaching its last node is as primary as an outcome gets for a
|
|
28868
|
+
// Form with no widget in it — but it never fires on one that ends in a
|
|
28869
|
+
// booking widget or a redirect, so it does not lead the list.
|
|
28870
|
+
isCompletion: false
|
|
28871
|
+
}
|
|
28872
|
+
];
|
|
28873
|
+
}
|
|
28874
|
+
|
|
28830
28875
|
// ../api/src/event-ingest/arrivals.ts
|
|
28831
28876
|
import { z as z33 } from "zod";
|
|
28832
28877
|
|
|
@@ -30006,56 +30051,14 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
30006
30051
|
}
|
|
30007
30052
|
|
|
30008
30053
|
// src/commands/analytics/flowConversionKeys.ts
|
|
30009
|
-
function walk(node, acc = []) {
|
|
30010
|
-
if (!node || typeof node !== "object") return acc;
|
|
30011
|
-
const record = node;
|
|
30012
|
-
acc.push(record);
|
|
30013
|
-
if (Array.isArray(record.children)) for (const child of record.children) walk(child, acc);
|
|
30014
|
-
return acc;
|
|
30015
|
-
}
|
|
30016
|
-
function flowConversionCandidates(tree, slug) {
|
|
30017
|
-
const primary = [];
|
|
30018
|
-
const secondary = [];
|
|
30019
|
-
for (const node of walk(tree)) {
|
|
30020
|
-
const id = typeof node.id === "string" ? node.id : null;
|
|
30021
|
-
if (!id) continue;
|
|
30022
|
-
const triggers = flowNodeTriggers(node.nodeData);
|
|
30023
|
-
for (const triggerId of triggers.available) {
|
|
30024
|
-
const candidate = {
|
|
30025
|
-
eventKey: formEventKey(slug, id, triggerId),
|
|
30026
|
-
nodeId: id,
|
|
30027
|
-
nodeName: typeof node.name === "string" ? node.name : id,
|
|
30028
|
-
nodeType: triggers.type,
|
|
30029
|
-
triggerId,
|
|
30030
|
-
isCompletion: triggers.completion === triggerId
|
|
30031
|
-
};
|
|
30032
|
-
(candidate.isCompletion ? primary : secondary).push(candidate);
|
|
30033
|
-
}
|
|
30034
|
-
}
|
|
30035
|
-
return [
|
|
30036
|
-
...primary,
|
|
30037
|
-
...secondary,
|
|
30038
|
-
{
|
|
30039
|
-
eventKey: `submit:${slug}`,
|
|
30040
|
-
nodeId: null,
|
|
30041
|
-
nodeName: "the Form ran out of steps",
|
|
30042
|
-
nodeType: null,
|
|
30043
|
-
triggerId: null,
|
|
30044
|
-
// A Form reaching its last node is as primary as an outcome gets for a
|
|
30045
|
-
// Form with no widget in it — but it never fires on one that ends in a
|
|
30046
|
-
// booking widget or a redirect, so it does not lead the list.
|
|
30047
|
-
isCompletion: false
|
|
30048
|
-
}
|
|
30049
|
-
];
|
|
30050
|
-
}
|
|
30051
30054
|
function formKeyRefusal(eventKey, tree, slug) {
|
|
30052
30055
|
const parsed = parseEventKey(eventKey);
|
|
30053
30056
|
if (!parsed || parsed.family !== "form" || parsed.flowSlug !== slug) return null;
|
|
30054
|
-
const node =
|
|
30057
|
+
const node = flowNodes(tree).find((candidate) => candidate.id === parsed.nodeId);
|
|
30055
30058
|
if (!node) {
|
|
30056
30059
|
return {
|
|
30057
30060
|
message: `"${slug}" has no step with id "${parsed.nodeId}", so this key would be stored and count zero forever.`,
|
|
30058
|
-
fix: `Steps in this Form: ${
|
|
30061
|
+
fix: `Steps in this Form: ${flowNodes(tree).map((n) => `${String(n.id)} (${String(n.name ?? "unnamed")})`).join(", ")}. \`baker analytics conversions --flow ${slug}\` prints each one already spelled as an event key.`
|
|
30059
30062
|
};
|
|
30060
30063
|
}
|
|
30061
30064
|
const triggers = flowNodeTriggers(node.nodeData);
|
|
@@ -30086,19 +30089,14 @@ function flowConversionHints(slug, rows, noConversionReason) {
|
|
|
30086
30089
|
`Nothing here is counted, and that is on purpose: this Form declares no outcome \u2014 "${noConversionReason}". Leave it alone unless that has stopped being true.`
|
|
30087
30090
|
];
|
|
30088
30091
|
}
|
|
30089
|
-
const deepestFirst = [...rows].reverse();
|
|
30090
|
-
const suggestion = deepestFirst.find((row) => row.isCompletion && row.nodeType !== "text") ?? deepestFirst.find((row) => row.isCompletion) ?? rows[rows.length - 1];
|
|
30091
30092
|
return [
|
|
30092
|
-
`Nothing on "${slug}" is counted, so it converts nobody on every report however many people finish it \u2014
|
|
30093
|
-
...suggestion ? [
|
|
30094
|
-
`Name its outcome: \`baker analytics conversions --event "${suggestion.eventKey}" --name "<what a person calls it>"\` (that key is "${suggestion.nodeName}"). It applies at once and rescores the whole history; nothing is staged and there is nothing to publish.`
|
|
30095
|
-
] : [],
|
|
30093
|
+
`Nothing on "${slug}" is counted, so it converts nobody on every report however many people finish it. Which ending is its outcome is your call, never Baker's: read the endings above by the step each happens on (\`nodeName\`), and when the step names do not make it obvious \u2014 a Form that branches into a rejection and a confirmation \u2014 ask the person which one means a real result. Then \`baker analytics conversions --event "<key>" --name "<what a person calls it>"\`. If this Form is already on a funnel step, count the key that step uses, so the two numbers agree.`,
|
|
30096
30094
|
`If this Form has no outcome of its own \u2014 it hands the visitor to a shop, a portal or a funnel that converts them there \u2014 say so instead, with \`noConversion: { "reason": "\u2026" }\` on its first step.`
|
|
30097
30095
|
];
|
|
30098
30096
|
}
|
|
30099
30097
|
function flowCoverage(forms, definitions) {
|
|
30100
30098
|
return forms.map(({ slug, tree }) => {
|
|
30101
|
-
const rows = joinFlowConversions(
|
|
30099
|
+
const rows = joinFlowConversions(flowEventKeys(tree, slug), definitions);
|
|
30102
30100
|
const declared = tree?.noConversion?.reason;
|
|
30103
30101
|
const seen = /* @__PURE__ */ new Set();
|
|
30104
30102
|
return {
|
|
@@ -31170,7 +31168,7 @@ var args2 = {
|
|
|
31170
31168
|
},
|
|
31171
31169
|
contacts: {
|
|
31172
31170
|
type: "string",
|
|
31173
|
-
description: "With --object deal (on --create-hubspot or --set-trigger): whose event it is \u2014 `
|
|
31171
|
+
description: "With --object deal (on --create-hubspot or --set-trigger): whose event it is \u2014 `every` (the default: every contact on the deal, each its own event, each worth the deal's amount) or `first` (the deal's first contact only)",
|
|
31174
31172
|
required: false
|
|
31175
31173
|
},
|
|
31176
31174
|
property: {
|
|
@@ -32116,7 +32114,7 @@ function readFlowConversions2(slug, definitions) {
|
|
|
32116
32114
|
return {
|
|
32117
32115
|
slug,
|
|
32118
32116
|
noConversionReason: reason,
|
|
32119
|
-
endings: joinFlowConversions(
|
|
32117
|
+
endings: joinFlowConversions(flowEventKeys(tree, slug), definitions)
|
|
32120
32118
|
};
|
|
32121
32119
|
}
|
|
32122
32120
|
function conversionsEnvelope(args4, definitions, candidates) {
|
|
@@ -47233,8 +47231,65 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
47233
47231
|
});
|
|
47234
47232
|
|
|
47235
47233
|
// src/commands/funnel/index.ts
|
|
47234
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
47236
47235
|
import { defineCommand as defineCommand129 } from "citty";
|
|
47237
47236
|
|
|
47237
|
+
// src/commands/funnel/formMoments.ts
|
|
47238
|
+
function offeredEndings(form) {
|
|
47239
|
+
return flowEventKeys(form.tree, form.slug).filter((ending) => ending.isCompletion || ending.nodeId === null);
|
|
47240
|
+
}
|
|
47241
|
+
function formMoments(events, forms, counted) {
|
|
47242
|
+
const endings = /* @__PURE__ */ new Map();
|
|
47243
|
+
for (const form of forms) {
|
|
47244
|
+
for (const ending of offeredEndings(form)) endings.set(ending.eventKey, { slug: form.slug, ending });
|
|
47245
|
+
}
|
|
47246
|
+
const known = events.map((event) => {
|
|
47247
|
+
const found = endings.get(event.eventKey);
|
|
47248
|
+
if (found === void 0) return event;
|
|
47249
|
+
endings.delete(event.eventKey);
|
|
47250
|
+
return { ...event, step: found.ending.nodeName };
|
|
47251
|
+
});
|
|
47252
|
+
const unfired = [...endings.values()].map(({ slug, ending }) => {
|
|
47253
|
+
const countedAs = counted.get(ending.eventKey);
|
|
47254
|
+
return {
|
|
47255
|
+
eventKey: ending.eventKey,
|
|
47256
|
+
origin: "site",
|
|
47257
|
+
flowSlug: slug,
|
|
47258
|
+
...ending.nodeType === null ? {} : { nodeType: ending.nodeType },
|
|
47259
|
+
events: 0,
|
|
47260
|
+
sessions: 0,
|
|
47261
|
+
step: ending.nodeName,
|
|
47262
|
+
seen: false,
|
|
47263
|
+
...countedAs === void 0 ? {} : { countedAs }
|
|
47264
|
+
};
|
|
47265
|
+
});
|
|
47266
|
+
return [...known, ...unfired];
|
|
47267
|
+
}
|
|
47268
|
+
function withFormMoments(moments, forms, counted) {
|
|
47269
|
+
return { ...moments, events: formMoments(moments.events, forms, counted) };
|
|
47270
|
+
}
|
|
47271
|
+
function formsNamedHere(forms) {
|
|
47272
|
+
return forms.filter((form) => flowEventKeys(form.tree, form.slug).length > 0).map((form) => form.slug);
|
|
47273
|
+
}
|
|
47274
|
+
function unplacedFormHints(steps, forms, counted) {
|
|
47275
|
+
const onAStep = new Set(
|
|
47276
|
+
steps.flatMap((step) => (step.triggers ?? []).flatMap((trigger) => trigger.eventKey ? [trigger.eventKey] : []))
|
|
47277
|
+
);
|
|
47278
|
+
const unplaced = [];
|
|
47279
|
+
for (const form of forms) {
|
|
47280
|
+
const endings = flowEventKeys(form.tree, form.slug);
|
|
47281
|
+
if (endings.length === 0 || endings.some((ending) => onAStep.has(ending.eventKey))) continue;
|
|
47282
|
+
const countedOn = endings.filter((ending) => counted.has(ending.eventKey));
|
|
47283
|
+
unplaced.push(
|
|
47284
|
+
countedOn.length === 0 ? form.slug : `${form.slug} (counted as ${countedOn.map((ending) => `"${counted.get(ending.eventKey)}" on \`${ending.eventKey}\``).join(", ")})`
|
|
47285
|
+
);
|
|
47286
|
+
}
|
|
47287
|
+
if (unplaced.length === 0) return [];
|
|
47288
|
+
return [
|
|
47289
|
+
`${unplaced.length} Form(s) in this workspace reach no funnel step, so they move nobody along it however many people finish them: ${unplaced.join("; ")}. Which ending moves somebody to which step is your call: \`baker funnel --moments\` lists every Form's endings by the step each happens on, and when the step names do not make it obvious \u2014 a Form that branches into a rejection and a confirmation \u2014 ask the person which one means a lead or a customer. Place it with \`baker funnel --add-trigger <step> --event <key>\`. A Form already counted as a page conversion goes on the funnel by THAT SAME key, or the two numbers disagree for ever.`
|
|
47290
|
+
];
|
|
47291
|
+
}
|
|
47292
|
+
|
|
47238
47293
|
// ../api/src/funnel/vocabulary.ts
|
|
47239
47294
|
var FUNNEL_STEP_CLASSES = [
|
|
47240
47295
|
/** Saw the offer: a landing opened, an ad clicked through. */
|
|
@@ -47527,6 +47582,18 @@ var funnelRequestSchema = z44.object({
|
|
|
47527
47582
|
step: funnelStepSchema.optional(),
|
|
47528
47583
|
/** One step taken out by key; whatever came after it moves up to whatever came before it. */
|
|
47529
47584
|
removeStep: z44.string().min(1).max(64).optional(),
|
|
47585
|
+
/**
|
|
47586
|
+
* ONE way in added to a step, leaving the rest of that step alone.
|
|
47587
|
+
*
|
|
47588
|
+
* `step` takes a whole step, so adding a way in through it means restating
|
|
47589
|
+
* the step's name, stage, `after[]` and every trigger it already had — and a
|
|
47590
|
+
* trigger left out of that restatement is silently removed. This is the door
|
|
47591
|
+
* for the thing that is actually being asked ("this Form's booking should
|
|
47592
|
+
* count here"), and it cannot drop anything.
|
|
47593
|
+
*/
|
|
47594
|
+
addTrigger: z44.object({ stepKey: z44.string().min(1).max(64), eventKey: z44.string().min(1).max(320) }).optional(),
|
|
47595
|
+
/** ONE way in taken off a step, by the event key it listens for. */
|
|
47596
|
+
removeTrigger: z44.object({ stepKey: z44.string().min(1).max(64), eventKey: z44.string().min(1).max(320) }).optional(),
|
|
47530
47597
|
/** One of the ready-made graphs, instead of stating steps. */
|
|
47531
47598
|
preset: z44.enum(FUNNEL_VERTICALS).optional(),
|
|
47532
47599
|
/** Also return the suggestion library and the presets. */
|
|
@@ -47538,7 +47605,14 @@ var funnelRequestSchema = z44.object({
|
|
|
47538
47605
|
*/
|
|
47539
47606
|
moments: z44.boolean().optional(),
|
|
47540
47607
|
/** How many days the counts beside each step cover. Default 30. */
|
|
47541
|
-
days: z44.number().int().min(1).max(400).optional()
|
|
47608
|
+
days: z44.number().int().min(1).max(400).optional(),
|
|
47609
|
+
/**
|
|
47610
|
+
* The Forms, by slug, the caller names itself when no step counts them —
|
|
47611
|
+
* `baker funnel` reads its own workspace and names each with the key that
|
|
47612
|
+
* places it. The backend leaves them out of its own hint, so no Form is
|
|
47613
|
+
* named twice.
|
|
47614
|
+
*/
|
|
47615
|
+
namedByCaller: z44.array(z44.string().min(1).max(200)).max(1e3).optional()
|
|
47542
47616
|
});
|
|
47543
47617
|
var funnelResponseSchema = z44.object({
|
|
47544
47618
|
ok: z44.literal(true),
|
|
@@ -47591,6 +47665,13 @@ var funnelResponseSchema = z44.object({
|
|
|
47591
47665
|
* one", given in the same turn.
|
|
47592
47666
|
*/
|
|
47593
47667
|
removed: z44.array(z44.string()).optional(),
|
|
47668
|
+
/**
|
|
47669
|
+
* What this company counts as page conversions, this chat's staged counts
|
|
47670
|
+
* included, by event key and name. Here so a Form's ending can say it is
|
|
47671
|
+
* already counted — the agent choosing a step's way in should use that
|
|
47672
|
+
* same key — and outside `moments` because the plain read's hints say it too.
|
|
47673
|
+
*/
|
|
47674
|
+
counted: z44.array(z44.object({ eventKey: z44.string(), name: z44.string() })).optional(),
|
|
47594
47675
|
/** Everything a trigger can name, when asked for with `moments`. */
|
|
47595
47676
|
moments: z44.object({
|
|
47596
47677
|
events: z44.array(
|
|
@@ -47604,7 +47685,20 @@ var funnelResponseSchema = z44.object({
|
|
|
47604
47685
|
events: z44.number(),
|
|
47605
47686
|
sessions: z44.number(),
|
|
47606
47687
|
/** The name it is counted under as a page conversion, when the company counts it. Informational. */
|
|
47607
|
-
countedAs: z44.string().optional()
|
|
47688
|
+
countedAs: z44.string().optional(),
|
|
47689
|
+
/**
|
|
47690
|
+
* The step of the Form this happens on, in the Form's own words —
|
|
47691
|
+
* never a node id. Present on a Form's ending read from the Form
|
|
47692
|
+
* itself, which is the only place the name is known.
|
|
47693
|
+
*/
|
|
47694
|
+
step: z44.string().optional(),
|
|
47695
|
+
/**
|
|
47696
|
+
* `false` on an ending a Form raises natively but nobody has fired
|
|
47697
|
+
* yet — derived from the Form, offered at zero, exactly as a
|
|
47698
|
+
* Source is offered before its first send. Absent means it came
|
|
47699
|
+
* from the event store and therefore happened.
|
|
47700
|
+
*/
|
|
47701
|
+
seen: z44.boolean().optional()
|
|
47608
47702
|
})
|
|
47609
47703
|
),
|
|
47610
47704
|
/** The company's sources: a system of theirs that posts events to Baker, by the event name it raises. */
|
|
@@ -47660,9 +47754,15 @@ function parseFunnelArgs(raw) {
|
|
|
47660
47754
|
const step = parseStep(raw.step);
|
|
47661
47755
|
const removeStep = parseRemoveStep(raw["remove-step"] ?? raw.removeStep);
|
|
47662
47756
|
const preset = parsePreset(raw.preset);
|
|
47663
|
-
const
|
|
47757
|
+
const addTrigger = parseWayIn(raw["add-trigger"] ?? raw.addTrigger, raw.event, "--add-trigger");
|
|
47758
|
+
const removeTrigger = parseWayIn(raw["remove-trigger"] ?? raw.removeTrigger, raw.event, "--remove-trigger");
|
|
47759
|
+
const doors = [steps, step, removeStep, preset, addTrigger, removeTrigger].filter(
|
|
47760
|
+
(door) => door !== void 0
|
|
47761
|
+
).length;
|
|
47664
47762
|
if (doors > 1) {
|
|
47665
|
-
throw new FunnelArgsError(
|
|
47763
|
+
throw new FunnelArgsError(
|
|
47764
|
+
"Give one of --steps, --step, --remove-step, --preset, --add-trigger or --remove-trigger, not two."
|
|
47765
|
+
);
|
|
47666
47766
|
}
|
|
47667
47767
|
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
47668
47768
|
if (days !== void 0 && (!Number.isInteger(days) || days <= 0 || days > 400)) {
|
|
@@ -47673,6 +47773,8 @@ function parseFunnelArgs(raw) {
|
|
|
47673
47773
|
...step === void 0 ? {} : { step },
|
|
47674
47774
|
...removeStep === void 0 ? {} : { removeStep },
|
|
47675
47775
|
...preset === void 0 ? {} : { preset },
|
|
47776
|
+
...addTrigger === void 0 ? {} : { addTrigger },
|
|
47777
|
+
...removeTrigger === void 0 ? {} : { removeTrigger },
|
|
47676
47778
|
templates: raw.templates === true,
|
|
47677
47779
|
moments: raw.moments === true,
|
|
47678
47780
|
...days === void 0 ? {} : { days }
|
|
@@ -47684,6 +47786,8 @@ function funnelWrite(args4) {
|
|
|
47684
47786
|
...args4.step === void 0 ? {} : { step: args4.step },
|
|
47685
47787
|
...args4.removeStep === void 0 ? {} : { removeStep: args4.removeStep },
|
|
47686
47788
|
...args4.preset === void 0 ? {} : { preset: args4.preset },
|
|
47789
|
+
...args4.addTrigger === void 0 ? {} : { addTrigger: args4.addTrigger },
|
|
47790
|
+
...args4.removeTrigger === void 0 ? {} : { removeTrigger: args4.removeTrigger },
|
|
47687
47791
|
...args4.templates ? { templates: true } : {},
|
|
47688
47792
|
...args4.moments ? { moments: true } : {},
|
|
47689
47793
|
...args4.days === void 0 ? {} : { days: args4.days }
|
|
@@ -47793,6 +47897,26 @@ function parsePreset(raw) {
|
|
|
47793
47897
|
}
|
|
47794
47898
|
return raw;
|
|
47795
47899
|
}
|
|
47900
|
+
function parseWayIn(stepKey, eventKey, flag) {
|
|
47901
|
+
if (stepKey === void 0) return void 0;
|
|
47902
|
+
if (typeof stepKey !== "string" || stepKey.trim() === "") {
|
|
47903
|
+
throw new FunnelArgsError(`${flag} takes the key of the step to change: \`${flag} lead\`.`);
|
|
47904
|
+
}
|
|
47905
|
+
if (typeof eventKey !== "string" || eventKey.trim() === "") {
|
|
47906
|
+
throw new FunnelArgsError(`${flag} needs --event, naming what gets somebody there.`, {
|
|
47907
|
+
action: "read_the_moments",
|
|
47908
|
+
explanation: `Run \`baker funnel --moments\` and copy an \`events[].eventKey\` \u2014 a Form's own outcome is listed there at zero before anybody has filled it in. Then: \`${flag} ${stepKey.trim()} --event "<key>"\`.`
|
|
47909
|
+
});
|
|
47910
|
+
}
|
|
47911
|
+
const key = eventKey.trim();
|
|
47912
|
+
if (flag === "--add-trigger" && parseEventKey(key) === null) {
|
|
47913
|
+
throw new FunnelArgsError(`"${key}" is not an event key, so nothing would ever reach that step through it.`, {
|
|
47914
|
+
action: "read_the_moments",
|
|
47915
|
+
explanation: "Run `baker funnel --moments` and copy an `events[].eventKey`. They look like form:<form>:<step>:<trigger>, submit:<form>, page:<name> or view:<landing>."
|
|
47916
|
+
});
|
|
47917
|
+
}
|
|
47918
|
+
return { stepKey: stepKey.trim(), eventKey: key };
|
|
47919
|
+
}
|
|
47796
47920
|
|
|
47797
47921
|
// src/commands/funnel/index.ts
|
|
47798
47922
|
var args3 = {
|
|
@@ -47806,6 +47930,21 @@ var args3 = {
|
|
|
47806
47930
|
description: 'ONE step as a JSON object, in the same shape as an entry of --steps. It is added to the funnel as it now stands, or replaces the step with the same `key`, and every other step is left exactly as it is \u2014 the door for adding or changing a stage without restating the rest. Example: --step \'{"key":"demo","displayName":"Demo held","stepClass":"engaged","after":["lead"],"triggers":[{"id":"t1","kind":"event","eventKey":"page:demo_held"}]}\'',
|
|
47807
47931
|
required: false
|
|
47808
47932
|
},
|
|
47933
|
+
"add-trigger": {
|
|
47934
|
+
type: "string",
|
|
47935
|
+
description: 'The key of ONE step to add a way in to, with `--event` naming what gets somebody there: `--add-trigger lead --event "submit:contact"`. Start here for "this Form should count as a lead" \u2014 it adds that one way in and leaves the step\'s name, stage, `after[]` and every other trigger exactly as they are. Prefer it to `--step`, which takes a WHOLE step and therefore silently removes any trigger the restatement forgets. Adding a key the step already listens for changes nothing. Take the key from `--moments`, never from memory',
|
|
47936
|
+
required: false
|
|
47937
|
+
},
|
|
47938
|
+
"remove-trigger": {
|
|
47939
|
+
type: "string",
|
|
47940
|
+
description: 'The key of ONE step to take a way in OFF, with `--event` naming which: `--remove-trigger lead --event "submit:contact"`. By event key rather than by trigger id, because the id is not something you ever saw. Everything else about the step is untouched',
|
|
47941
|
+
required: false
|
|
47942
|
+
},
|
|
47943
|
+
event: {
|
|
47944
|
+
type: "string",
|
|
47945
|
+
description: "The event key `--add-trigger` or `--remove-trigger` acts on \u2014 an `events[].eventKey` from `--moments`, never invented. Every Form's endings are listed there by the step each happens on, at zero before anybody has filled the Form in; which one means the step is your decision",
|
|
47946
|
+
required: false
|
|
47947
|
+
},
|
|
47809
47948
|
"remove-step": {
|
|
47810
47949
|
type: "string",
|
|
47811
47950
|
description: "The key of one step to take off the funnel. Whatever came after it moves up to whatever came before it, so the chain stays joined. The response lists it under `removed`",
|
|
@@ -47818,7 +47957,7 @@ var args3 = {
|
|
|
47818
47957
|
},
|
|
47819
47958
|
moments: {
|
|
47820
47959
|
type: "boolean",
|
|
47821
|
-
description: "Also return everything a trigger can name, so a trigger is PICKED rather than invented: `events` (every event this company's Forms, pages and systems
|
|
47960
|
+
description: "Also return everything a trigger can name, so a trigger is PICKED rather than invented: `events` (every event this company's Forms, pages and systems produced in the window, with volume, the Form it belongs to, `origin` \u2014 `site` for a page or Form, `systems` for the client's own server, `both` \u2014 and `countedAs` when the company also counts it as a page conversion, which a trigger does not need; PLUS **every workspace Form's endings** \u2014 each step's completion and its `submit:` \u2014 with the `step` each happens on, at zero and `seen: false` until somebody fires one, so a Form built minutes ago is pickable with nothing set up first, and `countedAs` when the company already counts it. Nothing is marked as the outcome: which ending means a step is YOUR decision \u2014 read the step names, and ask the person when they do not make it obvious (a Form that branches into \u201CNot a fit\u201D and \u201CQuote confirmed\u201D). If the Form is already counted, use that same key, so the step and the conversion agree. `baker analytics conversions --flow <slug>` also lists a widget's housekeeping), `sources` (the client's own systems that post events to Baker, by the `page:<name>` key each raises, pickable before its first send arrives) and `landings` (its pages, by the id a `landing` trigger takes). Use this before writing any `triggers`: a key typed from memory saves, publishes and counts nobody forever. A Form's events need NOTHING set up first \u2014 no Source, no conversion: a Baker page raises them by itself",
|
|
47822
47961
|
required: false
|
|
47823
47962
|
},
|
|
47824
47963
|
days: {
|
|
@@ -47840,17 +47979,26 @@ registerSchema({
|
|
|
47840
47979
|
var funnelCommand2 = defineCommand129({
|
|
47841
47980
|
meta: {
|
|
47842
47981
|
name: "funnel",
|
|
47843
|
-
description: 'Start here: run with no flags to see the funnel this company has, with the last 30 days of PEOPLE counted beside every step \u2014 `people` reached it, `atLeast` got at least that far, `before` got as far as the step before, `share` is the ratio, and `worstStep` names where the most people are lost. Every company has one from the day it exists: Visited (any landing) \u2192 Became a lead \u2192 Became a customer, the last two with no way in until somebody gives them one. Then `--moments` for everything a trigger can name (every event the company\'s Forms, pages and systems
|
|
47982
|
+
description: 'Start here: run with no flags to see the funnel this company has, with the last 30 days of PEOPLE counted beside every step \u2014 `people` reached it, `atLeast` got at least that far, `before` got as far as the step before, `share` is the ratio, and `worstStep` names where the most people are lost. Every company has one from the day it exists: Visited (any landing) \u2192 Became a lead \u2192 Became a customer, the last two with no way in until somebody gives them one. Then `--moments` for everything a trigger can name (every event the company\'s Forms, pages and systems produced, its sources, its landings, plus each Form\'s own outcome at zero). **To make an event count on a step \u2014 the usual job \u2014 use `--add-trigger <step> --event <key>`:** it adds that one way in and touches nothing else about the step. `--step \'<json>\'` is for adding or renaming a STEP; it replaces the step with that key, so it means restating its `after` and every trigger it keeps, and one left out is gone. A step is reached by three kinds of thing and nothing else: an event by its own key (`{"id":"t1","kind":"event","eventKey":"<from moments.events or moments.sources>"}`), one landing being viewed (`{"id":"t2","kind":"landing","landingId":"<from moments.landings>"}`) or any landing (`{"id":"t3","kind":"any_landing"}`). Nothing has to be named first. Pick every trigger from `--moments`, never from memory. A step with no `triggers` advances NOBODY and reports zero forever without warning \u2014 that is what the hints keep pointing at. There is no default door: a Form is only counted where a trigger names it. Keep it true: a chat that adds a Form, a Source or an event that moves people forward places it on its step in the same chat. Each step comes back with `sends[]`, read-only: where the people who reach it are sent and what happened, read off the system events behind its ways in. A send is set on the event with `baker analytics sends`, never on a step, and once published it spends ad budget \u2014 a failed one is named in the hints. Everything here is STAGED: it becomes the company\'s funnel in one piece when the chat is published \u2014 the client sees it on the canvas in this chat and can edit it there too \u2014 and the previous version stays on file so what was already measured under it is not lost.'
|
|
47844
47983
|
},
|
|
47845
47984
|
args: args3,
|
|
47846
47985
|
run: async ({ args: raw }) => {
|
|
47847
47986
|
try {
|
|
47848
47987
|
const parsed = parseFunnelArgs(raw);
|
|
47849
|
-
const
|
|
47988
|
+
const forms = workspaceForms();
|
|
47989
|
+
const namedByCaller = formsNamedHere(forms);
|
|
47990
|
+
const request = {
|
|
47991
|
+
...funnelWrite(parsed),
|
|
47992
|
+
...namedByCaller.length === 0 ? {} : { namedByCaller }
|
|
47993
|
+
};
|
|
47994
|
+
const response = await apiPost("/api/funnel", request);
|
|
47995
|
+
const counted = new Map((response.data.counted ?? []).map((row) => [row.eventKey, row.name]));
|
|
47996
|
+
const data = response.data.moments === void 0 ? response.data : { ...response.data, moments: withFormMoments(response.data.moments, forms, counted) };
|
|
47997
|
+
const hints2 = [...response.hints ?? [], ...unplacedFormHints(response.data.steps ?? [], forms, counted)];
|
|
47850
47998
|
writeJsonEnvelope({
|
|
47851
47999
|
ok: true,
|
|
47852
|
-
data
|
|
47853
|
-
...
|
|
48000
|
+
data,
|
|
48001
|
+
...hints2.length > 0 ? { hints: hints2 } : {}
|
|
47854
48002
|
});
|
|
47855
48003
|
} catch (err) {
|
|
47856
48004
|
handleError4(err);
|
|
@@ -47875,6 +48023,16 @@ function handleError4(err) {
|
|
|
47875
48023
|
});
|
|
47876
48024
|
process.exit(1);
|
|
47877
48025
|
}
|
|
48026
|
+
function workspaceForms() {
|
|
48027
|
+
const forms = [];
|
|
48028
|
+
for (const slug of listFlowSlugs()) {
|
|
48029
|
+
try {
|
|
48030
|
+
forms.push({ slug, tree: JSON.parse(readFileSync15(flowDataPath(slug), "utf-8")) });
|
|
48031
|
+
} catch {
|
|
48032
|
+
}
|
|
48033
|
+
}
|
|
48034
|
+
return forms;
|
|
48035
|
+
}
|
|
47878
48036
|
|
|
47879
48037
|
// src/commands/ga4/index.ts
|
|
47880
48038
|
import { defineCommand as defineCommand136 } from "citty";
|
|
@@ -48004,7 +48162,7 @@ Examples:
|
|
|
48004
48162
|
import { defineCommand as defineCommand131 } from "citty";
|
|
48005
48163
|
|
|
48006
48164
|
// src/commands/ga4/shared.ts
|
|
48007
|
-
import { readFileSync as
|
|
48165
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
48008
48166
|
function failValidation3(message) {
|
|
48009
48167
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
48010
48168
|
process.exit(1);
|
|
@@ -48020,7 +48178,7 @@ function requireTarget5(args4, entity) {
|
|
|
48020
48178
|
function readJsonSource(args4, flag) {
|
|
48021
48179
|
const inline = args4[flag];
|
|
48022
48180
|
const file = args4.file;
|
|
48023
|
-
const raw = typeof file === "string" && file.length > 0 ?
|
|
48181
|
+
const raw = typeof file === "string" && file.length > 0 ? readFileSync16(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
48024
48182
|
if (raw === void 0) {
|
|
48025
48183
|
failValidation3(`pass --${flag} with inline JSON or --file with a path to a JSON file`);
|
|
48026
48184
|
}
|
|
@@ -48371,7 +48529,7 @@ Examples:
|
|
|
48371
48529
|
});
|
|
48372
48530
|
|
|
48373
48531
|
// src/commands/ga4/query.ts
|
|
48374
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as
|
|
48532
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync17, writeFileSync as writeFileSync4 } from "fs";
|
|
48375
48533
|
import { resolve as resolve2 } from "path";
|
|
48376
48534
|
import { defineCommand as defineCommand134 } from "citty";
|
|
48377
48535
|
|
|
@@ -48462,7 +48620,7 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
48462
48620
|
writeFileSync4(filePath, content, "utf-8");
|
|
48463
48621
|
}
|
|
48464
48622
|
} else if (append && existsSync7(filePath)) {
|
|
48465
|
-
const existing = JSON.parse(
|
|
48623
|
+
const existing = JSON.parse(readFileSync17(filePath, "utf-8"));
|
|
48466
48624
|
writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
48467
48625
|
} else {
|
|
48468
48626
|
writeFileSync4(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -49314,7 +49472,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
49314
49472
|
import { defineCommand as defineCommand140 } from "citty";
|
|
49315
49473
|
|
|
49316
49474
|
// src/commands/gsc/query.ts
|
|
49317
|
-
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as
|
|
49475
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync18, writeFileSync as writeFileSync5 } from "fs";
|
|
49318
49476
|
import { resolve as resolve3 } from "path";
|
|
49319
49477
|
import { defineCommand as defineCommand137 } from "citty";
|
|
49320
49478
|
|
|
@@ -49462,7 +49620,7 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
49462
49620
|
writeFileSync5(filePath, content, "utf-8");
|
|
49463
49621
|
}
|
|
49464
49622
|
} else if (append && existsSync8(filePath)) {
|
|
49465
|
-
const existing = JSON.parse(
|
|
49623
|
+
const existing = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
49466
49624
|
writeFileSync5(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
49467
49625
|
} else {
|
|
49468
49626
|
writeFileSync5(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -56340,7 +56498,7 @@ var inPageCollectUsedCss = (selector) => {
|
|
|
56340
56498
|
}
|
|
56341
56499
|
return false;
|
|
56342
56500
|
};
|
|
56343
|
-
const
|
|
56501
|
+
const walk = (rules, sink) => {
|
|
56344
56502
|
for (const rule of Array.from(rules)) {
|
|
56345
56503
|
totalRules++;
|
|
56346
56504
|
if (rule instanceof CSSStyleRule) {
|
|
@@ -56361,7 +56519,7 @@ var inPageCollectUsedCss = (selector) => {
|
|
|
56361
56519
|
const grouping = rule instanceof CSSMediaRule || rule instanceof CSSSupportsRule || typeof CSSLayerBlockRule !== "undefined" && rule instanceof CSSLayerBlockRule || typeof CSSContainerRule !== "undefined" && rule instanceof CSSContainerRule;
|
|
56362
56520
|
if (grouping) {
|
|
56363
56521
|
const inner = [];
|
|
56364
|
-
|
|
56522
|
+
walk(rule.cssRules, inner);
|
|
56365
56523
|
if (inner.length === 0) continue;
|
|
56366
56524
|
const condition = rule.conditionText ?? "";
|
|
56367
56525
|
const prelude = rule instanceof CSSMediaRule ? `@media ${condition}` : rule.cssText.split("{")[0]?.trim();
|
|
@@ -56375,7 +56533,7 @@ ${inner.join("\n")}
|
|
|
56375
56533
|
const owner = sheet.ownerNode;
|
|
56376
56534
|
if (owner?.hasAttribute?.("data-baker-freeze")) continue;
|
|
56377
56535
|
try {
|
|
56378
|
-
|
|
56536
|
+
walk(sheet.cssRules, kept);
|
|
56379
56537
|
} catch {
|
|
56380
56538
|
if (sheet.href) unreadableHrefs.push(sheet.href);
|
|
56381
56539
|
}
|
|
@@ -56826,7 +56984,7 @@ var inPageCollectMotion = (selector) => {
|
|
|
56826
56984
|
else if (infinite) loop.push(effect);
|
|
56827
56985
|
else entrance.push(effect);
|
|
56828
56986
|
};
|
|
56829
|
-
const
|
|
56987
|
+
const walk = (rules, insideScrollTimeline) => {
|
|
56830
56988
|
for (const rule of Array.from(rules)) {
|
|
56831
56989
|
if (rule instanceof CSSKeyframesRule) {
|
|
56832
56990
|
keyframesByName.set(rule.name, rule.cssText);
|
|
@@ -56844,17 +57002,17 @@ var inPageCollectMotion = (selector) => {
|
|
|
56844
57002
|
respectsReducedMotion = true;
|
|
56845
57003
|
continue;
|
|
56846
57004
|
}
|
|
56847
|
-
|
|
57005
|
+
walk(rule.cssRules, insideScrollTimeline);
|
|
56848
57006
|
continue;
|
|
56849
57007
|
}
|
|
56850
57008
|
const grouping = rule;
|
|
56851
|
-
if (grouping.cssRules)
|
|
57009
|
+
if (grouping.cssRules) walk(grouping.cssRules, insideScrollTimeline);
|
|
56852
57010
|
}
|
|
56853
57011
|
};
|
|
56854
57012
|
for (const sheet of Array.from(document.styleSheets)) {
|
|
56855
57013
|
if (sheet.ownerNode?.hasAttribute?.("data-baker-freeze")) continue;
|
|
56856
57014
|
try {
|
|
56857
|
-
|
|
57015
|
+
walk(sheet.cssRules, false);
|
|
56858
57016
|
} catch {
|
|
56859
57017
|
}
|
|
56860
57018
|
}
|
|
@@ -62693,7 +62851,7 @@ import { defineCommand as defineCommand217 } from "citty";
|
|
|
62693
62851
|
import { defineCommand as defineCommand214 } from "citty";
|
|
62694
62852
|
|
|
62695
62853
|
// src/commands/tag-manager/shared.ts
|
|
62696
|
-
import { readFileSync as
|
|
62854
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
62697
62855
|
function failValidation5(message) {
|
|
62698
62856
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
62699
62857
|
process.exit(1);
|
|
@@ -62709,7 +62867,7 @@ function requireTarget6(args4, entity) {
|
|
|
62709
62867
|
function loadJsonArg2(args4, flag = "json") {
|
|
62710
62868
|
const inline = args4[flag];
|
|
62711
62869
|
const file = args4.file;
|
|
62712
|
-
const raw = typeof file === "string" && file.length > 0 ?
|
|
62870
|
+
const raw = typeof file === "string" && file.length > 0 ? readFileSync19(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
62713
62871
|
if (raw === void 0) {
|
|
62714
62872
|
failValidation5(`pass --${flag} with inline JSON or --file with a path to a JSON file`);
|
|
62715
62873
|
}
|
|
@@ -65988,7 +66146,7 @@ function refuseUnknownFlags(root, argv) {
|
|
|
65988
66146
|
}
|
|
65989
66147
|
|
|
65990
66148
|
// src/version.ts
|
|
65991
|
-
import { readFileSync as
|
|
66149
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
65992
66150
|
function packageJsonUrl() {
|
|
65993
66151
|
return new URL("../package.json", import.meta.url);
|
|
65994
66152
|
}
|
|
@@ -66000,7 +66158,7 @@ function parsePackageVersion(raw) {
|
|
|
66000
66158
|
throw new Error("Invalid CLI package.json: missing version");
|
|
66001
66159
|
}
|
|
66002
66160
|
function getCliVersion() {
|
|
66003
|
-
return parsePackageVersion(
|
|
66161
|
+
return parsePackageVersion(readFileSync20(packageJsonUrl(), "utf8"));
|
|
66004
66162
|
}
|
|
66005
66163
|
|
|
66006
66164
|
// src/cli.ts
|