@drip-apex/apex-cli 0.14.0 → 0.14.2
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/cli.js +207 -93
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7325,7 +7325,7 @@ async function checkForUpdate(current) {
|
|
|
7325
7325
|
// package.json
|
|
7326
7326
|
var package_default = {
|
|
7327
7327
|
name: "@drip-apex/apex-cli",
|
|
7328
|
-
version: "0.14.
|
|
7328
|
+
version: "0.14.2",
|
|
7329
7329
|
license: "MIT",
|
|
7330
7330
|
description: "Apex CLI for managing experiments, approved roadmap ideas, and draft workspaces.",
|
|
7331
7331
|
private: false,
|
|
@@ -8336,11 +8336,19 @@ function listExperiments(creds, opts) {
|
|
|
8336
8336
|
const qs = params.toString();
|
|
8337
8337
|
return request(creds, "GET", `/api/v1/experiments${qs ? `?${qs}` : ""}`);
|
|
8338
8338
|
}
|
|
8339
|
-
function getExperiment(creds, id) {
|
|
8340
|
-
return request(
|
|
8339
|
+
function getExperiment(creds, id, includePreviewTarget = false) {
|
|
8340
|
+
return request(
|
|
8341
|
+
creds,
|
|
8342
|
+
"GET",
|
|
8343
|
+
`/api/v1/experiments/${id}${includePreviewTarget ? "?include=preview_target" : ""}`
|
|
8344
|
+
);
|
|
8341
8345
|
}
|
|
8342
|
-
function getExperimentBySlug(creds, slug) {
|
|
8343
|
-
return request(
|
|
8346
|
+
function getExperimentBySlug(creds, slug, includePreviewTarget = false) {
|
|
8347
|
+
return request(
|
|
8348
|
+
creds,
|
|
8349
|
+
"GET",
|
|
8350
|
+
`/api/v1/experiments/by-slug/${slug}${includePreviewTarget ? "?include=preview_target" : ""}`
|
|
8351
|
+
);
|
|
8344
8352
|
}
|
|
8345
8353
|
function upsertExperimentBySlug(creds, slug, body5) {
|
|
8346
8354
|
return request(creds, "PUT", `/api/v1/experiments/by-slug/${slug}`, body5);
|
|
@@ -9541,10 +9549,10 @@ var evidenceKinds = [
|
|
|
9541
9549
|
|
|
9542
9550
|
// src/lib/experiment-handover.ts
|
|
9543
9551
|
function summarizeHandoverQa(value) {
|
|
9544
|
-
const
|
|
9545
|
-
const qa3 =
|
|
9546
|
-
const run3 =
|
|
9547
|
-
const summary =
|
|
9552
|
+
const record4 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
|
|
9553
|
+
const qa3 = record4(value);
|
|
9554
|
+
const run3 = record4(qa3.latestRun);
|
|
9555
|
+
const summary = record4(run3.summary);
|
|
9548
9556
|
const count2 = (value2) => typeof value2 === "number" && Number.isInteger(value2) && value2 >= 0 ? value2 : null;
|
|
9549
9557
|
let requiredDone = count2(summary.completedRequired);
|
|
9550
9558
|
let requiredTotal = count2(summary.required);
|
|
@@ -9619,12 +9627,6 @@ function deviceLabel(targeting) {
|
|
|
9619
9627
|
return void 0;
|
|
9620
9628
|
}
|
|
9621
9629
|
|
|
9622
|
-
// src/lib/test-key.ts
|
|
9623
|
-
var TEST_KEY_RE = /^([A-Z0-9]{2,8})-(\d+)$/;
|
|
9624
|
-
function isTestKeyReference(value) {
|
|
9625
|
-
return value === value.toUpperCase() && TEST_KEY_RE.test(value.toUpperCase());
|
|
9626
|
-
}
|
|
9627
|
-
|
|
9628
9630
|
// src/lib/effective-page-targeting.ts
|
|
9629
9631
|
var ALL_PAGES_LABEL = "All pages";
|
|
9630
9632
|
var CHECKOUT_LABEL = "Checkout";
|
|
@@ -9711,6 +9713,99 @@ function classifyIdeaReference(reference) {
|
|
|
9711
9713
|
return { kind: "invalid", value: trimmed };
|
|
9712
9714
|
}
|
|
9713
9715
|
|
|
9716
|
+
// ../api-client/src/experiments.ts
|
|
9717
|
+
var ID_REFERENCE = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[1-9][0-9]{9})$/i;
|
|
9718
|
+
function isExperimentTestKey(value) {
|
|
9719
|
+
return /^([A-Z0-9]{2,8})-(\d+)$/.test(value);
|
|
9720
|
+
}
|
|
9721
|
+
function record(value) {
|
|
9722
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9723
|
+
}
|
|
9724
|
+
async function resolveExperimentReference(request2, idOrSlug, variationRef) {
|
|
9725
|
+
const explicitSlug = idOrSlug.startsWith("slug:");
|
|
9726
|
+
const reference = explicitSlug ? idOrSlug.slice(5) : idOrSlug;
|
|
9727
|
+
const idShaped = !explicitSlug && ID_REFERENCE.test(reference);
|
|
9728
|
+
const keyShaped = !explicitSlug && isExperimentTestKey(reference);
|
|
9729
|
+
const slugPath = `/api/v1/experiments/by-slug/${encodeURIComponent(reference)}`;
|
|
9730
|
+
let res = await request2("GET", idShaped || keyShaped ? `/api/v1/experiments/${encodeURIComponent(reference)}` : slugPath);
|
|
9731
|
+
if (!res.ok && res.status === 404 && idShaped) res = await request2("GET", slugPath);
|
|
9732
|
+
if (!res.ok) return { ok: false, error: res.error ?? "Experiment not found", status: res.status, response: res };
|
|
9733
|
+
const experiment = record(res.data);
|
|
9734
|
+
if (typeof experiment.id !== "string") return { ok: false, error: "Experiment has no id" };
|
|
9735
|
+
const variations = Array.isArray(experiment.variations) ? experiment.variations.map(record) : [];
|
|
9736
|
+
if (variationRef === void 0) return { ok: true, experimentId: experiment.id, variations, experiment };
|
|
9737
|
+
const available = variations.map((v) => String(v.slug ?? v.name)).join(", ") || "none";
|
|
9738
|
+
const byIdentity = variations.filter((v) => v.id === variationRef || v.public_id === variationRef || v.slug === variationRef);
|
|
9739
|
+
const byName = variations.filter((v) => v.name === variationRef);
|
|
9740
|
+
const matches = byIdentity.length > 0 ? byIdentity : byName;
|
|
9741
|
+
if (matches.length > 1) return {
|
|
9742
|
+
ok: false,
|
|
9743
|
+
error: `Variation "${variationRef}" is ambiguous; use one of these slugs: ${matches.map((v) => String(v.slug)).join(", ")}`
|
|
9744
|
+
};
|
|
9745
|
+
const match2 = matches[0];
|
|
9746
|
+
if (typeof match2?.id !== "string") return { ok: false, error: `Variation "${variationRef}" not found. Available: ${available}` };
|
|
9747
|
+
return { ok: true, experimentId: experiment.id, variationId: match2.id, variations, experiment };
|
|
9748
|
+
}
|
|
9749
|
+
function summarizeResults(payload) {
|
|
9750
|
+
const data = record(payload);
|
|
9751
|
+
const experiment = record(data.experiment);
|
|
9752
|
+
const decision = record(data.decision);
|
|
9753
|
+
const outcome = record(data.effective_outcome);
|
|
9754
|
+
const commerce = record(data.commerce);
|
|
9755
|
+
const rawArms = Array.isArray(data.arms) ? data.arms.map(record) : [];
|
|
9756
|
+
const degradedFlags = {
|
|
9757
|
+
explicit: data.degraded === true,
|
|
9758
|
+
commerceUnavailable: commerce.unavailable === true,
|
|
9759
|
+
armMetricsMissing: rawArms.some((arm) => arm.primaryConversions == null || arm.primaryRate == null)
|
|
9760
|
+
};
|
|
9761
|
+
const missing = /* @__PURE__ */ new Set();
|
|
9762
|
+
if (degradedFlags.commerceUnavailable) missing.add("commerce orders");
|
|
9763
|
+
const controlRate = rawArms.find((arm) => arm.isControl === true)?.primaryRate;
|
|
9764
|
+
const treatmentCount = rawArms.filter((arm) => arm.isControl !== true).length;
|
|
9765
|
+
const arms = rawArms.map((arm) => {
|
|
9766
|
+
const judged = arm.isControl !== true && (decision.treatmentVariationId != null ? arm.variationId === decision.treatmentVariationId : treatmentCount === 1);
|
|
9767
|
+
let lift = null;
|
|
9768
|
+
let confidence = null;
|
|
9769
|
+
if (arm.isControl !== true) {
|
|
9770
|
+
if (judged) {
|
|
9771
|
+
lift = decision.lift;
|
|
9772
|
+
confidence = decision.judgedConfidence;
|
|
9773
|
+
} else if (typeof arm.primaryRate === "number" && typeof controlRate === "number" && controlRate > 0)
|
|
9774
|
+
lift = Math.round((arm.primaryRate / controlRate - 1) * 1e4) / 100;
|
|
9775
|
+
if (lift == null) missing.add("lift");
|
|
9776
|
+
if (judged && confidence == null) missing.add("confidence");
|
|
9777
|
+
}
|
|
9778
|
+
if (arm.visitors == null) missing.add("visitors");
|
|
9779
|
+
if (arm.primaryConversions == null) missing.add("conversions");
|
|
9780
|
+
if (arm.primaryRate == null) missing.add("conversion rate");
|
|
9781
|
+
return { ...arm, lift, confidence, judged };
|
|
9782
|
+
});
|
|
9783
|
+
const verdictWithheld = decision.state === "untrustworthy";
|
|
9784
|
+
return {
|
|
9785
|
+
experiment,
|
|
9786
|
+
runWindow: { startedAt: experiment.resultsWindowStartedAt ?? experiment.startedAt, endedAt: experiment.endedAt },
|
|
9787
|
+
primaryGoal: decision.primaryGoalName,
|
|
9788
|
+
totals: record(data.totals),
|
|
9789
|
+
decision,
|
|
9790
|
+
outcome,
|
|
9791
|
+
arms,
|
|
9792
|
+
judgedArm: arms.find((arm) => arm.judged)?.variationId,
|
|
9793
|
+
verdict: outcome.outcome ?? decision.state,
|
|
9794
|
+
verdictWithheld,
|
|
9795
|
+
statisticsState: (verdictWithheld ? decision.state : outcome.statisticsOutcome ?? decision.state) ?? "unknown",
|
|
9796
|
+
presentedOutcome: (verdictWithheld && outcome.provenance !== "manager_decided" ? decision.state : outcome.outcome ?? decision.state) ?? "unknown",
|
|
9797
|
+
degraded: Object.values(degradedFlags).some(Boolean),
|
|
9798
|
+
degradedFlags,
|
|
9799
|
+
missingMetrics: [...missing],
|
|
9800
|
+
warnings: Array.isArray(data.warnings) ? data.warnings.map((value) => ({
|
|
9801
|
+
message: record(value).message,
|
|
9802
|
+
value
|
|
9803
|
+
})) : [],
|
|
9804
|
+
metrics: Array.isArray(data.metrics) ? data.metrics.map(record) : [],
|
|
9805
|
+
resultsWeekdays: data.results_weekdays
|
|
9806
|
+
};
|
|
9807
|
+
}
|
|
9808
|
+
|
|
9714
9809
|
// ../api-client/src/experiment-create.ts
|
|
9715
9810
|
function deriveStoreUrl(patterns) {
|
|
9716
9811
|
for (const pattern of patterns) {
|
|
@@ -9976,14 +10071,9 @@ function formatRevenue(value, currency) {
|
|
|
9976
10071
|
}
|
|
9977
10072
|
}
|
|
9978
10073
|
function printExperimentResults(results2, currency) {
|
|
9979
|
-
const
|
|
9980
|
-
const
|
|
9981
|
-
const
|
|
9982
|
-
const effectiveOutcome = results2.effective_outcome ?? {};
|
|
9983
|
-
const outcomeProvenance = effectiveOutcome.provenance === "manager_decided" ? " (manager decided)" : "";
|
|
9984
|
-
const verdictWithheld = decision.state === "untrustworthy";
|
|
9985
|
-
const statisticsState = verdictWithheld ? decision.state : effectiveOutcome.statisticsOutcome ?? decision.state ?? "unknown";
|
|
9986
|
-
const presentedOutcome = verdictWithheld && effectiveOutcome.provenance !== "manager_decided" ? decision.state : effectiveOutcome.outcome ?? decision.state ?? "unknown";
|
|
10074
|
+
const summary = summarizeResults(results2);
|
|
10075
|
+
const { experiment, totals, decision, verdictWithheld, statisticsState, presentedOutcome } = summary;
|
|
10076
|
+
const outcomeProvenance = summary.outcome.provenance === "manager_decided" ? " (manager decided)" : "";
|
|
9987
10077
|
console.log();
|
|
9988
10078
|
console.log(source_default.bold(String(experiment.name ?? experiment.id ?? "Experiment results")));
|
|
9989
10079
|
console.log(` Status: ${statusBadge(String(experiment.status ?? "unknown"))}`);
|
|
@@ -9991,7 +10081,7 @@ function printExperimentResults(results2, currency) {
|
|
|
9991
10081
|
console.log(` Conversions: ${String(totals.primaryConversions ?? 0)}`);
|
|
9992
10082
|
console.log(` Revenue: ${formatRevenue(totals.revenue, currency)}`);
|
|
9993
10083
|
console.log(` Outcome: ${statisticsStateLabel(presentedOutcome)}${outcomeProvenance}`);
|
|
9994
|
-
const resultsWeekdays =
|
|
10084
|
+
const resultsWeekdays = summary.resultsWeekdays;
|
|
9995
10085
|
if (resultsWeekdays && Array.isArray(resultsWeekdays.days)) {
|
|
9996
10086
|
const labels = {
|
|
9997
10087
|
monday: "Mon",
|
|
@@ -10014,7 +10104,7 @@ function printExperimentResults(results2, currency) {
|
|
|
10014
10104
|
console.log(
|
|
10015
10105
|
` Confidence (${confidenceBasisLabel(decision.basis)}): ${verdictWithheld ? "withheld \u2014 not decision-grade" : formatPct(decision.judgedConfidence)}`
|
|
10016
10106
|
);
|
|
10017
|
-
const arms =
|
|
10107
|
+
const arms = summary.arms;
|
|
10018
10108
|
if (arms.length > 0) {
|
|
10019
10109
|
console.log();
|
|
10020
10110
|
printTable(
|
|
@@ -10032,7 +10122,7 @@ function printExperimentResults(results2, currency) {
|
|
|
10032
10122
|
[32, 8, 6, 8, 10]
|
|
10033
10123
|
);
|
|
10034
10124
|
}
|
|
10035
|
-
const metrics =
|
|
10125
|
+
const metrics = summary.metrics;
|
|
10036
10126
|
if (metrics.length > 0) {
|
|
10037
10127
|
console.log();
|
|
10038
10128
|
console.log(source_default.bold("Goal counting"));
|
|
@@ -10042,7 +10132,7 @@ function printExperimentResults(results2, currency) {
|
|
|
10042
10132
|
});
|
|
10043
10133
|
}
|
|
10044
10134
|
console.log(" Definitions: https://docs.drip-apex.com/docs/experiments/metric-definitions");
|
|
10045
|
-
const warnings =
|
|
10135
|
+
const warnings = summary.warnings;
|
|
10046
10136
|
if (warnings.length > 0) {
|
|
10047
10137
|
console.log();
|
|
10048
10138
|
console.log(source_default.yellow("Warnings"));
|
|
@@ -10345,10 +10435,10 @@ function printQaRun(run3) {
|
|
|
10345
10435
|
}
|
|
10346
10436
|
if ((run3.evidenceRecords ?? []).length > 0) {
|
|
10347
10437
|
console.log(source_default.bold("\nEvidence records"));
|
|
10348
|
-
for (const
|
|
10349
|
-
const device =
|
|
10438
|
+
for (const record4 of run3.evidenceRecords ?? []) {
|
|
10439
|
+
const device = record4.device ? ` \xB7 ${record4.device}` : "";
|
|
10350
10440
|
console.log(
|
|
10351
|
-
` - ${
|
|
10441
|
+
` - ${record4.kind} \xB7 ${record4.label} \xB7 ${record4.status}${device} \xB7 ${record4.capturedAt}${qaVersionMarker(record4)}`
|
|
10352
10442
|
);
|
|
10353
10443
|
}
|
|
10354
10444
|
}
|
|
@@ -10467,26 +10557,29 @@ async function refreshServerOwnedFilesIfNeeded(creds, folder, experimentId, upda
|
|
|
10467
10557
|
}
|
|
10468
10558
|
}
|
|
10469
10559
|
var EXPERIMENT_REFERENCE_DESCRIPTION = "Experiment ID, slug, or test key (for example BIO-085)";
|
|
10560
|
+
function resolveCliExperimentReference(creds, reference, variationRef) {
|
|
10561
|
+
return resolveExperimentReference(
|
|
10562
|
+
(_method, requestPath) => {
|
|
10563
|
+
const prefix = "/api/v1/experiments/by-slug/";
|
|
10564
|
+
const bySlug = requestPath.startsWith(prefix);
|
|
10565
|
+
const idOrSlug = decodeURIComponent(
|
|
10566
|
+
requestPath.slice(bySlug ? prefix.length : "/api/v1/experiments/".length)
|
|
10567
|
+
);
|
|
10568
|
+
return bySlug ? getExperimentBySlug(creds, idOrSlug) : getExperiment(creds, idOrSlug);
|
|
10569
|
+
},
|
|
10570
|
+
reference,
|
|
10571
|
+
variationRef
|
|
10572
|
+
);
|
|
10573
|
+
}
|
|
10470
10574
|
async function resolveExperiment(idOrSlug) {
|
|
10471
10575
|
const creds = requireCredentials();
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
if (res2.ok) return res2.data;
|
|
10475
|
-
throw new CliError(
|
|
10476
|
-
res2.status === 404 && isTestKeyReference(idOrSlug) ? `Experiment "${idOrSlug}" not found in selected shop ${creds.resolvedContext?.shopId ?? "(API key shop)"}. Test keys resolve within the selected shop; use --shop <shop-id> to change it.` : res2.error ?? `Experiment "${idOrSlug}" not found`,
|
|
10477
|
-
classifyStatus(res2.status),
|
|
10478
|
-
res2.errorDetails,
|
|
10479
|
-
apiFailureOf(res2)
|
|
10480
|
-
);
|
|
10481
|
-
}
|
|
10482
|
-
const slug = idOrSlug.startsWith("slug:") ? idOrSlug.slice(5) : idOrSlug;
|
|
10483
|
-
const res = await getExperimentBySlug(creds, slug);
|
|
10484
|
-
if (res.ok) return res.data;
|
|
10576
|
+
const res = await resolveCliExperimentReference(creds, idOrSlug);
|
|
10577
|
+
if (res.ok) return res.experiment;
|
|
10485
10578
|
throw new CliError(
|
|
10486
|
-
res.error ?? `Experiment "${idOrSlug}" not found
|
|
10487
|
-
classifyStatus(res.status),
|
|
10488
|
-
res.errorDetails,
|
|
10489
|
-
apiFailureOf(res)
|
|
10579
|
+
res.status === 404 && isExperimentTestKey(idOrSlug) ? `Experiment "${idOrSlug}" not found in selected shop ${creds.resolvedContext?.shopId ?? "(API key shop)"}. Test keys resolve within the selected shop; use --shop <shop-id> to change it.` : res.response ? res.response.error ?? `Experiment "${idOrSlug}" not found` : res.error,
|
|
10580
|
+
classifyStatus(res.status ?? 500),
|
|
10581
|
+
res.response?.errorDetails,
|
|
10582
|
+
res.response ? apiFailureOf(res.response) : void 0
|
|
10490
10583
|
);
|
|
10491
10584
|
}
|
|
10492
10585
|
var list = new Command("list").alias("ls").description(
|
|
@@ -12106,7 +12199,7 @@ var qaEvidence = new Command("evidence").description("Attach screenshot jobs or
|
|
|
12106
12199
|
classifyStatus(current.status),
|
|
12107
12200
|
current.errorDetails
|
|
12108
12201
|
);
|
|
12109
|
-
for (const
|
|
12202
|
+
for (const record4 of current.data.run.evidenceRecords) previousIds.add(record4.id);
|
|
12110
12203
|
}
|
|
12111
12204
|
let response;
|
|
12112
12205
|
if (opts.job) {
|
|
@@ -12151,7 +12244,7 @@ var qaEvidence = new Command("evidence").description("Attach screenshot jobs or
|
|
|
12151
12244
|
const run3 = response.data.run;
|
|
12152
12245
|
const data = opts.summary ? qaSummary(
|
|
12153
12246
|
run3,
|
|
12154
|
-
run3.evidenceRecords.filter((
|
|
12247
|
+
run3.evidenceRecords.filter((record4) => !previousIds.has(record4.id))
|
|
12155
12248
|
) : response.data;
|
|
12156
12249
|
output(this, data, () => {
|
|
12157
12250
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
@@ -12842,6 +12935,14 @@ var previewCommand = new Command("preview").description(
|
|
|
12842
12935
|
const data = created.data;
|
|
12843
12936
|
output(previewCommand, data, () => {
|
|
12844
12937
|
console.log(source_default.cyan(data.preview_url));
|
|
12938
|
+
if (data.preview_target) {
|
|
12939
|
+
console.log(`Chosen page: ${data.preview_target.url} (${data.preview_target.source})`);
|
|
12940
|
+
if (!data.preview_target.matches_targeting) {
|
|
12941
|
+
console.log(
|
|
12942
|
+
`The test will not show on this page: ${data.preview_target.reason ?? "The page does not match URL targeting."}`
|
|
12943
|
+
);
|
|
12944
|
+
}
|
|
12945
|
+
}
|
|
12845
12946
|
console.log(
|
|
12846
12947
|
data.qa_run.created ? `QA run ${data.qa_run.id} created` : `QA run ${data.qa_run.id} refreshed (${data.qa_run.automated_evidence_count} automated evidence records)`
|
|
12847
12948
|
);
|
|
@@ -12867,7 +12968,7 @@ var previewCommand = new Command("preview").description(
|
|
|
12867
12968
|
const spinner = await createSpinner("Fetching experiment...");
|
|
12868
12969
|
let exp;
|
|
12869
12970
|
if (/^[0-9a-f-]{36}$/i.test(idOrSlug)) {
|
|
12870
|
-
const res = await getExperiment(creds, idOrSlug);
|
|
12971
|
+
const res = await getExperiment(creds, idOrSlug, !opts?.storeUrl);
|
|
12871
12972
|
if (!res.ok) {
|
|
12872
12973
|
spinner.fail(`Experiment "${idOrSlug}" not found`);
|
|
12873
12974
|
fail(
|
|
@@ -12880,7 +12981,7 @@ var previewCommand = new Command("preview").description(
|
|
|
12880
12981
|
exp = res.data;
|
|
12881
12982
|
} else {
|
|
12882
12983
|
const slug = idOrSlug.startsWith("slug:") ? idOrSlug.slice(5) : idOrSlug;
|
|
12883
|
-
const res = await getExperimentBySlug(creds, slug);
|
|
12984
|
+
const res = await getExperimentBySlug(creds, slug, !opts?.storeUrl);
|
|
12884
12985
|
if (!res.ok) {
|
|
12885
12986
|
spinner.fail(`Experiment "${slug}" not found`);
|
|
12886
12987
|
fail(
|
|
@@ -12915,7 +13016,7 @@ var previewCommand = new Command("preview").description(
|
|
|
12915
13016
|
variation = exp.variations.find((v) => !v.is_control) ?? exp.variations[0];
|
|
12916
13017
|
}
|
|
12917
13018
|
spinner.stop();
|
|
12918
|
-
const storeUrl = opts?.storeUrl ?? exp.store_url;
|
|
13019
|
+
const storeUrl = opts?.storeUrl ?? exp.preview_target?.url ?? exp.store_url;
|
|
12919
13020
|
if (!storeUrl) {
|
|
12920
13021
|
fail(
|
|
12921
13022
|
previewCommand,
|
|
@@ -12933,11 +13034,24 @@ var previewCommand = new Command("preview").description(
|
|
|
12933
13034
|
}
|
|
12934
13035
|
output(
|
|
12935
13036
|
previewCommand,
|
|
12936
|
-
{
|
|
13037
|
+
{
|
|
13038
|
+
experimentId: exp.id,
|
|
13039
|
+
variationId: variation.id,
|
|
13040
|
+
previewUrl: previewUrl.toString(),
|
|
13041
|
+
...!opts?.storeUrl && exp.preview_target ? { previewTarget: exp.preview_target } : {}
|
|
13042
|
+
},
|
|
12937
13043
|
() => {
|
|
12938
13044
|
console.log();
|
|
12939
13045
|
console.log(source_default.bold(`Preview: ${exp.name}`));
|
|
12940
13046
|
console.log(`Variation: ${variation.name}${variation.is_control ? " (control)" : ""}`);
|
|
13047
|
+
if (!opts?.storeUrl && exp.preview_target) {
|
|
13048
|
+
console.log(`Chosen page: ${exp.preview_target.url} (${exp.preview_target.source})`);
|
|
13049
|
+
if (!exp.preview_target.matches_targeting) {
|
|
13050
|
+
console.log(
|
|
13051
|
+
`The test will not show on this page: ${exp.preview_target.reason ?? "The page does not match URL targeting."}`
|
|
13052
|
+
);
|
|
13053
|
+
}
|
|
13054
|
+
}
|
|
12941
13055
|
console.log();
|
|
12942
13056
|
console.log(source_default.cyan(previewUrl.toString()));
|
|
12943
13057
|
console.log();
|
|
@@ -15333,18 +15447,18 @@ function fieldsFrom(value, prefix = "", descriptorList = false) {
|
|
|
15333
15447
|
)
|
|
15334
15448
|
);
|
|
15335
15449
|
}
|
|
15336
|
-
const
|
|
15337
|
-
const explicitPath = typeof
|
|
15450
|
+
const record4 = value;
|
|
15451
|
+
const explicitPath = typeof record4.path === "string" ? record4.path : void 0;
|
|
15338
15452
|
if (descriptorList && explicitPath) {
|
|
15339
|
-
const rawValues =
|
|
15453
|
+
const rawValues = record4.values ?? record4.samples ?? record4.examples ?? record4.example;
|
|
15340
15454
|
const values = Array.isArray(rawValues) ? rawValues : rawValues === void 0 ? [] : [rawValues];
|
|
15341
|
-
const magnitude = [
|
|
15455
|
+
const magnitude = [record4.mean, record4.average, record4.max, record4.magnitude].find(
|
|
15342
15456
|
(candidate) => typeof candidate === "number"
|
|
15343
15457
|
);
|
|
15344
|
-
const numericType = Array.isArray(
|
|
15458
|
+
const numericType = Array.isArray(record4.types) && record4.types.length > 0 && record4.types.every((type) => type === "num" || type === "numstr" || type === "numstr_comma");
|
|
15345
15459
|
return [{ path: runtimePath(explicitPath), values, magnitude, numericType }];
|
|
15346
15460
|
}
|
|
15347
|
-
return Object.entries(
|
|
15461
|
+
return Object.entries(record4).flatMap(([key, child]) => {
|
|
15348
15462
|
if (["eventName", "event_name", "name", "count", "frequency", "evidence"].includes(key))
|
|
15349
15463
|
return [];
|
|
15350
15464
|
const next = prefix ? `${prefix}.${key}` : key;
|
|
@@ -15377,8 +15491,8 @@ function isDescriptorArray(value) {
|
|
|
15377
15491
|
]);
|
|
15378
15492
|
return Array.isArray(value) && value.length > 0 && value.every((item) => {
|
|
15379
15493
|
if (!item || typeof item !== "object" || Array.isArray(item)) return false;
|
|
15380
|
-
const
|
|
15381
|
-
return typeof
|
|
15494
|
+
const record4 = item;
|
|
15495
|
+
return typeof record4.path === "string" && record4.path.length > 0 && Object.keys(record4).every((key) => descriptorKeys.has(key));
|
|
15382
15496
|
});
|
|
15383
15497
|
}
|
|
15384
15498
|
function candidatesFrom(report) {
|
|
@@ -15534,10 +15648,10 @@ var whenOps = new Set(runtime_settings_trigger_constants_default.whenOps);
|
|
|
15534
15648
|
function strictObject(value, location, keys) {
|
|
15535
15649
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
15536
15650
|
throw new Error(`${location} must be an object`);
|
|
15537
|
-
const
|
|
15538
|
-
for (const key of Object.keys(
|
|
15651
|
+
const record4 = value;
|
|
15652
|
+
for (const key of Object.keys(record4))
|
|
15539
15653
|
if (!keys.has(key)) throw new Error(`${location}.${key} is not allowed`);
|
|
15540
|
-
return
|
|
15654
|
+
return record4;
|
|
15541
15655
|
}
|
|
15542
15656
|
function optionalType(value, type, location) {
|
|
15543
15657
|
if (value !== void 0 && typeof value !== type)
|
|
@@ -15673,19 +15787,19 @@ function strictTriggers(value) {
|
|
|
15673
15787
|
return value.map((item, index) => {
|
|
15674
15788
|
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
15675
15789
|
throw new Error(`trigger[${index}] must be an object`);
|
|
15676
|
-
const
|
|
15677
|
-
for (const key of Object.keys(
|
|
15790
|
+
const record4 = item;
|
|
15791
|
+
for (const key of Object.keys(record4))
|
|
15678
15792
|
if (!allowed.has(key)) throw new Error(`trigger[${index}].${key} is not allowed`);
|
|
15679
|
-
if (typeof
|
|
15793
|
+
if (typeof record4.eventName !== "string" || !record4.eventName.trim())
|
|
15680
15794
|
throw new Error(`trigger[${index}].eventName must be a non-empty string`);
|
|
15681
15795
|
for (const key of ["enabled", "reEvaluate", "trackPageview"])
|
|
15682
|
-
optionalType(
|
|
15796
|
+
optionalType(record4[key], "boolean", `trigger[${index}].${key}`);
|
|
15683
15797
|
for (const key of ["dataLayerName", "trackEventName"])
|
|
15684
|
-
optionalType(
|
|
15685
|
-
strictWhen(
|
|
15686
|
-
if (
|
|
15798
|
+
optionalType(record4[key], "string", `trigger[${index}].${key}`);
|
|
15799
|
+
strictWhen(record4.when, `trigger[${index}].when`);
|
|
15800
|
+
if (record4.trackRevenue !== void 0) {
|
|
15687
15801
|
const revenue = strictObject(
|
|
15688
|
-
|
|
15802
|
+
record4.trackRevenue,
|
|
15689
15803
|
`trigger[${index}].trackRevenue`,
|
|
15690
15804
|
/* @__PURE__ */ new Set([
|
|
15691
15805
|
"enabled",
|
|
@@ -15708,21 +15822,21 @@ function strictTriggers(value) {
|
|
|
15708
15822
|
);
|
|
15709
15823
|
}
|
|
15710
15824
|
}
|
|
15711
|
-
if (
|
|
15712
|
-
if (!Array.isArray(
|
|
15825
|
+
if (record4.mappings !== void 0) {
|
|
15826
|
+
if (!Array.isArray(record4.mappings))
|
|
15713
15827
|
throw new Error(`trigger[${index}].mappings must be an array`);
|
|
15714
|
-
|
|
15828
|
+
record4.mappings.forEach(
|
|
15715
15829
|
(mapping, mappingIndex) => strictMapping(mapping, `trigger[${index}].mappings[${mappingIndex}]`, false)
|
|
15716
15830
|
);
|
|
15717
15831
|
}
|
|
15718
|
-
if (
|
|
15719
|
-
if (!Array.isArray(
|
|
15832
|
+
if (record4.properties !== void 0) {
|
|
15833
|
+
if (!Array.isArray(record4.properties))
|
|
15720
15834
|
throw new Error(`trigger[${index}].properties must be an array`);
|
|
15721
|
-
|
|
15835
|
+
record4.properties.forEach(
|
|
15722
15836
|
(mapping, mappingIndex) => strictMapping(mapping, `trigger[${index}].properties[${mappingIndex}]`, true)
|
|
15723
15837
|
);
|
|
15724
15838
|
}
|
|
15725
|
-
return
|
|
15839
|
+
return record4;
|
|
15726
15840
|
});
|
|
15727
15841
|
}
|
|
15728
15842
|
function writeWarnings(result) {
|
|
@@ -16251,7 +16365,7 @@ function compare(a, b) {
|
|
|
16251
16365
|
const left = a.fraction.padEnd(precision, "0"), right = b.fraction.padEnd(precision, "0");
|
|
16252
16366
|
return left === right ? 0 : left < right ? -1 : 1;
|
|
16253
16367
|
}
|
|
16254
|
-
var
|
|
16368
|
+
var record2 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
16255
16369
|
var text = (v) => typeof v === "string" && v.length > 0;
|
|
16256
16370
|
var reason = (v) => typeof v === "string" && (/^[a-z][a-z0-9_]{0,79}$/.test(v) || /^(publishedConfig|consentPolicy|goalMapping|sdkArtifact|sdkPolicy|identityPolicy|goalDefinition|resultWindow|inputSnapshot)_(expected_unknown|observed_unknown|mismatch|binding_mismatch)$/.test(
|
|
16257
16371
|
v
|
|
@@ -16260,8 +16374,8 @@ var member = (v, values) => typeof v === "string" && values.includes(v);
|
|
|
16260
16374
|
var status = (v) => member(v, ["pass", "fail", "inconclusive"]);
|
|
16261
16375
|
var count = (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
|
|
16262
16376
|
function validReport(v) {
|
|
16263
|
-
if (!
|
|
16264
|
-
(s) =>
|
|
16377
|
+
if (!record2(v) || v.schemaVersion !== 1 || v.finalStatisticalContribution !== "not_evaluated" || !record2(v.evaluation) || !status(v.evaluation.status) || !member(v.evaluation.freshness, ["current", "stale", "unknown"]) || !Array.isArray(v.evaluation.stages) || !v.evaluation.stages.every(
|
|
16378
|
+
(s) => record2(s) && (s.freshness === void 0 || member(s.freshness, ["current", "stale", "unknown"])) && member(s.stage, [
|
|
16265
16379
|
"consent",
|
|
16266
16380
|
"assignment",
|
|
16267
16381
|
"event",
|
|
@@ -16273,17 +16387,17 @@ function validReport(v) {
|
|
|
16273
16387
|
))
|
|
16274
16388
|
return false;
|
|
16275
16389
|
if (v.receiptOutcomes !== void 0 && (!Array.isArray(v.receiptOutcomes) || v.receiptOutcomes.length > 6856 || !v.receiptOutcomes.every(
|
|
16276
|
-
(r) =>
|
|
16390
|
+
(r) => record2(r) && text(r.receiptId) && text(r.stage) && text(r.producerContract) && record2(r.scope) && [r.scope.experimentId, r.scope.variationId, r.scope.goalId].every(
|
|
16277
16391
|
(x) => x === null || text(x)
|
|
16278
16392
|
) && member(r.freshness, ["current", "stale", "unknown"]) && Array.isArray(r.reasonCodes) && r.reasonCodes.every(reason)
|
|
16279
16393
|
)))
|
|
16280
16394
|
return false;
|
|
16281
16395
|
const coverage = v.assignmentCoverage;
|
|
16282
|
-
if (!
|
|
16396
|
+
if (!record2(coverage) || typeof coverage.complete !== "boolean" || typeof coverage.overflowCountIsLowerBound !== "boolean" || !(coverage.overflowCount === null || count(coverage.overflowCount)))
|
|
16283
16397
|
return false;
|
|
16284
16398
|
return Array.isArray(v.assignments) && v.assignments.length <= 50 && v.assignments.every(
|
|
16285
|
-
(a) =>
|
|
16286
|
-
(g) =>
|
|
16399
|
+
(a) => record2(a) && text(a.experimentId) && text(a.variationId) && (a.storedAttribution === null || typeof a.storedAttribution === "boolean") && reason(a.reasonCode) && Array.isArray(a.goals) && a.goals.length <= 50 && a.goals.every(
|
|
16400
|
+
(g) => record2(g) && text(g.goalId) && member(g.status, [
|
|
16287
16401
|
"eligible_for_attributed_goal_read",
|
|
16288
16402
|
"excluded_from_attributed_goal_read",
|
|
16289
16403
|
"unknown"
|
|
@@ -16654,7 +16768,7 @@ var PURCHASE_CADENCE_WINDOW_MINUTES = PURCHASE_WINDOW_MINUTES * 4;
|
|
|
16654
16768
|
var MIN_CAPTURE_WINDOW_MINUTES = 60;
|
|
16655
16769
|
var DUPLICATE_RATE_THRESHOLD = 0.02;
|
|
16656
16770
|
var MAGNITUDE_TOLERANCE_RATE = 0.1;
|
|
16657
|
-
function
|
|
16771
|
+
function record3(value) {
|
|
16658
16772
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
16659
16773
|
}
|
|
16660
16774
|
function purchasePlane(config) {
|
|
@@ -16662,8 +16776,8 @@ function purchasePlane(config) {
|
|
|
16662
16776
|
const names = [];
|
|
16663
16777
|
const triggers = config.runtime?.dataLayerTriggers ?? config.dataLayerTriggers;
|
|
16664
16778
|
if (Array.isArray(triggers) && triggers.some((trigger) => {
|
|
16665
|
-
const row =
|
|
16666
|
-
const trackRevenue =
|
|
16779
|
+
const row = record3(trigger);
|
|
16780
|
+
const trackRevenue = record3(row?.trackRevenue);
|
|
16667
16781
|
return row?.enabled !== false && trackRevenue !== null && trackRevenue.enabled !== false;
|
|
16668
16782
|
}))
|
|
16669
16783
|
names.push("dataLayer trigger");
|
|
@@ -16705,7 +16819,7 @@ function lineItemSum(value) {
|
|
|
16705
16819
|
if (!Array.isArray(value)) return null;
|
|
16706
16820
|
let sum = 0;
|
|
16707
16821
|
for (const item of value) {
|
|
16708
|
-
const row =
|
|
16822
|
+
const row = record3(item);
|
|
16709
16823
|
const price = numeric(row?.price);
|
|
16710
16824
|
if (price === null) return null;
|
|
16711
16825
|
sum += price * (numeric(row?.quantity) ?? 1);
|
|
@@ -18245,10 +18359,10 @@ function getEdgeDeliveryStatus(deliveryType, expectedWorstCaseSeconds = 360) {
|
|
|
18245
18359
|
return deliveryType === "api" ? { edge_delivery: "not_applicable", message: `API-delivered flag \u2014 edge delivery is not applicable. A previously cached visual payload may remain at some PoPs for up to ~${expectedWorstCaseSeconds}s; a single-vantage status cannot prove global propagation.` } : { edge_delivery: "applicable", message: null };
|
|
18246
18360
|
}
|
|
18247
18361
|
function parsePublicationMetadata(value) {
|
|
18248
|
-
const
|
|
18362
|
+
const record4 = value && typeof value === "object" ? value : {};
|
|
18249
18363
|
return {
|
|
18250
|
-
publication_revision: Number.isSafeInteger(
|
|
18251
|
-
generated_at: typeof
|
|
18364
|
+
publication_revision: Number.isSafeInteger(record4.publication_revision) && record4.publication_revision >= 0 ? record4.publication_revision : null,
|
|
18365
|
+
generated_at: typeof record4.generated_at === "string" && !Number.isNaN(Date.parse(record4.generated_at)) ? record4.generated_at : null
|
|
18252
18366
|
};
|
|
18253
18367
|
}
|
|
18254
18368
|
function compareEdgePublication(currentValue, edgeValue, expectedWorstCaseSeconds, flagUpdatedAtValue, confirmedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|