@drip-apex/apex-cli 0.16.0 → 0.17.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 +9 -0
- package/dist/cli.js +1172 -797
- package/package.json +1 -1
- package/skills/apex-cli/SKILL.md +6 -0
package/dist/cli.js
CHANGED
|
@@ -127,11 +127,11 @@ var require_argument = __commonJS({
|
|
|
127
127
|
/**
|
|
128
128
|
* @package
|
|
129
129
|
*/
|
|
130
|
-
_concatValue(
|
|
130
|
+
_concatValue(value2, previous) {
|
|
131
131
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
132
|
-
return [
|
|
132
|
+
return [value2];
|
|
133
133
|
}
|
|
134
|
-
return previous.concat(
|
|
134
|
+
return previous.concat(value2);
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Set the default value, and optionally supply the description to be displayed in the help.
|
|
@@ -140,8 +140,8 @@ var require_argument = __commonJS({
|
|
|
140
140
|
* @param {string} [description]
|
|
141
141
|
* @return {Argument}
|
|
142
142
|
*/
|
|
143
|
-
default(
|
|
144
|
-
this.defaultValue =
|
|
143
|
+
default(value2, description) {
|
|
144
|
+
this.defaultValue = value2;
|
|
145
145
|
this.defaultValueDescription = description;
|
|
146
146
|
return this;
|
|
147
147
|
}
|
|
@@ -815,8 +815,8 @@ var require_option = __commonJS({
|
|
|
815
815
|
* @param {string} [description]
|
|
816
816
|
* @return {Option}
|
|
817
817
|
*/
|
|
818
|
-
default(
|
|
819
|
-
this.defaultValue =
|
|
818
|
+
default(value2, description) {
|
|
819
|
+
this.defaultValue = value2;
|
|
820
820
|
this.defaultValueDescription = description;
|
|
821
821
|
return this;
|
|
822
822
|
}
|
|
@@ -917,11 +917,11 @@ var require_option = __commonJS({
|
|
|
917
917
|
/**
|
|
918
918
|
* @package
|
|
919
919
|
*/
|
|
920
|
-
_concatValue(
|
|
920
|
+
_concatValue(value2, previous) {
|
|
921
921
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
922
|
-
return [
|
|
922
|
+
return [value2];
|
|
923
923
|
}
|
|
924
|
-
return previous.concat(
|
|
924
|
+
return previous.concat(value2);
|
|
925
925
|
}
|
|
926
926
|
/**
|
|
927
927
|
* Only allow option value to be one of choices.
|
|
@@ -1004,7 +1004,7 @@ var require_option = __commonJS({
|
|
|
1004
1004
|
this.positiveOptions.set(option.attributeName(), option);
|
|
1005
1005
|
}
|
|
1006
1006
|
});
|
|
1007
|
-
this.negativeOptions.forEach((
|
|
1007
|
+
this.negativeOptions.forEach((value2, key) => {
|
|
1008
1008
|
if (this.positiveOptions.has(key)) {
|
|
1009
1009
|
this.dualOptions.add(key);
|
|
1010
1010
|
}
|
|
@@ -1017,12 +1017,12 @@ var require_option = __commonJS({
|
|
|
1017
1017
|
* @param {Option} option
|
|
1018
1018
|
* @returns {boolean}
|
|
1019
1019
|
*/
|
|
1020
|
-
valueFromOption(
|
|
1020
|
+
valueFromOption(value2, option) {
|
|
1021
1021
|
const optionKey = option.attributeName();
|
|
1022
1022
|
if (!this.dualOptions.has(optionKey)) return true;
|
|
1023
1023
|
const preset = this.negativeOptions.get(optionKey).presetArg;
|
|
1024
1024
|
const negativeValue = preset !== void 0 ? preset : false;
|
|
1025
|
-
return option.negate === (negativeValue ===
|
|
1025
|
+
return option.negate === (negativeValue === value2);
|
|
1026
1026
|
}
|
|
1027
1027
|
};
|
|
1028
1028
|
function camelcase(str) {
|
|
@@ -1159,8 +1159,8 @@ var require_command = __commonJS({
|
|
|
1159
1159
|
"node_modules/commander/lib/command.js"(exports2) {
|
|
1160
1160
|
var EventEmitter = require("node:events").EventEmitter;
|
|
1161
1161
|
var childProcess2 = require("node:child_process");
|
|
1162
|
-
var
|
|
1163
|
-
var
|
|
1162
|
+
var path27 = require("node:path");
|
|
1163
|
+
var fs31 = require("node:fs");
|
|
1164
1164
|
var process16 = require("node:process");
|
|
1165
1165
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1166
1166
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1650,9 +1650,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1650
1650
|
* @param {string} invalidArgumentMessage
|
|
1651
1651
|
* @private
|
|
1652
1652
|
*/
|
|
1653
|
-
_callParseArg(target,
|
|
1653
|
+
_callParseArg(target, value2, previous, invalidArgumentMessage) {
|
|
1654
1654
|
try {
|
|
1655
|
-
return target.parseArg(
|
|
1655
|
+
return target.parseArg(value2, previous);
|
|
1656
1656
|
} catch (err) {
|
|
1657
1657
|
if (err.code === "commander.invalidArgument") {
|
|
1658
1658
|
const message = `${invalidArgumentMessage} ${err.message}`;
|
|
@@ -1937,8 +1937,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1937
1937
|
* @param {object} value
|
|
1938
1938
|
* @return {Command} `this` command for chaining
|
|
1939
1939
|
*/
|
|
1940
|
-
setOptionValue(key,
|
|
1941
|
-
return this.setOptionValueWithSource(key,
|
|
1940
|
+
setOptionValue(key, value2) {
|
|
1941
|
+
return this.setOptionValueWithSource(key, value2, void 0);
|
|
1942
1942
|
}
|
|
1943
1943
|
/**
|
|
1944
1944
|
* Store option value and where the value came from.
|
|
@@ -1948,11 +1948,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1948
1948
|
* @param {string} source - expected values are default/config/env/cli/implied
|
|
1949
1949
|
* @return {Command} `this` command for chaining
|
|
1950
1950
|
*/
|
|
1951
|
-
setOptionValueWithSource(key,
|
|
1951
|
+
setOptionValueWithSource(key, value2, source) {
|
|
1952
1952
|
if (this._storeOptionsAsProperties) {
|
|
1953
|
-
this[key] =
|
|
1953
|
+
this[key] = value2;
|
|
1954
1954
|
} else {
|
|
1955
|
-
this._optionValues[key] =
|
|
1955
|
+
this._optionValues[key] = value2;
|
|
1956
1956
|
}
|
|
1957
1957
|
this._optionValueSources[key] = source;
|
|
1958
1958
|
return this;
|
|
@@ -2141,7 +2141,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2141
2141
|
* @param {string} subcommandName
|
|
2142
2142
|
*/
|
|
2143
2143
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
2144
|
-
if (
|
|
2144
|
+
if (fs31.existsSync(executableFile)) return;
|
|
2145
2145
|
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
2146
2146
|
const executableMissing = `'${executableFile}' does not exist
|
|
2147
2147
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -2159,11 +2159,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2159
2159
|
let launchWithNode = false;
|
|
2160
2160
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2161
2161
|
function findFile(baseDir, baseName) {
|
|
2162
|
-
const localBin =
|
|
2163
|
-
if (
|
|
2164
|
-
if (sourceExt.includes(
|
|
2162
|
+
const localBin = path27.resolve(baseDir, baseName);
|
|
2163
|
+
if (fs31.existsSync(localBin)) return localBin;
|
|
2164
|
+
if (sourceExt.includes(path27.extname(baseName))) return void 0;
|
|
2165
2165
|
const foundExt = sourceExt.find(
|
|
2166
|
-
(ext) =>
|
|
2166
|
+
(ext) => fs31.existsSync(`${localBin}${ext}`)
|
|
2167
2167
|
);
|
|
2168
2168
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
2169
2169
|
return void 0;
|
|
@@ -2175,21 +2175,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2175
2175
|
if (this._scriptPath) {
|
|
2176
2176
|
let resolvedScriptPath;
|
|
2177
2177
|
try {
|
|
2178
|
-
resolvedScriptPath =
|
|
2178
|
+
resolvedScriptPath = fs31.realpathSync(this._scriptPath);
|
|
2179
2179
|
} catch {
|
|
2180
2180
|
resolvedScriptPath = this._scriptPath;
|
|
2181
2181
|
}
|
|
2182
|
-
executableDir =
|
|
2183
|
-
|
|
2182
|
+
executableDir = path27.resolve(
|
|
2183
|
+
path27.dirname(resolvedScriptPath),
|
|
2184
2184
|
executableDir
|
|
2185
2185
|
);
|
|
2186
2186
|
}
|
|
2187
2187
|
if (executableDir) {
|
|
2188
2188
|
let localFile = findFile(executableDir, executableFile);
|
|
2189
2189
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2190
|
-
const legacyName =
|
|
2190
|
+
const legacyName = path27.basename(
|
|
2191
2191
|
this._scriptPath,
|
|
2192
|
-
|
|
2192
|
+
path27.extname(this._scriptPath)
|
|
2193
2193
|
);
|
|
2194
2194
|
if (legacyName !== this._name) {
|
|
2195
2195
|
localFile = findFile(
|
|
@@ -2200,7 +2200,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2200
2200
|
}
|
|
2201
2201
|
executableFile = localFile || executableFile;
|
|
2202
2202
|
}
|
|
2203
|
-
launchWithNode = sourceExt.includes(
|
|
2203
|
+
launchWithNode = sourceExt.includes(path27.extname(executableFile));
|
|
2204
2204
|
let proc;
|
|
2205
2205
|
if (process16.platform !== "win32") {
|
|
2206
2206
|
if (launchWithNode) {
|
|
@@ -2335,13 +2335,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2335
2335
|
* @private
|
|
2336
2336
|
*/
|
|
2337
2337
|
_processArguments() {
|
|
2338
|
-
const myParseArg = (argument,
|
|
2339
|
-
let parsedValue =
|
|
2340
|
-
if (
|
|
2341
|
-
const invalidValueMessage = `error: command-argument value '${
|
|
2338
|
+
const myParseArg = (argument, value2, previous) => {
|
|
2339
|
+
let parsedValue = value2;
|
|
2340
|
+
if (value2 !== null && argument.parseArg) {
|
|
2341
|
+
const invalidValueMessage = `error: command-argument value '${value2}' is invalid for argument '${argument.name()}'.`;
|
|
2342
2342
|
parsedValue = this._callParseArg(
|
|
2343
2343
|
argument,
|
|
2344
|
-
|
|
2344
|
+
value2,
|
|
2345
2345
|
previous,
|
|
2346
2346
|
invalidValueMessage
|
|
2347
2347
|
);
|
|
@@ -2351,25 +2351,25 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2351
2351
|
this._checkNumberOfArguments();
|
|
2352
2352
|
const processedArgs = [];
|
|
2353
2353
|
this.registeredArguments.forEach((declaredArg, index) => {
|
|
2354
|
-
let
|
|
2354
|
+
let value2 = declaredArg.defaultValue;
|
|
2355
2355
|
if (declaredArg.variadic) {
|
|
2356
2356
|
if (index < this.args.length) {
|
|
2357
|
-
|
|
2357
|
+
value2 = this.args.slice(index);
|
|
2358
2358
|
if (declaredArg.parseArg) {
|
|
2359
|
-
|
|
2359
|
+
value2 = value2.reduce((processed, v) => {
|
|
2360
2360
|
return myParseArg(declaredArg, v, processed);
|
|
2361
2361
|
}, declaredArg.defaultValue);
|
|
2362
2362
|
}
|
|
2363
|
-
} else if (
|
|
2364
|
-
|
|
2363
|
+
} else if (value2 === void 0) {
|
|
2364
|
+
value2 = [];
|
|
2365
2365
|
}
|
|
2366
2366
|
} else if (index < this.args.length) {
|
|
2367
|
-
|
|
2367
|
+
value2 = this.args[index];
|
|
2368
2368
|
if (declaredArg.parseArg) {
|
|
2369
|
-
|
|
2369
|
+
value2 = myParseArg(declaredArg, value2, declaredArg.defaultValue);
|
|
2370
2370
|
}
|
|
2371
2371
|
}
|
|
2372
|
-
processedArgs[index] =
|
|
2372
|
+
processedArgs[index] = value2;
|
|
2373
2373
|
});
|
|
2374
2374
|
this.processedArgs = processedArgs;
|
|
2375
2375
|
}
|
|
@@ -2626,15 +2626,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2626
2626
|
const option = this._findOption(arg);
|
|
2627
2627
|
if (option) {
|
|
2628
2628
|
if (option.required) {
|
|
2629
|
-
const
|
|
2630
|
-
if (
|
|
2631
|
-
this.emit(`option:${option.name()}`,
|
|
2629
|
+
const value2 = args.shift();
|
|
2630
|
+
if (value2 === void 0) this.optionMissingArgument(option);
|
|
2631
|
+
this.emit(`option:${option.name()}`, value2);
|
|
2632
2632
|
} else if (option.optional) {
|
|
2633
|
-
let
|
|
2633
|
+
let value2 = null;
|
|
2634
2634
|
if (args.length > 0 && !maybeOption(args[0])) {
|
|
2635
|
-
|
|
2635
|
+
value2 = args.shift();
|
|
2636
2636
|
}
|
|
2637
|
-
this.emit(`option:${option.name()}`,
|
|
2637
|
+
this.emit(`option:${option.name()}`, value2);
|
|
2638
2638
|
} else {
|
|
2639
2639
|
this.emit(`option:${option.name()}`);
|
|
2640
2640
|
}
|
|
@@ -3047,7 +3047,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3047
3047
|
* @return {Command}
|
|
3048
3048
|
*/
|
|
3049
3049
|
nameFromFilename(filename) {
|
|
3050
|
-
this._name =
|
|
3050
|
+
this._name = path27.basename(filename, path27.extname(filename));
|
|
3051
3051
|
return this;
|
|
3052
3052
|
}
|
|
3053
3053
|
/**
|
|
@@ -3061,9 +3061,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3061
3061
|
* @param {string} [path]
|
|
3062
3062
|
* @return {(string|null|Command)}
|
|
3063
3063
|
*/
|
|
3064
|
-
executableDir(
|
|
3065
|
-
if (
|
|
3066
|
-
this._executableDir =
|
|
3064
|
+
executableDir(path28) {
|
|
3065
|
+
if (path28 === void 0) return this._executableDir;
|
|
3066
|
+
this._executableDir = path28;
|
|
3067
3067
|
return this;
|
|
3068
3068
|
}
|
|
3069
3069
|
/**
|
|
@@ -3427,12 +3427,12 @@ function assembleStyles() {
|
|
|
3427
3427
|
green = Math.floor(remainder / 6) / 5;
|
|
3428
3428
|
blue = remainder % 6 / 5;
|
|
3429
3429
|
}
|
|
3430
|
-
const
|
|
3431
|
-
if (
|
|
3430
|
+
const value2 = Math.max(red, green, blue) * 2;
|
|
3431
|
+
if (value2 === 0) {
|
|
3432
3432
|
return 30;
|
|
3433
3433
|
}
|
|
3434
3434
|
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
3435
|
-
if (
|
|
3435
|
+
if (value2 === 2) {
|
|
3436
3436
|
result += 60;
|
|
3437
3437
|
}
|
|
3438
3438
|
return result;
|
|
@@ -6295,22 +6295,22 @@ var init_ora = __esm({
|
|
|
6295
6295
|
get text() {
|
|
6296
6296
|
return this.#text;
|
|
6297
6297
|
}
|
|
6298
|
-
set text(
|
|
6299
|
-
this.#text =
|
|
6298
|
+
set text(value2 = "") {
|
|
6299
|
+
this.#text = value2;
|
|
6300
6300
|
this.#updateLineCount();
|
|
6301
6301
|
}
|
|
6302
6302
|
get prefixText() {
|
|
6303
6303
|
return this.#prefixText;
|
|
6304
6304
|
}
|
|
6305
|
-
set prefixText(
|
|
6306
|
-
this.#prefixText =
|
|
6305
|
+
set prefixText(value2 = "") {
|
|
6306
|
+
this.#prefixText = value2;
|
|
6307
6307
|
this.#updateLineCount();
|
|
6308
6308
|
}
|
|
6309
6309
|
get suffixText() {
|
|
6310
6310
|
return this.#suffixText;
|
|
6311
6311
|
}
|
|
6312
|
-
set suffixText(
|
|
6313
|
-
this.#suffixText =
|
|
6312
|
+
set suffixText(value2 = "") {
|
|
6313
|
+
this.#suffixText = value2;
|
|
6314
6314
|
this.#updateLineCount();
|
|
6315
6315
|
}
|
|
6316
6316
|
get isSpinning() {
|
|
@@ -6347,20 +6347,20 @@ var init_ora = __esm({
|
|
|
6347
6347
|
get isEnabled() {
|
|
6348
6348
|
return this.#isEnabled && !this.#isSilent;
|
|
6349
6349
|
}
|
|
6350
|
-
set isEnabled(
|
|
6351
|
-
if (typeof
|
|
6350
|
+
set isEnabled(value2) {
|
|
6351
|
+
if (typeof value2 !== "boolean") {
|
|
6352
6352
|
throw new TypeError("The `isEnabled` option must be a boolean");
|
|
6353
6353
|
}
|
|
6354
|
-
this.#isEnabled =
|
|
6354
|
+
this.#isEnabled = value2;
|
|
6355
6355
|
}
|
|
6356
6356
|
get isSilent() {
|
|
6357
6357
|
return this.#isSilent;
|
|
6358
6358
|
}
|
|
6359
|
-
set isSilent(
|
|
6360
|
-
if (typeof
|
|
6359
|
+
set isSilent(value2) {
|
|
6360
|
+
if (typeof value2 !== "boolean") {
|
|
6361
6361
|
throw new TypeError("The `isSilent` option must be a boolean");
|
|
6362
6362
|
}
|
|
6363
|
-
this.#isSilent =
|
|
6363
|
+
this.#isSilent = value2;
|
|
6364
6364
|
}
|
|
6365
6365
|
frame() {
|
|
6366
6366
|
const now = Date.now();
|
|
@@ -6613,7 +6613,7 @@ var init_wsl_utils = __esm({
|
|
|
6613
6613
|
|
|
6614
6614
|
// node_modules/define-lazy-prop/index.js
|
|
6615
6615
|
function defineLazyProperty(object, propertyName, valueGetter) {
|
|
6616
|
-
const define = (
|
|
6616
|
+
const define = (value2) => Object.defineProperty(object, propertyName, { value: value2, enumerable: true, writable: true });
|
|
6617
6617
|
Object.defineProperty(object, propertyName, {
|
|
6618
6618
|
configurable: true,
|
|
6619
6619
|
enumerable: true,
|
|
@@ -6622,8 +6622,8 @@ function defineLazyProperty(object, propertyName, valueGetter) {
|
|
|
6622
6622
|
define(result);
|
|
6623
6623
|
return result;
|
|
6624
6624
|
},
|
|
6625
|
-
set(
|
|
6626
|
-
define(
|
|
6625
|
+
set(value2) {
|
|
6626
|
+
define(value2);
|
|
6627
6627
|
}
|
|
6628
6628
|
});
|
|
6629
6629
|
return object;
|
|
@@ -7092,8 +7092,8 @@ var import_node_crypto2 = require("node:crypto");
|
|
|
7092
7092
|
var import_node_crypto = require("node:crypto");
|
|
7093
7093
|
var invocationId = (0, import_node_crypto.randomUUID)();
|
|
7094
7094
|
var identity;
|
|
7095
|
-
function setClientIdentity(
|
|
7096
|
-
identity = { ...
|
|
7095
|
+
function setClientIdentity(value2) {
|
|
7096
|
+
identity = { ...value2, invocationId };
|
|
7097
7097
|
}
|
|
7098
7098
|
function getClientIdentity() {
|
|
7099
7099
|
return identity ? { ...identity } : void 0;
|
|
@@ -7124,7 +7124,7 @@ function extractErrorDetails(json) {
|
|
|
7124
7124
|
if (!json) return void 0;
|
|
7125
7125
|
const nested = json.error && typeof json.error === "object" && !Array.isArray(json.error) ? json.error : null;
|
|
7126
7126
|
const code = typeof json.code === "string" ? json.code : typeof nested?.code === "string" ? nested.code : void 0;
|
|
7127
|
-
for (const
|
|
7127
|
+
for (const value2 of [json.details, json.meta, nested?.details]) if (value2 && typeof value2 === "object" && !Array.isArray(value2)) return { ...value2, ...code ? { code } : {} };
|
|
7128
7128
|
const details = Object.fromEntries(["limit", "current", "max", "actual", "field", "code"].filter((key) => key in json).map((key) => [key, json[key]]));
|
|
7129
7129
|
if (code) details.code = code;
|
|
7130
7130
|
return Object.keys(details).length ? details : void 0;
|
|
@@ -7133,23 +7133,23 @@ var warnedAboutVersionSkew = false;
|
|
|
7133
7133
|
function createHttpClient(creds, options) {
|
|
7134
7134
|
const warn3 = options.warn ?? ((message) => process.stderr.write(message));
|
|
7135
7135
|
function inspectVersion(headers) {
|
|
7136
|
-
const
|
|
7137
|
-
if (!
|
|
7138
|
-
const version = Number(
|
|
7136
|
+
const value2 = headers.get(APEX_API_VERSION_HEADER);
|
|
7137
|
+
if (!value2 || warnedAboutVersionSkew) return;
|
|
7138
|
+
const version = Number(value2);
|
|
7139
7139
|
if (!Number.isFinite(version) || version === Number(SUPPORTED_APEX_API_VERSION)) return;
|
|
7140
7140
|
warnedAboutVersionSkew = true;
|
|
7141
7141
|
warn3(version > 1 ? "CLI is behind the server \u2014 update.\n" : "Server API is older than this CLI supports.\n");
|
|
7142
7142
|
}
|
|
7143
|
-
async function request2(method,
|
|
7143
|
+
async function request2(method, path27, body5, requestTimeoutMs, form = false, requestOptions) {
|
|
7144
7144
|
const started2 = performance.now();
|
|
7145
7145
|
const observe = (status4, requestId2, errorCode, responseHeaders) => {
|
|
7146
7146
|
const semver = (name) => {
|
|
7147
|
-
const
|
|
7148
|
-
return
|
|
7147
|
+
const value2 = responseHeaders?.get(name) ?? void 0;
|
|
7148
|
+
return value2 && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value2) ? value2 : void 0;
|
|
7149
7149
|
};
|
|
7150
7150
|
const serverTiming = responseHeaders?.get("server-timing");
|
|
7151
7151
|
try {
|
|
7152
|
-
options.onResponse?.({ method, path:
|
|
7152
|
+
options.onResponse?.({ method, path: path27, status: status4, requestId: requestId2, errorCode: typeof errorCode === "string" ? errorCode : void 0, durationMs: Math.max(0, Math.round(performance.now() - started2)), serverTiming: serverTiming?.slice(0, 300) || void 0, cliLatest: semver("x-apex-cli-latest"), cliMinimum: semver("x-apex-cli-minimum") });
|
|
7153
7153
|
} catch {
|
|
7154
7154
|
}
|
|
7155
7155
|
};
|
|
@@ -7165,7 +7165,7 @@ function createHttpClient(creds, options) {
|
|
|
7165
7165
|
if (creds.resolvedContext?.orgId) headers["X-Apex-Org"] = creds.resolvedContext.orgId;
|
|
7166
7166
|
if (creds.resolvedContext?.shopId) headers["X-Apex-Shop"] = creds.resolvedContext.shopId;
|
|
7167
7167
|
}
|
|
7168
|
-
const mock = options.transport?.(method,
|
|
7168
|
+
const mock = options.transport?.(method, path27, body5, headers);
|
|
7169
7169
|
if (mock !== void 0) {
|
|
7170
7170
|
const version = options.testTransportVersion?.();
|
|
7171
7171
|
if (version) inspectVersion(new Headers({ [APEX_API_VERSION_HEADER]: version }));
|
|
@@ -7174,7 +7174,7 @@ function createHttpClient(creds, options) {
|
|
|
7174
7174
|
}
|
|
7175
7175
|
let response;
|
|
7176
7176
|
try {
|
|
7177
|
-
response = await fetch(`${creds.baseUrl}${
|
|
7177
|
+
response = await fetch(`${creds.baseUrl}${path27}`, { method, headers, body: form ? body5 : body5 ? JSON.stringify(body5) : void 0, signal: AbortSignal.timeout(timeoutMs) });
|
|
7178
7178
|
} catch (error) {
|
|
7179
7179
|
const outer = error && typeof error === "object" ? error : void 0;
|
|
7180
7180
|
const nested = outer?.cause && typeof outer.cause === "object" ? outer.cause : void 0;
|
|
@@ -7195,7 +7195,7 @@ function createHttpClient(creds, options) {
|
|
|
7195
7195
|
if (!response.ok) return { ok: false, status: response.status, data: json, error: extractErrorMessage(json, response.status), errorDetails: extractErrorDetails(json), requestId, retryAfter: response.headers.get("retry-after"), rateLimit: { limit: response.headers.get("x-ratelimit-limit"), remaining: response.headers.get("x-ratelimit-remaining"), reset: response.headers.get("x-ratelimit-reset") } };
|
|
7196
7196
|
return { ok: true, status: response.status, data: json };
|
|
7197
7197
|
}
|
|
7198
|
-
return { request: (method,
|
|
7198
|
+
return { request: (method, path27, body5, timeoutMs, requestOptions) => request2(method, path27, body5, timeoutMs, false, requestOptions), requestForm: (method, path27, body5) => request2(method, path27, body5, void 0, true) };
|
|
7199
7199
|
}
|
|
7200
7200
|
|
|
7201
7201
|
// ../api-client/src/credentials.ts
|
|
@@ -7286,18 +7286,18 @@ function compareVersions(left, right) {
|
|
|
7286
7286
|
}
|
|
7287
7287
|
function readCache() {
|
|
7288
7288
|
try {
|
|
7289
|
-
const
|
|
7290
|
-
return
|
|
7289
|
+
const value2 = JSON.parse((0, import_node_fs2.readFileSync)(cachePath(), "utf8"));
|
|
7290
|
+
return value2 && typeof value2 === "object" ? value2 : {};
|
|
7291
7291
|
} catch {
|
|
7292
7292
|
return {};
|
|
7293
7293
|
}
|
|
7294
7294
|
}
|
|
7295
7295
|
function writeCache(patch, remove5 = []) {
|
|
7296
7296
|
try {
|
|
7297
|
-
const
|
|
7298
|
-
for (const key of remove5) delete
|
|
7297
|
+
const value2 = { ...readCache(), ...patch };
|
|
7298
|
+
for (const key of remove5) delete value2[key];
|
|
7299
7299
|
(0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(cachePath()), { recursive: true });
|
|
7300
|
-
(0, import_node_fs2.writeFileSync)(cachePath(), JSON.stringify(
|
|
7300
|
+
(0, import_node_fs2.writeFileSync)(cachePath(), JSON.stringify(value2), { mode: 384 });
|
|
7301
7301
|
} catch {
|
|
7302
7302
|
}
|
|
7303
7303
|
}
|
|
@@ -7362,7 +7362,7 @@ function clearUpdateCache() {
|
|
|
7362
7362
|
function currentUpdateState(current, minimumOverride) {
|
|
7363
7363
|
if (minimumOverride && versionParts(minimumOverride))
|
|
7364
7364
|
recordServerCliPolicy({ cliMinimum: minimumOverride });
|
|
7365
|
-
const latest = [npmLatest, serverLatest, serverMinimum, current].filter((
|
|
7365
|
+
const latest = [npmLatest, serverLatest, serverMinimum, current].filter((value2) => Boolean(value2)).reduce((highest, value2) => compareVersions(value2, highest) > 0 ? value2 : highest, current);
|
|
7366
7366
|
const minimum = serverMinimum;
|
|
7367
7367
|
const required = Boolean(minimum && compareVersions(current, minimum) < 0);
|
|
7368
7368
|
if (!required && process.env.APEX_NO_UPDATE_CHECK === "1") return;
|
|
@@ -7423,7 +7423,7 @@ async function checkForUpdate(current) {
|
|
|
7423
7423
|
// package.json
|
|
7424
7424
|
var package_default = {
|
|
7425
7425
|
name: "@drip-apex/apex-cli",
|
|
7426
|
-
version: "0.
|
|
7426
|
+
version: "0.17.0",
|
|
7427
7427
|
license: "MIT",
|
|
7428
7428
|
description: "Apex CLI for managing experiments, approved roadmap ideas, and draft workspaces.",
|
|
7429
7429
|
private: false,
|
|
@@ -7771,8 +7771,8 @@ process.on?.("beforeExit", writePendingUpdateNotice);
|
|
|
7771
7771
|
function minimumFromError(error, reason2) {
|
|
7772
7772
|
if (reason2 !== "cli_upgrade_required") return;
|
|
7773
7773
|
const api = error.api?.body;
|
|
7774
|
-
const
|
|
7775
|
-
return typeof
|
|
7774
|
+
const value2 = error.details?.minimum ?? api?.error?.details?.minimum;
|
|
7775
|
+
return typeof value2 === "string" ? value2 : void 0;
|
|
7776
7776
|
}
|
|
7777
7777
|
async function handleCliError(err, command) {
|
|
7778
7778
|
if (err && typeof err === "object" && "exitCode" in err && err.exitCode === 0) {
|
|
@@ -8384,9 +8384,9 @@ var staticRouteSegments = /* @__PURE__ */ new Set([
|
|
|
8384
8384
|
"webhooks",
|
|
8385
8385
|
"workspace"
|
|
8386
8386
|
]);
|
|
8387
|
-
function normalizeRoute(
|
|
8388
|
-
if (!
|
|
8389
|
-
const parts =
|
|
8387
|
+
function normalizeRoute(path27) {
|
|
8388
|
+
if (!path27.startsWith("/api/")) return ":route";
|
|
8389
|
+
const parts = path27.split(/[?#]/, 1)[0].split("/");
|
|
8390
8390
|
const files = parts.indexOf("files");
|
|
8391
8391
|
if (files !== -1 && parts.length > files + 1) parts.splice(files + 1, parts.length, ":id");
|
|
8392
8392
|
return parts.map((part) => !part || staticRouteSegments.has(part) ? part : ":id").join("/");
|
|
@@ -8438,19 +8438,19 @@ function classifyError(exitCode, error, status4) {
|
|
|
8438
8438
|
function redactAttempted(token) {
|
|
8439
8439
|
return /^(?:apx_|sk_|pk_|rk_|ghp_|gho_|xox|Bearer)/.test(token) || /^[A-Za-z0-9_-]{24,}$/.test(token) || /:\/\/|[/\\@=]/.test(token) || token.length > 40 ? "(redacted)" : token;
|
|
8440
8440
|
}
|
|
8441
|
-
function normalizeErrorCode(
|
|
8442
|
-
const normalized =
|
|
8441
|
+
function normalizeErrorCode(value2, exitCode) {
|
|
8442
|
+
const normalized = value2.toLowerCase();
|
|
8443
8443
|
return normalized.length <= 64 && /^[a-z0-9._-]+$/.test(normalized) ? normalized : `exit_${exitCode}`;
|
|
8444
8444
|
}
|
|
8445
8445
|
function invocationErrorCode(exitCode, error, commanderExit) {
|
|
8446
8446
|
if (exitCode === 0) return void 0;
|
|
8447
|
-
let
|
|
8448
|
-
if (!
|
|
8449
|
-
|
|
8447
|
+
let value2 = firstError?.errorCode;
|
|
8448
|
+
if (!value2 && firstError)
|
|
8449
|
+
value2 = firstError.status === 410 ? "gone" : `http_${firstError.status}`;
|
|
8450
8450
|
const detail5 = error && typeof error === "object" ? error : {};
|
|
8451
|
-
if (!
|
|
8451
|
+
if (!value2 && typeof detail5.details?.reason === "string" && !detail5.api) {
|
|
8452
8452
|
const reason2 = detail5.details.reason.toLowerCase();
|
|
8453
|
-
|
|
8453
|
+
value2 = [
|
|
8454
8454
|
"network",
|
|
8455
8455
|
"dns",
|
|
8456
8456
|
"timeout",
|
|
@@ -8461,20 +8461,20 @@ function invocationErrorCode(exitCode, error, commanderExit) {
|
|
|
8461
8461
|
"unknown"
|
|
8462
8462
|
].includes(reason2) ? `network_${reason2}` : reason2 || void 0;
|
|
8463
8463
|
}
|
|
8464
|
-
if (!
|
|
8465
|
-
|
|
8466
|
-
if (!
|
|
8464
|
+
if (!value2 && commanderExit && typeof detail5.code === "string")
|
|
8465
|
+
value2 = detail5.code.slice("commander.".length).replace(/([a-z])([A-Z])/g, "$1_$2");
|
|
8466
|
+
if (!value2) {
|
|
8467
8467
|
const apiCode = detail5.api?.body?.code ?? detail5.api?.body?.error?.code ?? detail5.details?.code;
|
|
8468
|
-
if (typeof apiCode === "string" && apiCode)
|
|
8469
|
-
else if (detail5.api?.status === 401 || exitCode === 2)
|
|
8470
|
-
else if (detail5.api?.status === 403)
|
|
8471
|
-
else if (detail5.api?.status === 404)
|
|
8472
|
-
else if (detail5.api?.status === 429)
|
|
8473
|
-
else if (detail5.api?.status === 409 || exitCode === 5)
|
|
8474
|
-
else if (exitCode === 4)
|
|
8475
|
-
else if (exitCode === 3)
|
|
8468
|
+
if (typeof apiCode === "string" && apiCode) value2 = apiCode;
|
|
8469
|
+
else if (detail5.api?.status === 401 || exitCode === 2) value2 = "auth_required";
|
|
8470
|
+
else if (detail5.api?.status === 403) value2 = "auth_forbidden";
|
|
8471
|
+
else if (detail5.api?.status === 404) value2 = "not_found";
|
|
8472
|
+
else if (detail5.api?.status === 429) value2 = "rate_limited";
|
|
8473
|
+
else if (detail5.api?.status === 409 || exitCode === 5) value2 = "conflict";
|
|
8474
|
+
else if (exitCode === 4) value2 = "confirmation_required";
|
|
8475
|
+
else if (exitCode === 3) value2 = "validation_failed";
|
|
8476
8476
|
}
|
|
8477
|
-
return normalizeErrorCode(
|
|
8477
|
+
return normalizeErrorCode(value2 ?? `exit_${exitCode}`, exitCode);
|
|
8478
8478
|
}
|
|
8479
8479
|
async function finishInvocation({
|
|
8480
8480
|
exitCode: rawExitCode,
|
|
@@ -8563,8 +8563,8 @@ function pagePath(id, action78) {
|
|
|
8563
8563
|
return `/api/v1/landing-pages/${encodeURIComponent(id)}${action78 ? `/${action78}` : ""}`;
|
|
8564
8564
|
}
|
|
8565
8565
|
function landingPagesApi(request2) {
|
|
8566
|
-
const call = async (method,
|
|
8567
|
-
const response = await request2(method,
|
|
8566
|
+
const call = async (method, path27, body5) => {
|
|
8567
|
+
const response = await request2(method, path27, body5);
|
|
8568
8568
|
return { ...response, data: response.data?.data };
|
|
8569
8569
|
};
|
|
8570
8570
|
return {
|
|
@@ -8650,6 +8650,19 @@ function validateLandingPageLocalFiles(files) {
|
|
|
8650
8650
|
}
|
|
8651
8651
|
|
|
8652
8652
|
// src/api.ts
|
|
8653
|
+
function lookupCommerceCatalog(creds, params) {
|
|
8654
|
+
const query = new URLSearchParams();
|
|
8655
|
+
if (params.query) query.set("q", params.query);
|
|
8656
|
+
if (params.handle) query.set("handle", params.handle);
|
|
8657
|
+
if (params.product_id) query.set("product_id", params.product_id);
|
|
8658
|
+
if (params.cursor) query.set("cursor", params.cursor);
|
|
8659
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
8660
|
+
return request(
|
|
8661
|
+
creds,
|
|
8662
|
+
"GET",
|
|
8663
|
+
`/api/v1/commerce/catalog${query.size ? `?${query}` : ""}`
|
|
8664
|
+
);
|
|
8665
|
+
}
|
|
8653
8666
|
function simulateTriggers(creds, body5) {
|
|
8654
8667
|
return request(creds, "POST", "/api/v1/tracking/simulate-trigger", body5);
|
|
8655
8668
|
}
|
|
@@ -8673,11 +8686,11 @@ function getUserKeyIdentity(creds) {
|
|
|
8673
8686
|
function getAccountContext(creds) {
|
|
8674
8687
|
return userRequest(creds, "GET", "/api/v1/me/context");
|
|
8675
8688
|
}
|
|
8676
|
-
function userRequest(creds, method,
|
|
8689
|
+
function userRequest(creds, method, path27, body5) {
|
|
8677
8690
|
return request(
|
|
8678
8691
|
{ ...creds, apiKey: creds.userApiKey ?? "", baseUrl: creds.userBaseUrl ?? creds.baseUrl },
|
|
8679
8692
|
method,
|
|
8680
|
-
|
|
8693
|
+
path27,
|
|
8681
8694
|
body5
|
|
8682
8695
|
);
|
|
8683
8696
|
}
|
|
@@ -8763,10 +8776,10 @@ function sharedClient(creds) {
|
|
|
8763
8776
|
}
|
|
8764
8777
|
return client;
|
|
8765
8778
|
}
|
|
8766
|
-
async function request(creds, method,
|
|
8779
|
+
async function request(creds, method, path27, body5, requestTimeoutMs, options) {
|
|
8767
8780
|
const response = await sharedClient(creds).request(
|
|
8768
8781
|
method,
|
|
8769
|
-
|
|
8782
|
+
path27,
|
|
8770
8783
|
body5,
|
|
8771
8784
|
requestTimeoutMs,
|
|
8772
8785
|
options
|
|
@@ -8774,8 +8787,8 @@ async function request(creds, method, path26, body5, requestTimeoutMs, options)
|
|
|
8774
8787
|
recordApiResponse(response);
|
|
8775
8788
|
return response;
|
|
8776
8789
|
}
|
|
8777
|
-
async function requestForm(creds, method,
|
|
8778
|
-
const response = await sharedClient(creds).requestForm(method,
|
|
8790
|
+
async function requestForm(creds, method, path27, body5) {
|
|
8791
|
+
const response = await sharedClient(creds).requestForm(method, path27, body5);
|
|
8779
8792
|
recordApiResponse(response);
|
|
8780
8793
|
return response;
|
|
8781
8794
|
}
|
|
@@ -9299,6 +9312,17 @@ function getAdminQuarantine(creds) {
|
|
|
9299
9312
|
"/api/v1/admin/tracking/quarantine"
|
|
9300
9313
|
);
|
|
9301
9314
|
}
|
|
9315
|
+
function getAdminShopSettings(creds, shopRef) {
|
|
9316
|
+
return request(
|
|
9317
|
+
userCredentials(creds),
|
|
9318
|
+
"GET",
|
|
9319
|
+
`/api/v1/admin/shops/${encodeURIComponent(shopRef)}/settings`
|
|
9320
|
+
);
|
|
9321
|
+
}
|
|
9322
|
+
function setAdminShopSetting(creds, shopId, body5) {
|
|
9323
|
+
const pinned = { ...userCredentials(creds), resolvedContext: { shopId } };
|
|
9324
|
+
return request(pinned, "PATCH", `/api/v1/admin/shops/${encodeURIComponent(shopId)}/settings`, body5);
|
|
9325
|
+
}
|
|
9302
9326
|
function archiveAdminShop(creds, shopId) {
|
|
9303
9327
|
return request(
|
|
9304
9328
|
userCredentials(creds),
|
|
@@ -9318,8 +9342,8 @@ function requestTargetingResource(creds, method, kind5, id, body5, limit, cursor
|
|
|
9318
9342
|
if (limit) params.set("limit", String(limit));
|
|
9319
9343
|
if (cursor) params.set("cursor", cursor);
|
|
9320
9344
|
const query = params.toString();
|
|
9321
|
-
const
|
|
9322
|
-
return request(creds, method,
|
|
9345
|
+
const path27 = `/api/v1/${kind5}${id ? `/${id.split("/").map(encodeURIComponent).join("/")}` : ""}${query ? `?${query}` : ""}`;
|
|
9346
|
+
return request(creds, method, path27, body5);
|
|
9323
9347
|
}
|
|
9324
9348
|
function managedPath(kind5, id, action78) {
|
|
9325
9349
|
return `/api/v1/${kind5}${id ? `/${encodeURIComponent(id)}` : ""}${action78 ? `/${action78}` : ""}`;
|
|
@@ -9355,7 +9379,7 @@ function getConfigResource(creds, family, id) {
|
|
|
9355
9379
|
}
|
|
9356
9380
|
function landingPages(creds) {
|
|
9357
9381
|
return landingPagesApi(
|
|
9358
|
-
(method,
|
|
9382
|
+
(method, path27, body5) => request(creds, method, path27, body5)
|
|
9359
9383
|
);
|
|
9360
9384
|
}
|
|
9361
9385
|
function deleteAsset(creds, id) {
|
|
@@ -9600,26 +9624,26 @@ function moveAdminCustomerStores(creds, orgId, body5) {
|
|
|
9600
9624
|
|
|
9601
9625
|
// src/context.ts
|
|
9602
9626
|
var import_node_readline = __toESM(require("node:readline"));
|
|
9603
|
-
function match(
|
|
9604
|
-
const byId = rows.find((row) => row.id ===
|
|
9627
|
+
function match(value2, rows, kind5) {
|
|
9628
|
+
const byId = rows.find((row) => row.id === value2);
|
|
9605
9629
|
if (byId) return byId;
|
|
9606
|
-
const exact = rows.filter((row) => row.name.toLowerCase() ===
|
|
9630
|
+
const exact = rows.filter((row) => row.name.toLowerCase() === value2.toLowerCase());
|
|
9607
9631
|
if (exact.length === 1) return exact[0];
|
|
9608
9632
|
if (exact.length > 1)
|
|
9609
9633
|
throw new CliError(
|
|
9610
|
-
`Ambiguous ${kind5} "${
|
|
9634
|
+
`Ambiguous ${kind5} "${value2}". Candidates: ${exact.map((row) => `${row.name} (${row.id})`).join(", ")}`,
|
|
9611
9635
|
EXIT_CODES.validation,
|
|
9612
9636
|
{ code: "ambiguous_context", candidates: exact.map(({ id, name }) => ({ id, name })) }
|
|
9613
9637
|
);
|
|
9614
|
-
const candidates = rows.filter((row) => row.name.toLowerCase().startsWith(
|
|
9638
|
+
const candidates = rows.filter((row) => row.name.toLowerCase().startsWith(value2.toLowerCase()));
|
|
9615
9639
|
if (candidates.length === 1) return candidates[0];
|
|
9616
9640
|
if (candidates.length > 1)
|
|
9617
9641
|
throw new CliError(
|
|
9618
|
-
`Ambiguous ${kind5} "${
|
|
9642
|
+
`Ambiguous ${kind5} "${value2}". Candidates: ${candidates.map((row) => `${row.name} (${row.id})`).join(", ")}`,
|
|
9619
9643
|
EXIT_CODES.validation,
|
|
9620
9644
|
{ code: "ambiguous_context", candidates: candidates.map(({ id, name }) => ({ id, name })) }
|
|
9621
9645
|
);
|
|
9622
|
-
throw new CliError(`Unknown ${kind5} "${
|
|
9646
|
+
throw new CliError(`Unknown ${kind5} "${value2}".`, EXIT_CODES.validation);
|
|
9623
9647
|
}
|
|
9624
9648
|
function resolveSelection(tree, input) {
|
|
9625
9649
|
const [orgValue, shopValue, extra] = input.split("/");
|
|
@@ -10188,12 +10212,12 @@ var evidenceKinds = [
|
|
|
10188
10212
|
];
|
|
10189
10213
|
|
|
10190
10214
|
// src/lib/experiment-handover.ts
|
|
10191
|
-
function summarizeHandoverQa(
|
|
10192
|
-
const record4 = (
|
|
10193
|
-
const qa3 = record4(
|
|
10194
|
-
const
|
|
10195
|
-
const summary = record4(
|
|
10196
|
-
const count2 = (
|
|
10215
|
+
function summarizeHandoverQa(value2) {
|
|
10216
|
+
const record4 = (value3) => value3 !== null && typeof value3 === "object" && !Array.isArray(value3) ? value3 : {};
|
|
10217
|
+
const qa3 = record4(value2);
|
|
10218
|
+
const run4 = record4(qa3.latestRun);
|
|
10219
|
+
const summary = record4(run4.summary);
|
|
10220
|
+
const count2 = (value3) => typeof value3 === "number" && Number.isInteger(value3) && value3 >= 0 ? value3 : null;
|
|
10197
10221
|
let requiredDone = count2(summary.completedRequired);
|
|
10198
10222
|
let requiredTotal = count2(summary.required);
|
|
10199
10223
|
if (requiredDone !== null && requiredTotal !== null && requiredDone > requiredTotal) {
|
|
@@ -10203,7 +10227,7 @@ function summarizeHandoverQa(value) {
|
|
|
10203
10227
|
const blockers = Array.isArray(summary.blockers) && summary.blockers.every((item) => typeof item === "string") ? summary.blockers : null;
|
|
10204
10228
|
const approvedAt = typeof qa3.qaApprovedAt === "string" ? Date.parse(qa3.qaApprovedAt) : Number.NaN;
|
|
10205
10229
|
return {
|
|
10206
|
-
run_status: typeof
|
|
10230
|
+
run_status: typeof run4.status === "string" ? run4.status : null,
|
|
10207
10231
|
required_done: requiredDone,
|
|
10208
10232
|
required_total: requiredTotal,
|
|
10209
10233
|
blockers,
|
|
@@ -10276,13 +10300,13 @@ function deviceLabel(targeting) {
|
|
|
10276
10300
|
var ALL_PAGES_LABEL = "All pages";
|
|
10277
10301
|
var CHECKOUT_LABEL = "Checkout";
|
|
10278
10302
|
var UNKNOWN_PAGE_NAME = "Saved Page";
|
|
10279
|
-
function isRecord(
|
|
10280
|
-
return Boolean(
|
|
10303
|
+
function isRecord(value2) {
|
|
10304
|
+
return Boolean(value2 && typeof value2 === "object" && !Array.isArray(value2));
|
|
10281
10305
|
}
|
|
10282
|
-
function arrayOf(
|
|
10283
|
-
if (Array.isArray(
|
|
10284
|
-
if (
|
|
10285
|
-
return [
|
|
10306
|
+
function arrayOf(value2) {
|
|
10307
|
+
if (Array.isArray(value2)) return value2;
|
|
10308
|
+
if (value2 === void 0 || value2 === null) return [];
|
|
10309
|
+
return [value2];
|
|
10286
10310
|
}
|
|
10287
10311
|
function ruleKey(rule) {
|
|
10288
10312
|
if (typeof rule === "string") return JSON.stringify(["include", "simple", rule.trim(), ""]);
|
|
@@ -10360,11 +10384,11 @@ function classifyIdeaReference(reference) {
|
|
|
10360
10384
|
|
|
10361
10385
|
// ../api-client/src/experiments.ts
|
|
10362
10386
|
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;
|
|
10363
|
-
function isExperimentTestKey(
|
|
10364
|
-
return /^([A-Z0-9]{2,8})-(\d+)$/.test(
|
|
10387
|
+
function isExperimentTestKey(value2) {
|
|
10388
|
+
return /^([A-Z0-9]{2,8})-(\d+)$/.test(value2);
|
|
10365
10389
|
}
|
|
10366
|
-
function record(
|
|
10367
|
-
return
|
|
10390
|
+
function record(value2) {
|
|
10391
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
|
|
10368
10392
|
}
|
|
10369
10393
|
async function resolveExperimentReference(request2, idOrSlug, variationRef) {
|
|
10370
10394
|
const explicitSlug = idOrSlug.startsWith("slug:");
|
|
@@ -10448,9 +10472,9 @@ function summarizeResults(payload) {
|
|
|
10448
10472
|
degraded: Object.values(degradedFlags).some(Boolean),
|
|
10449
10473
|
degradedFlags,
|
|
10450
10474
|
missingMetrics: [...missing],
|
|
10451
|
-
warnings: Array.isArray(data.warnings) ? data.warnings.map((
|
|
10452
|
-
message: record(
|
|
10453
|
-
value
|
|
10475
|
+
warnings: Array.isArray(data.warnings) ? data.warnings.map((value2) => ({
|
|
10476
|
+
message: record(value2).message,
|
|
10477
|
+
value: value2
|
|
10454
10478
|
})) : [],
|
|
10455
10479
|
metrics: Array.isArray(data.metrics) ? data.metrics.map(record) : [],
|
|
10456
10480
|
resultsWeekdays: data.results_weekdays,
|
|
@@ -10514,25 +10538,25 @@ function extensionForMimeType(mimeType) {
|
|
|
10514
10538
|
const safeSubtype = subtype?.replace(/[^a-z0-9.+-]/g, "");
|
|
10515
10539
|
return safeSubtype ? `.${safeSubtype}` : ".bin";
|
|
10516
10540
|
}
|
|
10517
|
-
function dataUriFromMatch(
|
|
10541
|
+
function dataUriFromMatch(value2, match2) {
|
|
10518
10542
|
let uri = match2[0];
|
|
10519
10543
|
const start = match2.index ?? 0;
|
|
10520
|
-
if (/url\(\s*$/i.test(
|
|
10544
|
+
if (/url\(\s*$/i.test(value2.slice(0, start))) {
|
|
10521
10545
|
const closingParenthesis = uri.indexOf(")");
|
|
10522
10546
|
if (closingParenthesis >= 0) uri = uri.slice(0, closingParenthesis);
|
|
10523
10547
|
}
|
|
10524
10548
|
return uri;
|
|
10525
10549
|
}
|
|
10526
|
-
function surroundingNonWhitespaceNonQuoteRun(
|
|
10527
|
-
const before =
|
|
10528
|
-
const after =
|
|
10529
|
-
return `${before}${
|
|
10550
|
+
function surroundingNonWhitespaceNonQuoteRun(value2, start, end) {
|
|
10551
|
+
const before = value2.slice(0, start).match(/[^\s"']*$/)?.[0] ?? "";
|
|
10552
|
+
const after = value2.slice(end).match(/^[^\s"']*/)?.[0] ?? "";
|
|
10553
|
+
return `${before}${value2.slice(start, end)}${after}`;
|
|
10530
10554
|
}
|
|
10531
10555
|
function isInsideRange(start, end, ranges) {
|
|
10532
10556
|
return ranges.some((range) => start >= range.start && end <= range.end);
|
|
10533
10557
|
}
|
|
10534
|
-
function applyReplacements(
|
|
10535
|
-
let rewritten =
|
|
10558
|
+
function applyReplacements(value2, replacements) {
|
|
10559
|
+
let rewritten = value2;
|
|
10536
10560
|
for (const replacement of replacements.sort((a, b) => b.start - a.start)) {
|
|
10537
10561
|
rewritten = rewritten.slice(0, replacement.start) + replacement.value + rewritten.slice(replacement.end);
|
|
10538
10562
|
}
|
|
@@ -10563,9 +10587,9 @@ function createAssetReferenceRewriter(options) {
|
|
|
10563
10587
|
}
|
|
10564
10588
|
return pending;
|
|
10565
10589
|
};
|
|
10566
|
-
const rewrite = async (
|
|
10567
|
-
if (options.enabled === false || !
|
|
10568
|
-
let rewritten =
|
|
10590
|
+
const rewrite = async (value2, baseDir = options.baseDir) => {
|
|
10591
|
+
if (options.enabled === false || !value2) return value2;
|
|
10592
|
+
let rewritten = value2;
|
|
10569
10593
|
const inlineMatches = [...rewritten.matchAll(DATA_IMAGE_URI_PATTERN)].map((match2) => ({ match: match2, uri: dataUriFromMatch(rewritten, match2) })).filter(({ uri }) => uri.length > INLINE_DATA_URI_MAX_CHARS);
|
|
10570
10594
|
for (const { uri } of inlineMatches) {
|
|
10571
10595
|
const commaIndex = uri.indexOf(",");
|
|
@@ -10640,22 +10664,22 @@ function createAssetReferenceRewriter(options) {
|
|
|
10640
10664
|
}
|
|
10641
10665
|
return applyReplacements(rewritten, bareReplacements);
|
|
10642
10666
|
};
|
|
10643
|
-
const rewriteUnknown = async (
|
|
10644
|
-
if (typeof
|
|
10645
|
-
if (Array.isArray(
|
|
10646
|
-
return Promise.all(
|
|
10667
|
+
const rewriteUnknown = async (value2, baseDir = options.baseDir) => {
|
|
10668
|
+
if (typeof value2 === "string") return rewrite(value2, baseDir);
|
|
10669
|
+
if (Array.isArray(value2)) {
|
|
10670
|
+
return Promise.all(value2.map((entry) => rewriteUnknown(entry, baseDir)));
|
|
10647
10671
|
}
|
|
10648
|
-
if (
|
|
10672
|
+
if (value2 !== null && typeof value2 === "object") {
|
|
10649
10673
|
return Object.fromEntries(
|
|
10650
10674
|
await Promise.all(
|
|
10651
|
-
Object.entries(
|
|
10675
|
+
Object.entries(value2).map(async ([key, entry]) => [
|
|
10652
10676
|
key,
|
|
10653
10677
|
await rewriteUnknown(entry, baseDir)
|
|
10654
10678
|
])
|
|
10655
10679
|
)
|
|
10656
10680
|
);
|
|
10657
10681
|
}
|
|
10658
|
-
return
|
|
10682
|
+
return value2;
|
|
10659
10683
|
};
|
|
10660
10684
|
return { rewrite, rewriteUnknown };
|
|
10661
10685
|
}
|
|
@@ -12862,27 +12886,27 @@ function printExperiment(exp, dashboardUrl = null) {
|
|
|
12862
12886
|
}
|
|
12863
12887
|
console.log();
|
|
12864
12888
|
}
|
|
12865
|
-
function formatPct(
|
|
12866
|
-
return typeof
|
|
12889
|
+
function formatPct(value2, digits = 1) {
|
|
12890
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? `${value2.toFixed(digits)}%` : "-";
|
|
12867
12891
|
}
|
|
12868
|
-
function confidenceBasisLabel(
|
|
12869
|
-
if (
|
|
12870
|
-
if (
|
|
12892
|
+
function confidenceBasisLabel(value2) {
|
|
12893
|
+
if (value2 === "fixed_horizon") return "fixed-horizon";
|
|
12894
|
+
if (value2 === "sequential") return "always-valid";
|
|
12871
12895
|
return "unknown";
|
|
12872
12896
|
}
|
|
12873
|
-
function statisticsStateLabel(
|
|
12874
|
-
return
|
|
12897
|
+
function statisticsStateLabel(value2) {
|
|
12898
|
+
return value2 === "untrustworthy" ? "verdict withheld" : String(value2 ?? "unknown");
|
|
12875
12899
|
}
|
|
12876
|
-
function formatRevenue(
|
|
12877
|
-
if (
|
|
12878
|
-
if (!currency || typeof
|
|
12900
|
+
function formatRevenue(value2, currency) {
|
|
12901
|
+
if (value2 === null || value2 === void 0) return "\u2014";
|
|
12902
|
+
if (!currency || typeof value2 !== "number" || !Number.isFinite(value2)) return String(value2);
|
|
12879
12903
|
try {
|
|
12880
12904
|
return new Intl.NumberFormat("en-US", {
|
|
12881
12905
|
style: "currency",
|
|
12882
12906
|
currency: currency.trim().toUpperCase()
|
|
12883
|
-
}).format(
|
|
12907
|
+
}).format(value2);
|
|
12884
12908
|
} catch {
|
|
12885
|
-
return String(
|
|
12909
|
+
return String(value2);
|
|
12886
12910
|
}
|
|
12887
12911
|
}
|
|
12888
12912
|
function audienceLine(segmentApplied) {
|
|
@@ -12971,8 +12995,8 @@ function printExperimentResults(results2, currency) {
|
|
|
12971
12995
|
const deltas = arm.deltaVsControl;
|
|
12972
12996
|
const cm = deltas?.cm;
|
|
12973
12997
|
const ci = cm?.ci95;
|
|
12974
|
-
const count2 = (
|
|
12975
|
-
const money = (
|
|
12998
|
+
const count2 = (value2) => typeof value2 === "number" && Number.isFinite(value2) ? String(value2) : "-";
|
|
12999
|
+
const money = (value2) => typeof value2 === "number" ? formatRevenue(value2, String(plane.currency ?? currency ?? "")) : "-";
|
|
12976
13000
|
return [
|
|
12977
13001
|
String(arm.name ?? arm.variationId ?? "-"),
|
|
12978
13002
|
// Fail closed: a missing count is unavailable, never a measured 0.
|
|
@@ -13025,13 +13049,13 @@ var EXPERIMENT_FILESYSTEM_PATH_SCHEMA = {
|
|
|
13025
13049
|
variation: filesystemPaths.filter((entry) => entry.startsWith("variations/*/")).map((entry) => entry.slice("variations/*/".length))
|
|
13026
13050
|
};
|
|
13027
13051
|
var SERVER_OWNED_EXPERIMENT_FILES = /* @__PURE__ */ new Set(["qa.json", "launch.json"]);
|
|
13028
|
-
var escapeRegex = (
|
|
13052
|
+
var escapeRegex = (value2) => value2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13029
13053
|
var pathAlternation = (paths) => paths.map(escapeRegex).join("|");
|
|
13030
13054
|
var FILESYSTEM_FILE_RE = new RegExp(
|
|
13031
13055
|
`^(?:${pathAlternation(EXPERIMENT_FILESYSTEM_PATH_SCHEMA.topLevel)}|experiment/(?:${pathAlternation(EXPERIMENT_FILESYSTEM_PATH_SCHEMA.experiment)})|commerce/(?:${pathAlternation(EXPERIMENT_FILESYSTEM_PATH_SCHEMA.commerce)})|variations/[^/]+/(?:${pathAlternation(EXPERIMENT_FILESYSTEM_PATH_SCHEMA.variation)}))$`
|
|
13032
13056
|
);
|
|
13033
|
-
function sha256Text(
|
|
13034
|
-
return import_node_crypto6.default.createHash("sha256").update(
|
|
13057
|
+
function sha256Text(value2) {
|
|
13058
|
+
return import_node_crypto6.default.createHash("sha256").update(value2).digest("hex");
|
|
13035
13059
|
}
|
|
13036
13060
|
function folderPath(folder) {
|
|
13037
13061
|
return import_node_path6.default.resolve(process.cwd(), folder);
|
|
@@ -13216,6 +13240,19 @@ function printFilesystemPlan(plan2) {
|
|
|
13216
13240
|
console.log(` - [${issue.code}] ${issue.message}${context ? ` (${context})` : ""}`);
|
|
13217
13241
|
});
|
|
13218
13242
|
}
|
|
13243
|
+
if ((plan2.commerceLaunchPreview?.length ?? 0) > 0) {
|
|
13244
|
+
console.log(source_default.bold("\nLaunch preview"));
|
|
13245
|
+
for (const preview2 of plan2.commerceLaunchPreview ?? []) {
|
|
13246
|
+
console.log(` ${preview2.kind} (${preview2.path})`);
|
|
13247
|
+
for (const issue of preview2.issues) {
|
|
13248
|
+
const variation = issue.variation ? ` (variation: ${issue.variation})` : "";
|
|
13249
|
+
console.log(source_default.yellow(` - [${issue.code}] ${issue.message}${variation}`));
|
|
13250
|
+
}
|
|
13251
|
+
console.log(` Checked at plan: ${preview2.checked.join(", ") || "none"}`);
|
|
13252
|
+
for (const item of preview2.launchOnly)
|
|
13253
|
+
console.log(` Checked at ${item.when ?? "launch"}: ${item.check}: ${item.reason}`);
|
|
13254
|
+
}
|
|
13255
|
+
}
|
|
13219
13256
|
console.log(source_default.bold("\nChanges"));
|
|
13220
13257
|
if (plan2.changes.length === 0) {
|
|
13221
13258
|
console.log(source_default.dim(" No changes."));
|
|
@@ -13299,38 +13336,38 @@ function printQaPreviewUrls(experimentId, result) {
|
|
|
13299
13336
|
);
|
|
13300
13337
|
}
|
|
13301
13338
|
}
|
|
13302
|
-
function qaVersionMarker(
|
|
13303
|
-
const version =
|
|
13339
|
+
function qaVersionMarker(value2) {
|
|
13340
|
+
const version = value2;
|
|
13304
13341
|
return version.stale ? " [stale: checked against an earlier version]" : version.unversioned ? " [unversioned]" : "";
|
|
13305
13342
|
}
|
|
13306
|
-
function printQaRun(
|
|
13343
|
+
function printQaRun(run4) {
|
|
13307
13344
|
console.log();
|
|
13308
|
-
console.log(source_default.bold(`QA run ${
|
|
13309
|
-
console.log(` computedAt: ${
|
|
13310
|
-
console.log(` Status: ${statusBadge(
|
|
13311
|
-
console.log(` Required: ${
|
|
13312
|
-
if (
|
|
13313
|
-
if (
|
|
13314
|
-
if (
|
|
13345
|
+
console.log(source_default.bold(`QA run ${run4.id}`));
|
|
13346
|
+
console.log(` computedAt: ${run4.computedAt}`);
|
|
13347
|
+
console.log(` Status: ${statusBadge(run4.summary.status)}`);
|
|
13348
|
+
console.log(` Required: ${run4.summary.completedRequired}/${run4.summary.required}`);
|
|
13349
|
+
if (run4.approvedAt) console.log(` Approved: ${run4.approvedAt}`);
|
|
13350
|
+
if (run4.completedAt) console.log(` Complete: ${run4.completedAt}`);
|
|
13351
|
+
if (run4.summary.blockers.length > 0) {
|
|
13315
13352
|
console.log(source_default.yellow("\nBlockers"));
|
|
13316
|
-
|
|
13353
|
+
run4.summary.blockers.forEach((blocker) => console.log(` - ${blocker}`));
|
|
13317
13354
|
}
|
|
13318
13355
|
console.log(source_default.bold("\nChecklist"));
|
|
13319
|
-
for (const item of
|
|
13356
|
+
for (const item of run4.checklist) {
|
|
13320
13357
|
const required = item.required ? source_default.yellow(" required") : "";
|
|
13321
13358
|
const notes = item.notes ? source_default.dim(` \u2014 ${item.notes}`) : "";
|
|
13322
13359
|
console.log(` ${statusBadge(item.status)} ${item.id}${required}${qaVersionMarker(item)}`);
|
|
13323
13360
|
console.log(` ${item.title}${notes}`);
|
|
13324
13361
|
}
|
|
13325
|
-
if (
|
|
13362
|
+
if (run4.urls.length > 0) {
|
|
13326
13363
|
console.log(source_default.bold("\nQA URLs"));
|
|
13327
|
-
|
|
13364
|
+
run4.urls.forEach((url) => {
|
|
13328
13365
|
console.log(` - ${url.label}: ${source_default.cyan(url.url)}`);
|
|
13329
13366
|
});
|
|
13330
13367
|
}
|
|
13331
|
-
if ((
|
|
13368
|
+
if ((run4.evidenceRecords ?? []).length > 0) {
|
|
13332
13369
|
console.log(source_default.bold("\nEvidence records"));
|
|
13333
|
-
for (const record4 of
|
|
13370
|
+
for (const record4 of run4.evidenceRecords ?? []) {
|
|
13334
13371
|
const device = record4.device ? ` \xB7 ${record4.device}` : "";
|
|
13335
13372
|
console.log(
|
|
13336
13373
|
` - ${record4.kind} \xB7 ${record4.label} \xB7 ${record4.status}${device} \xB7 ${record4.capturedAt}${qaVersionMarker(record4)}`
|
|
@@ -13343,18 +13380,18 @@ async function confirmApply(message) {
|
|
|
13343
13380
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
13344
13381
|
return null;
|
|
13345
13382
|
}
|
|
13346
|
-
const
|
|
13347
|
-
const rl =
|
|
13383
|
+
const readline4 = await import("node:readline");
|
|
13384
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
13348
13385
|
const answer = await new Promise((resolve2) => {
|
|
13349
13386
|
rl.question(source_default.yellow(`${message} [y/N] `), resolve2);
|
|
13350
13387
|
});
|
|
13351
13388
|
rl.close();
|
|
13352
13389
|
return answer.toLowerCase() === "y";
|
|
13353
13390
|
}
|
|
13354
|
-
function parseEvidenceInput(
|
|
13355
|
-
if (!
|
|
13356
|
-
const source =
|
|
13357
|
-
const text2 =
|
|
13391
|
+
function parseEvidenceInput(value2) {
|
|
13392
|
+
if (!value2) return void 0;
|
|
13393
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
13394
|
+
const text2 = value2.startsWith("@") || import_node_fs8.default.existsSync(source) ? import_node_fs8.default.readFileSync(import_node_path6.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
13358
13395
|
const parsed = JSON.parse(text2);
|
|
13359
13396
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
13360
13397
|
throw new Error("QA evidence must be a JSON object");
|
|
@@ -13362,24 +13399,24 @@ function parseEvidenceInput(value) {
|
|
|
13362
13399
|
return parsed;
|
|
13363
13400
|
}
|
|
13364
13401
|
function qaChoice(flags, description, choices) {
|
|
13365
|
-
return new Option(flags, description).choices([...choices]).argParser((
|
|
13402
|
+
return new Option(flags, description).choices([...choices]).argParser((value2) => value2);
|
|
13366
13403
|
}
|
|
13367
|
-
function validateQaChoice(command, option,
|
|
13368
|
-
if (
|
|
13369
|
-
fail(command, `Invalid ${option}: ${
|
|
13404
|
+
function validateQaChoice(command, option, value2, allowed2) {
|
|
13405
|
+
if (value2 !== void 0 && !allowed2.includes(value2)) {
|
|
13406
|
+
fail(command, `Invalid ${option}: ${value2}`, EXIT_CODES.validation, {
|
|
13370
13407
|
option,
|
|
13371
13408
|
allowedValues: [...allowed2]
|
|
13372
13409
|
});
|
|
13373
13410
|
}
|
|
13374
13411
|
}
|
|
13375
|
-
function qaSummary(
|
|
13412
|
+
function qaSummary(run4, changed) {
|
|
13376
13413
|
return {
|
|
13377
13414
|
run: {
|
|
13378
|
-
id:
|
|
13379
|
-
status:
|
|
13380
|
-
summary:
|
|
13381
|
-
approvedAt:
|
|
13382
|
-
updatedAt:
|
|
13415
|
+
id: run4.id,
|
|
13416
|
+
status: run4.status,
|
|
13417
|
+
summary: run4.summary,
|
|
13418
|
+
approvedAt: run4.approvedAt,
|
|
13419
|
+
updatedAt: run4.updatedAt
|
|
13383
13420
|
},
|
|
13384
13421
|
changed,
|
|
13385
13422
|
validationErrors: []
|
|
@@ -13392,8 +13429,8 @@ function tryReadFilesystemSession(folder) {
|
|
|
13392
13429
|
return null;
|
|
13393
13430
|
}
|
|
13394
13431
|
}
|
|
13395
|
-
async function resolveExperimentForFilesystemOrId(
|
|
13396
|
-
const candidate = folderPath(
|
|
13432
|
+
async function resolveExperimentForFilesystemOrId(value2) {
|
|
13433
|
+
const candidate = folderPath(value2);
|
|
13397
13434
|
const session = tryReadFilesystemSession(candidate);
|
|
13398
13435
|
if (session) {
|
|
13399
13436
|
return {
|
|
@@ -13402,8 +13439,8 @@ async function resolveExperimentForFilesystemOrId(value) {
|
|
|
13402
13439
|
label: import_node_path6.default.basename(candidate)
|
|
13403
13440
|
};
|
|
13404
13441
|
}
|
|
13405
|
-
const exp = await resolveExperiment(
|
|
13406
|
-
if (!exp) throw new Error(`Experiment "${
|
|
13442
|
+
const exp = await resolveExperiment(value2);
|
|
13443
|
+
if (!exp) throw new Error(`Experiment "${value2}" not found.`);
|
|
13407
13444
|
return { experimentId: exp.id, folder: null, label: exp.name };
|
|
13408
13445
|
}
|
|
13409
13446
|
async function refreshExperimentFilesystemFolderIfNeeded(creds, folder, experimentId) {
|
|
@@ -13525,8 +13562,8 @@ var list = new Command("list").alias("ls").description(
|
|
|
13525
13562
|
fields3.map((field) => field.toUpperCase()),
|
|
13526
13563
|
experiments.map(
|
|
13527
13564
|
(experiment2) => fields3.map((field) => {
|
|
13528
|
-
const
|
|
13529
|
-
return
|
|
13565
|
+
const value2 = experiment2[field];
|
|
13566
|
+
return value2 == null ? "-" : typeof value2 === "object" ? JSON.stringify(value2) : String(value2);
|
|
13530
13567
|
})
|
|
13531
13568
|
)
|
|
13532
13569
|
);
|
|
@@ -13769,17 +13806,17 @@ var update = new Command("update").description("Update an experiment").addOption
|
|
|
13769
13806
|
);
|
|
13770
13807
|
});
|
|
13771
13808
|
});
|
|
13772
|
-
function collectCreateOption(
|
|
13773
|
-
return [...previous,
|
|
13809
|
+
function collectCreateOption(value2, previous) {
|
|
13810
|
+
return [...previous, value2];
|
|
13774
13811
|
}
|
|
13775
|
-
function parseHttpDestination(
|
|
13776
|
-
const trimmed =
|
|
13812
|
+
function parseHttpDestination(value2) {
|
|
13813
|
+
const trimmed = value2.trim();
|
|
13777
13814
|
try {
|
|
13778
13815
|
const url = new URL(trimmed);
|
|
13779
13816
|
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error();
|
|
13780
13817
|
} catch {
|
|
13781
13818
|
throw new CliError(
|
|
13782
|
-
`Invalid redirect destination "${
|
|
13819
|
+
`Invalid redirect destination "${value2}": expected an HTTP(S) URL.`,
|
|
13783
13820
|
EXIT_CODES.validation
|
|
13784
13821
|
);
|
|
13785
13822
|
}
|
|
@@ -13823,8 +13860,8 @@ function normalizeNewGoalKey(key) {
|
|
|
13823
13860
|
const normalized = key.trim().toLowerCase().replace(/-/g, "_");
|
|
13824
13861
|
return normalized === "page" ? "page_id" : normalized;
|
|
13825
13862
|
}
|
|
13826
|
-
function validateNewGoal(command,
|
|
13827
|
-
const invalid = (reason2) => fail(command, `Invalid --goal "new:${
|
|
13863
|
+
function validateNewGoal(command, value2, body5) {
|
|
13864
|
+
const invalid = (reason2) => fail(command, `Invalid --goal "new:${value2}"; ${reason2}`, EXIT_CODES.validation);
|
|
13828
13865
|
const text2 = (field) => {
|
|
13829
13866
|
const raw = body5[field];
|
|
13830
13867
|
return typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
@@ -13872,20 +13909,20 @@ function validateNewGoal(command, value, body5) {
|
|
|
13872
13909
|
if (valueUnit && !GOAL_VALUE_UNITS.includes(valueUnit))
|
|
13873
13910
|
invalid(`value-unit must be one of ${GOAL_VALUE_UNITS.join(", ")}`);
|
|
13874
13911
|
}
|
|
13875
|
-
function parseNewGoal(command,
|
|
13912
|
+
function parseNewGoal(command, value2) {
|
|
13876
13913
|
const body5 = {};
|
|
13877
|
-
for (const field of
|
|
13914
|
+
for (const field of value2.split(",")) {
|
|
13878
13915
|
const separator = field.indexOf("=");
|
|
13879
13916
|
if (separator <= 0 || separator === field.length - 1) {
|
|
13880
13917
|
fail(
|
|
13881
13918
|
command,
|
|
13882
|
-
`Invalid --goal "new:${
|
|
13919
|
+
`Invalid --goal "new:${value2}"; use new:type=<type>,selector=<css>,name=<text>`,
|
|
13883
13920
|
EXIT_CODES.validation
|
|
13884
13921
|
);
|
|
13885
13922
|
}
|
|
13886
13923
|
body5[normalizeNewGoalKey(field.slice(0, separator))] = field.slice(separator + 1).trim();
|
|
13887
13924
|
}
|
|
13888
|
-
validateNewGoal(command,
|
|
13925
|
+
validateNewGoal(command, value2, body5);
|
|
13889
13926
|
return body5;
|
|
13890
13927
|
}
|
|
13891
13928
|
async function resolveNewGoalPages(command, creds, goals, interactive) {
|
|
@@ -13928,8 +13965,8 @@ async function resolveNewGoalPages(command, creds, goals, interactive) {
|
|
|
13928
13965
|
}
|
|
13929
13966
|
}
|
|
13930
13967
|
async function askCreate(question) {
|
|
13931
|
-
const
|
|
13932
|
-
const rl =
|
|
13968
|
+
const readline4 = await import("node:readline");
|
|
13969
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
13933
13970
|
return new Promise(
|
|
13934
13971
|
(resolve2) => rl.question(question, (answer) => {
|
|
13935
13972
|
rl.close();
|
|
@@ -14026,8 +14063,8 @@ var create = new Command("create").description(
|
|
|
14026
14063
|
if (!Number.isFinite(traffic) || traffic < 0 || traffic > 100) {
|
|
14027
14064
|
fail(this, "--traffic must be a number from 0 to 100", EXIT_CODES.validation);
|
|
14028
14065
|
}
|
|
14029
|
-
const sourceRules = [...opts.sourceUrl, ...opts.pageUrl].map((
|
|
14030
|
-
if (sourceRules.some((
|
|
14066
|
+
const sourceRules = [...opts.sourceUrl, ...opts.pageUrl].map((value2) => value2.trim());
|
|
14067
|
+
if (sourceRules.some((value2) => value2.length === 0)) {
|
|
14031
14068
|
fail(this, "--source-url/--page-url cannot be empty", EXIT_CODES.validation);
|
|
14032
14069
|
}
|
|
14033
14070
|
if (opts.type !== "redirect" && opts.destination.length > 0) {
|
|
@@ -14330,8 +14367,8 @@ var del = new Command("delete").alias("rm").description("Delete an experiment").
|
|
|
14330
14367
|
`apex experiments delete ${idOrSlug} --force`
|
|
14331
14368
|
);
|
|
14332
14369
|
}
|
|
14333
|
-
const
|
|
14334
|
-
const rl =
|
|
14370
|
+
const readline4 = await import("node:readline");
|
|
14371
|
+
const rl = readline4.createInterface({
|
|
14335
14372
|
input: process.stdin,
|
|
14336
14373
|
output: process.stderr
|
|
14337
14374
|
});
|
|
@@ -14946,7 +14983,7 @@ var applyFilesystem = new Command("apply").option(
|
|
|
14946
14983
|
);
|
|
14947
14984
|
for (const variation of receipt.variations) {
|
|
14948
14985
|
console.log(
|
|
14949
|
-
` ${variation.name} (${variation.slug}): ${Object.entries(variation.digests).map(([key,
|
|
14986
|
+
` ${variation.name} (${variation.slug}): ${Object.entries(variation.digests).map(([key, value2]) => `${key}=${value2 ?? "null"}`).join(" ")}`
|
|
14950
14987
|
);
|
|
14951
14988
|
}
|
|
14952
14989
|
}
|
|
@@ -15019,18 +15056,18 @@ var qaCheck = new Command("check").description("Update one QA checklist item wit
|
|
|
15019
15056
|
classifyStatus(res.status),
|
|
15020
15057
|
res.errorDetails
|
|
15021
15058
|
);
|
|
15022
|
-
const
|
|
15059
|
+
const run4 = res.data.run;
|
|
15023
15060
|
await refreshExperimentFilesystemFolderIfNeeded(
|
|
15024
15061
|
creds,
|
|
15025
15062
|
resolved.folder,
|
|
15026
15063
|
resolved.experimentId
|
|
15027
15064
|
);
|
|
15028
|
-
const data = opts.summary ? qaSummary(
|
|
15065
|
+
const data = opts.summary ? qaSummary(run4, run4.checklist.find((item) => item.id === opts.item) ?? null) : res.data;
|
|
15029
15066
|
output(this, data, () => {
|
|
15030
15067
|
spinner.succeed("Updated QA checklist");
|
|
15031
15068
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
15032
15069
|
`);
|
|
15033
|
-
else printQaRun(
|
|
15070
|
+
else printQaRun(run4);
|
|
15034
15071
|
});
|
|
15035
15072
|
} catch (error) {
|
|
15036
15073
|
spinner.fail("Failed to update QA checklist");
|
|
@@ -15065,21 +15102,21 @@ var qaNotes = new Command("notes").description("Update QA run notes or acceptanc
|
|
|
15065
15102
|
classifyStatus(res.status),
|
|
15066
15103
|
res.errorDetails
|
|
15067
15104
|
);
|
|
15068
|
-
const
|
|
15105
|
+
const run4 = res.data.run;
|
|
15069
15106
|
await refreshExperimentFilesystemFolderIfNeeded(
|
|
15070
15107
|
creds,
|
|
15071
15108
|
resolved.folder,
|
|
15072
15109
|
resolved.experimentId
|
|
15073
15110
|
);
|
|
15074
|
-
const data = opts.summary ? qaSummary(
|
|
15075
|
-
notes:
|
|
15076
|
-
acceptanceCriteriaSummary:
|
|
15111
|
+
const data = opts.summary ? qaSummary(run4, {
|
|
15112
|
+
notes: run4.notes,
|
|
15113
|
+
acceptanceCriteriaSummary: run4.acceptanceCriteriaSummary
|
|
15077
15114
|
}) : res.data;
|
|
15078
15115
|
output(this, data, () => {
|
|
15079
15116
|
spinner.succeed("Updated QA notes");
|
|
15080
15117
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
15081
15118
|
`);
|
|
15082
|
-
else printQaRun(
|
|
15119
|
+
else printQaRun(run4);
|
|
15083
15120
|
});
|
|
15084
15121
|
} catch (error) {
|
|
15085
15122
|
spinner.fail("Failed to update QA notes");
|
|
@@ -15119,9 +15156,9 @@ var qaApprove = new Command("approve").description("Approve QA and move the expe
|
|
|
15119
15156
|
}
|
|
15120
15157
|
if (typeof details.split_hash === "string" && details.split_hash.length > 0) {
|
|
15121
15158
|
const weights = Array.isArray(details.variation_weights) ? details.variation_weights : [];
|
|
15122
|
-
for (const
|
|
15123
|
-
if (
|
|
15124
|
-
const variation =
|
|
15159
|
+
for (const value2 of weights) {
|
|
15160
|
+
if (value2 && typeof value2 === "object") {
|
|
15161
|
+
const variation = value2;
|
|
15125
15162
|
process.stderr.write(
|
|
15126
15163
|
`${variation.name ?? variation.id ?? "Variation"}: ${(variation.weight ?? 0) * 100}%${variation.weight === 0 ? " (no traffic)" : ""}
|
|
15127
15164
|
`
|
|
@@ -15197,17 +15234,17 @@ var qaReopen = new Command("reopen").description("Reopen QA and clear scheduled
|
|
|
15197
15234
|
throw error;
|
|
15198
15235
|
}
|
|
15199
15236
|
});
|
|
15200
|
-
function parseJsonValue(
|
|
15201
|
-
const source =
|
|
15202
|
-
const text2 =
|
|
15237
|
+
function parseJsonValue(value2) {
|
|
15238
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
15239
|
+
const text2 = value2.startsWith("@") || import_node_fs8.default.existsSync(source) ? import_node_fs8.default.readFileSync(import_node_path6.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
15203
15240
|
return JSON.parse(text2);
|
|
15204
15241
|
}
|
|
15205
|
-
function collectFile(
|
|
15206
|
-
return [...previous,
|
|
15242
|
+
function collectFile(value2, previous = []) {
|
|
15243
|
+
return [...previous, value2];
|
|
15207
15244
|
}
|
|
15208
|
-
function normalizeEvidenceDevice(
|
|
15209
|
-
if (!
|
|
15210
|
-
const normalized =
|
|
15245
|
+
function normalizeEvidenceDevice(value2) {
|
|
15246
|
+
if (!value2) return void 0;
|
|
15247
|
+
const normalized = value2.trim().toLowerCase();
|
|
15211
15248
|
if (normalized === "desktop_chrome" || normalized === "desktop_safari") return "desktop";
|
|
15212
15249
|
if (normalized === "iphone_15_pro" || normalized === "galaxy_s24") return "mobile";
|
|
15213
15250
|
if (normalized === "ipad_pro") return "tablet";
|
|
@@ -15294,15 +15331,15 @@ var qaEvidence = new Command("evidence").description("Attach screenshot jobs or
|
|
|
15294
15331
|
);
|
|
15295
15332
|
}
|
|
15296
15333
|
spinner.stop();
|
|
15297
|
-
const
|
|
15334
|
+
const run4 = response.data.run;
|
|
15298
15335
|
const data = opts.summary ? qaSummary(
|
|
15299
|
-
|
|
15300
|
-
|
|
15336
|
+
run4,
|
|
15337
|
+
run4.evidenceRecords.filter((record4) => !previousIds.has(record4.id))
|
|
15301
15338
|
) : response.data;
|
|
15302
15339
|
output(this, data, () => {
|
|
15303
15340
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
15304
15341
|
`);
|
|
15305
|
-
else printQaRun(
|
|
15342
|
+
else printQaRun(run4);
|
|
15306
15343
|
});
|
|
15307
15344
|
} catch (error) {
|
|
15308
15345
|
spinner.fail("Failed to write QA evidence");
|
|
@@ -15334,14 +15371,14 @@ var qa = new Command("qa").description("Manage experiment QA runs from the CLI")
|
|
|
15334
15371
|
data,
|
|
15335
15372
|
() => printTable(
|
|
15336
15373
|
["KIND", "STATE", "SUMMARY"],
|
|
15337
|
-
Object.entries(data.kinds).map(([kind5,
|
|
15374
|
+
Object.entries(data.kinds).map(([kind5, value2]) => [
|
|
15338
15375
|
kind5,
|
|
15339
|
-
|
|
15340
|
-
|
|
15376
|
+
value2.evidence.state,
|
|
15377
|
+
value2.result?.summary ?? value2.evidence.reasons[0] ?? "Saved evidence is current."
|
|
15341
15378
|
])
|
|
15342
15379
|
)
|
|
15343
15380
|
);
|
|
15344
|
-
const states = Object.values(data.kinds).map((
|
|
15381
|
+
const states = Object.values(data.kinds).map((value2) => value2?.evidence.state);
|
|
15345
15382
|
if (states.some((state) => state !== "pass")) {
|
|
15346
15383
|
console.error(
|
|
15347
15384
|
"Next: fix stale, pending, or failing evidence and run apex experiments qa probe again."
|
|
@@ -15405,11 +15442,11 @@ var SCREENSHOT_DEVICES = [
|
|
|
15405
15442
|
"ipad_pro",
|
|
15406
15443
|
"desktop_safari"
|
|
15407
15444
|
];
|
|
15408
|
-
var safeFilenamePart = (
|
|
15409
|
-
var commaList = (
|
|
15410
|
-
function shellQuote(
|
|
15411
|
-
if (
|
|
15412
|
-
return `'${
|
|
15445
|
+
var safeFilenamePart = (value2) => value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "screenshot";
|
|
15446
|
+
var commaList = (value2) => value2.split(",").map((item) => item.trim()).filter(Boolean);
|
|
15447
|
+
function shellQuote(value2) {
|
|
15448
|
+
if (value2.length > 0 && /^[A-Za-z0-9_@%+=:,./-]+$/.test(value2)) return value2;
|
|
15449
|
+
return `'${value2.replaceAll("'", "'\\''")}'`;
|
|
15413
15450
|
}
|
|
15414
15451
|
function isTransientResumeStatus(status4) {
|
|
15415
15452
|
return status4 === 429 || status4 !== void 0 && status4 >= 500;
|
|
@@ -15794,11 +15831,197 @@ Examples:
|
|
|
15794
15831
|
`
|
|
15795
15832
|
);
|
|
15796
15833
|
|
|
15834
|
+
// src/commands/results.ts
|
|
15835
|
+
var import_node_fs9 = __toESM(require("node:fs"));
|
|
15836
|
+
var import_node_path7 = __toESM(require("node:path"));
|
|
15837
|
+
var import_promises3 = __toESM(require("node:readline/promises"));
|
|
15838
|
+
var OUTCOMES = /* @__PURE__ */ new Set(["won", "lost", "inconclusive"]);
|
|
15839
|
+
function collect(value2, previous) {
|
|
15840
|
+
return [...previous, value2];
|
|
15841
|
+
}
|
|
15842
|
+
function pair(command, value2, flag) {
|
|
15843
|
+
const index = value2.indexOf("=");
|
|
15844
|
+
if (index <= 0 || index === value2.length - 1)
|
|
15845
|
+
fail(command, `Invalid ${flag} "${value2}": use left=right.`, EXIT_CODES.validation);
|
|
15846
|
+
return [value2.slice(0, index).trim(), value2.slice(index + 1).trim()];
|
|
15847
|
+
}
|
|
15848
|
+
function apiFailure(command, response) {
|
|
15849
|
+
const body5 = response.data;
|
|
15850
|
+
fail(
|
|
15851
|
+
command,
|
|
15852
|
+
body5?.error?.message ?? response.error ?? `Request failed (HTTP ${response.status})`,
|
|
15853
|
+
classifyStatus(response.status),
|
|
15854
|
+
void 0,
|
|
15855
|
+
{ status: response.status, body: response.data }
|
|
15856
|
+
);
|
|
15857
|
+
}
|
|
15858
|
+
function value(row, key) {
|
|
15859
|
+
const item = row[key];
|
|
15860
|
+
return item == null ? "-" : String(item);
|
|
15861
|
+
}
|
|
15862
|
+
function printPreview(preview2) {
|
|
15863
|
+
printTable(
|
|
15864
|
+
["ROW", "TITLE", "OUTCOME", "METRIC", "LIFT", "SAMPLE", "CONF", "DEVICE", "DATES", "LEARNING"],
|
|
15865
|
+
preview2.rows.map((row, index) => [
|
|
15866
|
+
String(row.source_row ?? index + 1),
|
|
15867
|
+
value(row, "title"),
|
|
15868
|
+
value(row, "outcome"),
|
|
15869
|
+
value(row, "primary_metric"),
|
|
15870
|
+
value(row, "primary_lift"),
|
|
15871
|
+
value(row, "sample_size"),
|
|
15872
|
+
value(row, "confidence"),
|
|
15873
|
+
value(row, "device"),
|
|
15874
|
+
[row.started_at, row.ended_at].filter(Boolean).join(" \u2013 ") || "-",
|
|
15875
|
+
value(row, "learning").slice(0, 60)
|
|
15876
|
+
])
|
|
15877
|
+
);
|
|
15878
|
+
for (const error of preview2.error_rows ?? [])
|
|
15879
|
+
console.error(`${error.source_name}:${error.source_row} ${error.field}: ${error.error}`);
|
|
15880
|
+
for (const warning of preview2.warnings ?? [])
|
|
15881
|
+
console.error(`Warning: ${typeof warning === "string" ? warning : JSON.stringify(warning)}`);
|
|
15882
|
+
}
|
|
15883
|
+
var importCommand = new Command("import").description("Upload past test results from CSV or JSON files").requiredOption("--file <path>", "CSV or JSON file (repeatable)", collect, []).option(
|
|
15884
|
+
"--map <column=field>",
|
|
15885
|
+
"Map a file column to an Apex field (repeatable). Fields: title, outcome, learning, primary_lift, sample_size, page_url, page_label, device, description, started_at, ended_at, legacy_id",
|
|
15886
|
+
collect,
|
|
15887
|
+
[]
|
|
15888
|
+
).option(
|
|
15889
|
+
"--outcome-value <value=outcome>",
|
|
15890
|
+
"Map a value of the outcome column to won, lost or inconclusive (repeatable)",
|
|
15891
|
+
collect,
|
|
15892
|
+
[]
|
|
15893
|
+
).option("--source <name>", "Source name stored on every imported row (default: the file name)").option("--dry-run", "Inspect and preview without importing").option("--yes", "Confirm the import without prompting").action(async function(options) {
|
|
15894
|
+
const creds = requireCredentials();
|
|
15895
|
+
const shopId = creds.resolvedContext?.shopId;
|
|
15896
|
+
const shopCredentials = creds;
|
|
15897
|
+
const shopLabel = shopCredentials.shopDomain ?? shopCredentials.domain ?? shopId ?? "the selected shop";
|
|
15898
|
+
const makeForm = () => {
|
|
15899
|
+
const form = new FormData();
|
|
15900
|
+
for (const fileArg of options.file) {
|
|
15901
|
+
const resolved = import_node_path7.default.resolve(fileArg);
|
|
15902
|
+
let bytes;
|
|
15903
|
+
try {
|
|
15904
|
+
bytes = import_node_fs9.default.readFileSync(resolved);
|
|
15905
|
+
} catch (error) {
|
|
15906
|
+
fail(
|
|
15907
|
+
this,
|
|
15908
|
+
`Could not read ${fileArg}: ${error instanceof Error ? error.message : String(error)}`,
|
|
15909
|
+
EXIT_CODES.validation,
|
|
15910
|
+
{ code: "local_file_error" }
|
|
15911
|
+
);
|
|
15912
|
+
}
|
|
15913
|
+
form.append("files", new Blob([bytes]), import_node_path7.default.basename(resolved));
|
|
15914
|
+
}
|
|
15915
|
+
return form;
|
|
15916
|
+
};
|
|
15917
|
+
const inspected = await requestForm(creds, "POST", "/api/v1/test-results/import/inspect", makeForm());
|
|
15918
|
+
if (!inspected.ok || !inspected.data) apiFailure(this, inspected);
|
|
15919
|
+
const mapping = { ...inspected.data.data.suggested_mapping.columns };
|
|
15920
|
+
for (const raw of options.map) {
|
|
15921
|
+
const [column, field] = pair(this, raw, "--map");
|
|
15922
|
+
mapping[field] = column;
|
|
15923
|
+
}
|
|
15924
|
+
const outcomeValues = { ...inspected.data.data.suggested_mapping.outcome_values };
|
|
15925
|
+
for (const raw of options.outcomeValue) {
|
|
15926
|
+
const [source, outcome] = pair(this, raw, "--outcome-value");
|
|
15927
|
+
if (!OUTCOMES.has(outcome))
|
|
15928
|
+
fail(
|
|
15929
|
+
this,
|
|
15930
|
+
`Invalid outcome "${outcome}": use won, lost, or inconclusive.`,
|
|
15931
|
+
EXIT_CODES.validation
|
|
15932
|
+
);
|
|
15933
|
+
outcomeValues[source] = outcome;
|
|
15934
|
+
}
|
|
15935
|
+
const missing = ["title", "outcome", "learning"].filter((field) => !mapping[field]);
|
|
15936
|
+
if (missing.length)
|
|
15937
|
+
fail(
|
|
15938
|
+
this,
|
|
15939
|
+
`Unmapped required columns: ${missing.join(", ")}. Use --map <column=field>.`,
|
|
15940
|
+
EXIT_CODES.validation
|
|
15941
|
+
);
|
|
15942
|
+
const previewForm = makeForm();
|
|
15943
|
+
previewForm.append(
|
|
15944
|
+
"mapping",
|
|
15945
|
+
JSON.stringify({ columns: mapping, outcome_values: outcomeValues })
|
|
15946
|
+
);
|
|
15947
|
+
const previewResponse = await requestForm(
|
|
15948
|
+
creds,
|
|
15949
|
+
"POST",
|
|
15950
|
+
"/api/v1/test-results/import/preview",
|
|
15951
|
+
previewForm
|
|
15952
|
+
);
|
|
15953
|
+
if (!previewResponse.ok || !previewResponse.data) apiFailure(this, previewResponse);
|
|
15954
|
+
const preview2 = previewResponse.data.data;
|
|
15955
|
+
if (preview2.error_rows?.length) {
|
|
15956
|
+
if (!shouldUseJson(this)) printPreview(preview2);
|
|
15957
|
+
fail(
|
|
15958
|
+
this,
|
|
15959
|
+
`Preview found ${preview2.error_rows.length} row error(s); nothing was imported.`,
|
|
15960
|
+
EXIT_CODES.validation,
|
|
15961
|
+
{ preview: preview2 }
|
|
15962
|
+
);
|
|
15963
|
+
}
|
|
15964
|
+
if (options.dryRun) {
|
|
15965
|
+
output(this, previewResponse.data, () => printPreview(preview2));
|
|
15966
|
+
return;
|
|
15967
|
+
}
|
|
15968
|
+
if (!shouldUseJson(this)) printPreview(preview2);
|
|
15969
|
+
if (!options.yes) {
|
|
15970
|
+
const globals = this.optsWithGlobals();
|
|
15971
|
+
const retryArgs = [
|
|
15972
|
+
...options.file.map((file) => `--file ${JSON.stringify(file)}`),
|
|
15973
|
+
...options.map.map((value2) => `--map ${JSON.stringify(value2)}`),
|
|
15974
|
+
...options.outcomeValue.map((value2) => `--outcome-value ${JSON.stringify(value2)}`),
|
|
15975
|
+
...options.source !== void 0 ? [`--source ${JSON.stringify(options.source)}`] : [],
|
|
15976
|
+
...globals.shop ? [`--shop ${JSON.stringify(globals.shop)}`] : [],
|
|
15977
|
+
...globals.org ? [`--org ${JSON.stringify(globals.org)}`] : []
|
|
15978
|
+
];
|
|
15979
|
+
const retry = `apex results import ${retryArgs.join(" ")} --yes`;
|
|
15980
|
+
if (!process.stdin.isTTY)
|
|
15981
|
+
confirmationRequired(
|
|
15982
|
+
this,
|
|
15983
|
+
"Import confirmation is required in non-TTY mode; rerun with --yes.",
|
|
15984
|
+
retry
|
|
15985
|
+
);
|
|
15986
|
+
const rl = import_promises3.default.createInterface({ input: process.stdin, output: process.stderr });
|
|
15987
|
+
const answer = await rl.question(
|
|
15988
|
+
`Import ${preview2.rows.length} rows into ${shopLabel}? [y/N] `
|
|
15989
|
+
);
|
|
15990
|
+
rl.close();
|
|
15991
|
+
if (!/^y(es)?$/i.test(answer.trim()))
|
|
15992
|
+
confirmationRequired(this, "Import cancelled; rerun with --yes to confirm.", retry);
|
|
15993
|
+
}
|
|
15994
|
+
const merged = { imported: 0, skipped: 0, test_results: [] };
|
|
15995
|
+
for (let offset = 0; offset < preview2.rows.length; offset += 500) {
|
|
15996
|
+
const response = await request(
|
|
15997
|
+
creds,
|
|
15998
|
+
"POST",
|
|
15999
|
+
"/api/v1/test-results/import/confirm",
|
|
16000
|
+
{
|
|
16001
|
+
rows: preview2.rows.slice(offset, offset + 500).map((row) => options.source ? { ...row, source_name: options.source } : row)
|
|
16002
|
+
}
|
|
16003
|
+
);
|
|
16004
|
+
if (!response.ok || !response.data) apiFailure(this, response);
|
|
16005
|
+
merged.imported += response.data.data.imported;
|
|
16006
|
+
merged.skipped += response.data.data.skipped;
|
|
16007
|
+
merged.test_results.push(...response.data.data.test_results);
|
|
16008
|
+
}
|
|
16009
|
+
for (const row of merged.test_results)
|
|
16010
|
+
if (row.shop_id != null)
|
|
16011
|
+
assertResponseShop(String(row.shop_id), shopId, creds.credentialKind);
|
|
16012
|
+
output(
|
|
16013
|
+
this,
|
|
16014
|
+
merged,
|
|
16015
|
+
() => console.log(`Imported ${merged.imported}, skipped ${merged.skipped} (already present).`)
|
|
16016
|
+
);
|
|
16017
|
+
});
|
|
16018
|
+
var resultsCommand = new Command("results").description("Import and manage test results").addCommand(importCommand);
|
|
16019
|
+
|
|
15797
16020
|
// src/commands/push.ts
|
|
15798
16021
|
init_source();
|
|
15799
|
-
var
|
|
16022
|
+
var import_node_fs10 = __toESM(require("node:fs"));
|
|
15800
16023
|
var import_node_os7 = __toESM(require("node:os"));
|
|
15801
|
-
var
|
|
16024
|
+
var import_node_path8 = __toESM(require("node:path"));
|
|
15802
16025
|
var import_node_url2 = require("node:url");
|
|
15803
16026
|
function toApiBody(exp) {
|
|
15804
16027
|
return {
|
|
@@ -15839,7 +16062,7 @@ async function rewriteExperimentAssets(exp, rewrite, baseDir) {
|
|
|
15839
16062
|
};
|
|
15840
16063
|
}
|
|
15841
16064
|
async function importConfigModule(absPath) {
|
|
15842
|
-
const ext =
|
|
16065
|
+
const ext = import_node_path8.default.extname(absPath).toLowerCase();
|
|
15843
16066
|
if (ext === ".js" || ext === ".mjs" || ext === ".cjs") {
|
|
15844
16067
|
return await import((0, import_node_url2.pathToFileURL)(absPath).href);
|
|
15845
16068
|
}
|
|
@@ -15853,8 +16076,8 @@ async function importConfigModule(absPath) {
|
|
|
15853
16076
|
` + (err instanceof Error ? err.message : String(err))
|
|
15854
16077
|
);
|
|
15855
16078
|
}
|
|
15856
|
-
const tmpDir =
|
|
15857
|
-
const outFile =
|
|
16079
|
+
const tmpDir = import_node_fs10.default.mkdtempSync(import_node_path8.default.join(import_node_os7.default.tmpdir(), "drip-config-"));
|
|
16080
|
+
const outFile = import_node_path8.default.join(tmpDir, "config.mjs");
|
|
15858
16081
|
try {
|
|
15859
16082
|
await esbuild.build({
|
|
15860
16083
|
entryPoints: [absPath],
|
|
@@ -15870,15 +16093,15 @@ async function importConfigModule(absPath) {
|
|
|
15870
16093
|
return await import(href);
|
|
15871
16094
|
} finally {
|
|
15872
16095
|
try {
|
|
15873
|
-
|
|
16096
|
+
import_node_fs10.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
15874
16097
|
} catch {
|
|
15875
16098
|
}
|
|
15876
16099
|
}
|
|
15877
16100
|
}
|
|
15878
16101
|
throw new Error(`Unsupported config extension "${ext}". Use .drip.config.ts or .drip.config.js.`);
|
|
15879
16102
|
}
|
|
15880
|
-
function isRecord2(
|
|
15881
|
-
return !!
|
|
16103
|
+
function isRecord2(value2) {
|
|
16104
|
+
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
15882
16105
|
}
|
|
15883
16106
|
var pushCommand = new Command("push").description("Push experiment definitions from config file to the API (idempotent by slug)").option("-c, --config <path>", "Config file path").option("--dry-run", "Show what would be pushed without making changes").option("--no-asset-upload", "Keep inline and local image references unchanged").action(async function action23(opts) {
|
|
15884
16107
|
const creds = requireCredentials();
|
|
@@ -15891,7 +16114,7 @@ var pushCommand = new Command("push").description("Push experiment definitions f
|
|
|
15891
16114
|
);
|
|
15892
16115
|
}
|
|
15893
16116
|
const spinner = process.stderr.isTTY ? await createSpinner(`Loading config from ${source_default.cyan(configPath)}...`) : null;
|
|
15894
|
-
const absoluteConfigPath =
|
|
16117
|
+
const absoluteConfigPath = import_node_path8.default.resolve(configPath);
|
|
15895
16118
|
let experiments;
|
|
15896
16119
|
try {
|
|
15897
16120
|
const mod = await importConfigModule(absoluteConfigPath);
|
|
@@ -15958,7 +16181,7 @@ var pushCommand = new Command("push").description("Push experiment definitions f
|
|
|
15958
16181
|
return;
|
|
15959
16182
|
}
|
|
15960
16183
|
const assetRewriter = createAssetReferenceRewriter({
|
|
15961
|
-
baseDir:
|
|
16184
|
+
baseDir: import_node_path8.default.dirname(absoluteConfigPath),
|
|
15962
16185
|
baseUrl: creds.baseUrl,
|
|
15963
16186
|
enabled: opts.assetUpload !== false,
|
|
15964
16187
|
upload: async (file) => {
|
|
@@ -15988,7 +16211,7 @@ var pushCommand = new Command("push").description("Push experiment definitions f
|
|
|
15988
16211
|
let body5;
|
|
15989
16212
|
try {
|
|
15990
16213
|
body5 = toApiBody(
|
|
15991
|
-
await rewriteExperimentAssets(exp, assetRewriter,
|
|
16214
|
+
await rewriteExperimentAssets(exp, assetRewriter, import_node_path8.default.dirname(absoluteConfigPath))
|
|
15992
16215
|
);
|
|
15993
16216
|
} catch (error) {
|
|
15994
16217
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -16110,9 +16333,9 @@ var previewCommand = new Command("preview").description(
|
|
|
16110
16333
|
);
|
|
16111
16334
|
const expiresAt = new Date(data.expires_at);
|
|
16112
16335
|
const remainingMs = expiresAt.getTime() - Date.now();
|
|
16113
|
-
const
|
|
16336
|
+
const value2 = remainingMs < 864e5 ? Math.max(1, Math.round(remainingMs / 36e5)) : Math.round(remainingMs / 864e5);
|
|
16114
16337
|
const unit = remainingMs < 864e5 ? "hour" : "day";
|
|
16115
|
-
const duration = `${
|
|
16338
|
+
const duration = `${value2} ${unit}${value2 === 1 ? "" : "s"}`;
|
|
16116
16339
|
console.log(
|
|
16117
16340
|
`Valid until ${expiresAt.toISOString()} (${duration}). Re-run this command for a fresh link.`
|
|
16118
16341
|
);
|
|
@@ -16191,8 +16414,8 @@ var previewCommand = new Command("preview").description(
|
|
|
16191
16414
|
const qaFile = snapshot.data.files.find((file) => file.path === "qa.json");
|
|
16192
16415
|
if (qaFile) {
|
|
16193
16416
|
try {
|
|
16194
|
-
const
|
|
16195
|
-
if (
|
|
16417
|
+
const run4 = JSON.parse(qaFile.content)?.latestRun;
|
|
16418
|
+
if (run4 && typeof run4.id === "string" && run4.id.trim()) qaRun = run4;
|
|
16196
16419
|
} catch {
|
|
16197
16420
|
}
|
|
16198
16421
|
}
|
|
@@ -16258,25 +16481,25 @@ var previewCommand = new Command("preview").description(
|
|
|
16258
16481
|
|
|
16259
16482
|
// src/commands/harness.ts
|
|
16260
16483
|
init_source();
|
|
16261
|
-
var
|
|
16262
|
-
var
|
|
16484
|
+
var import_node_fs11 = __toESM(require("node:fs"));
|
|
16485
|
+
var import_node_path9 = __toESM(require("node:path"));
|
|
16263
16486
|
var import_node_child_process6 = require("node:child_process");
|
|
16264
|
-
function slugify(
|
|
16265
|
-
const slug =
|
|
16487
|
+
function slugify(value2, fallback2 = "variation") {
|
|
16488
|
+
const slug = value2.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
16266
16489
|
return slug || fallback2;
|
|
16267
16490
|
}
|
|
16268
16491
|
function readJson(filePath) {
|
|
16269
|
-
if (!
|
|
16270
|
-
return JSON.parse(
|
|
16492
|
+
if (!import_node_fs11.default.existsSync(filePath)) return null;
|
|
16493
|
+
return JSON.parse(import_node_fs11.default.readFileSync(filePath, "utf8"));
|
|
16271
16494
|
}
|
|
16272
16495
|
function resolveFolder(folder) {
|
|
16273
|
-
return
|
|
16496
|
+
return import_node_path9.default.resolve(process.cwd(), folder);
|
|
16274
16497
|
}
|
|
16275
16498
|
function experimentConfigPath(folder) {
|
|
16276
|
-
return
|
|
16499
|
+
return import_node_path9.default.join(folder, "experiment.config.json");
|
|
16277
16500
|
}
|
|
16278
16501
|
function apexConfigPath(folder) {
|
|
16279
|
-
return
|
|
16502
|
+
return import_node_path9.default.join(folder, "apex.harness.json");
|
|
16280
16503
|
}
|
|
16281
16504
|
function loadHarnessConfig(folder) {
|
|
16282
16505
|
const experiment2 = readJson(experimentConfigPath(folder)) ?? {};
|
|
@@ -16285,8 +16508,8 @@ function loadHarnessConfig(folder) {
|
|
|
16285
16508
|
const targetOrigin = experiment2.targetOrigin?.replace(/\/+$/, "") ?? "";
|
|
16286
16509
|
const defaultPath = experiment2.defaultPath ?? "/";
|
|
16287
16510
|
const targetUrl = targetOrigin ? new URL(defaultPath, targetOrigin).toString() : "";
|
|
16288
|
-
const id = experiment2.id ??
|
|
16289
|
-
const variation =
|
|
16511
|
+
const id = experiment2.id ?? import_node_path9.default.basename(import_node_path9.default.dirname(folder));
|
|
16512
|
+
const variation = import_node_path9.default.basename(folder);
|
|
16290
16513
|
return {
|
|
16291
16514
|
experiment: experiment2,
|
|
16292
16515
|
apex: {
|
|
@@ -16320,37 +16543,37 @@ function runAbHarness(args, cwd) {
|
|
|
16320
16543
|
function artifactPaths(folder, experiment2) {
|
|
16321
16544
|
const variant = experiment2.variant;
|
|
16322
16545
|
if (variant?.endsWith(".bundle.js")) {
|
|
16323
|
-
const jsPath =
|
|
16324
|
-
const cssPath =
|
|
16325
|
-
return { jsPath, cssPath:
|
|
16546
|
+
const jsPath = import_node_path9.default.join(folder, variant.replace(/\.bundle\.js$/, ".js"));
|
|
16547
|
+
const cssPath = import_node_path9.default.join(folder, variant.replace(/\.bundle\.js$/, ".css"));
|
|
16548
|
+
return { jsPath, cssPath: import_node_fs11.default.existsSync(cssPath) ? cssPath : null };
|
|
16326
16549
|
}
|
|
16327
|
-
const buildDir =
|
|
16328
|
-
const files =
|
|
16550
|
+
const buildDir = import_node_path9.default.join(folder, "build");
|
|
16551
|
+
const files = import_node_fs11.default.existsSync(buildDir) ? import_node_fs11.default.readdirSync(buildDir) : [];
|
|
16329
16552
|
const js = files.find(
|
|
16330
16553
|
(file) => file.endsWith(".js") && !file.endsWith(".bundle.js") && !file.endsWith(".min.js")
|
|
16331
16554
|
);
|
|
16332
16555
|
const css = files.find((file) => file.endsWith(".css") && !file.endsWith(".min.css"));
|
|
16333
16556
|
if (!js) throw new Error("Could not find harness JS artifact in build/");
|
|
16334
16557
|
return {
|
|
16335
|
-
jsPath:
|
|
16336
|
-
cssPath: css ?
|
|
16558
|
+
jsPath: import_node_path9.default.join(buildDir, js),
|
|
16559
|
+
cssPath: css ? import_node_path9.default.join(buildDir, css) : null
|
|
16337
16560
|
};
|
|
16338
16561
|
}
|
|
16339
16562
|
async function uploadVersion(params) {
|
|
16340
16563
|
const creds = requireCredentials();
|
|
16341
16564
|
const { jsPath, cssPath } = artifactPaths(params.folder, params.experiment);
|
|
16342
|
-
if (!
|
|
16565
|
+
if (!import_node_fs11.default.existsSync(jsPath)) throw new Error(`Missing JS artifact: ${jsPath}`);
|
|
16343
16566
|
const form = new FormData();
|
|
16344
16567
|
form.append(
|
|
16345
16568
|
"js",
|
|
16346
|
-
new Blob([
|
|
16347
|
-
|
|
16569
|
+
new Blob([import_node_fs11.default.readFileSync(jsPath)], { type: "application/javascript" }),
|
|
16570
|
+
import_node_path9.default.basename(jsPath)
|
|
16348
16571
|
);
|
|
16349
|
-
if (cssPath &&
|
|
16572
|
+
if (cssPath && import_node_fs11.default.existsSync(cssPath) && import_node_fs11.default.statSync(cssPath).size > 0) {
|
|
16350
16573
|
form.append(
|
|
16351
16574
|
"css",
|
|
16352
|
-
new Blob([
|
|
16353
|
-
|
|
16575
|
+
new Blob([import_node_fs11.default.readFileSync(cssPath)], { type: "text/css" }),
|
|
16576
|
+
import_node_path9.default.basename(cssPath)
|
|
16354
16577
|
);
|
|
16355
16578
|
}
|
|
16356
16579
|
form.append(
|
|
@@ -16359,8 +16582,8 @@ async function uploadVersion(params) {
|
|
|
16359
16582
|
...params.apex,
|
|
16360
16583
|
resetJs: cleanupResetJs(params.experiment),
|
|
16361
16584
|
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16362
|
-
jsPath:
|
|
16363
|
-
cssPath: cssPath ?
|
|
16585
|
+
jsPath: import_node_path9.default.relative(params.folder, jsPath),
|
|
16586
|
+
cssPath: cssPath ? import_node_path9.default.relative(params.folder, cssPath) : null
|
|
16364
16587
|
})
|
|
16365
16588
|
);
|
|
16366
16589
|
const res = await uploadHarnessVersion(creds, params.session.sessionId, form);
|
|
@@ -16402,11 +16625,11 @@ var harnessCommand = new Command("harness").description(
|
|
|
16402
16625
|
harnessCommand.command("init").argument("<folder>", "AB Test Harness experiment folder").option("--force", "Overwrite existing apex.harness.json").action(function action24(folderArg, opts) {
|
|
16403
16626
|
const folder = resolveFolder(folderArg);
|
|
16404
16627
|
const targetPath = apexConfigPath(folder);
|
|
16405
|
-
if (
|
|
16628
|
+
if (import_node_fs11.default.existsSync(targetPath) && !opts.force) {
|
|
16406
16629
|
fail(this, `${targetPath} already exists. Use --force to overwrite.`, EXIT_CODES.conflict);
|
|
16407
16630
|
}
|
|
16408
16631
|
const { apex } = loadHarnessConfig(folder);
|
|
16409
|
-
|
|
16632
|
+
import_node_fs11.default.writeFileSync(targetPath, `${JSON.stringify(apex, null, 2)}
|
|
16410
16633
|
`, "utf8");
|
|
16411
16634
|
output(
|
|
16412
16635
|
this,
|
|
@@ -16472,7 +16695,7 @@ harnessCommand.command("dev").argument("<folder>", "AB Test Harness experiment f
|
|
|
16472
16695
|
}
|
|
16473
16696
|
};
|
|
16474
16697
|
let debounce = null;
|
|
16475
|
-
const watcher =
|
|
16698
|
+
const watcher = import_node_fs11.default.watch(folder, { recursive: true }, (_event, filename) => {
|
|
16476
16699
|
const name = String(filename ?? "");
|
|
16477
16700
|
if (!name || name.startsWith("build/") || name.includes("/build/")) return;
|
|
16478
16701
|
if (debounce) clearTimeout(debounce);
|
|
@@ -16515,8 +16738,8 @@ harnessCommand.command("publish").argument("<folder>", "AB Test Harness experime
|
|
|
16515
16738
|
// src/commands/operator.ts
|
|
16516
16739
|
init_source();
|
|
16517
16740
|
var import_node_crypto7 = __toESM(require("node:crypto"));
|
|
16518
|
-
var
|
|
16519
|
-
var
|
|
16741
|
+
var import_node_fs12 = __toESM(require("node:fs"));
|
|
16742
|
+
var import_node_path10 = __toESM(require("node:path"));
|
|
16520
16743
|
var CANONICAL_FILE_RE = /^(src\/(?:index\.js|index\.scss|info\.js|mutations\.json)|experiment\.config\.json|metrics\.json|targeting\.json|dev-doc\.md|brand\.md|goals\/[a-zA-Z0-9_.-]+\.json|segments\/[a-zA-Z0-9_.-]+\.json|network\/[a-zA-Z0-9_.-]+\.recipe\.json)$/;
|
|
16521
16744
|
function workspaceIssueFile(field, evidence) {
|
|
16522
16745
|
if (field === "custom_js" || field === "reset_js") return "src/index.js";
|
|
@@ -16530,9 +16753,9 @@ function workspaceIssueFile(field, evidence) {
|
|
|
16530
16753
|
if (field === "anti_flicker_selectors") return "experiment.config.json";
|
|
16531
16754
|
return null;
|
|
16532
16755
|
}
|
|
16533
|
-
function formatWorkspaceBlockingIssues(
|
|
16534
|
-
if (!
|
|
16535
|
-
const issues =
|
|
16756
|
+
function formatWorkspaceBlockingIssues(value2) {
|
|
16757
|
+
if (!value2 || typeof value2 !== "object") return null;
|
|
16758
|
+
const issues = value2.blockingIssues;
|
|
16536
16759
|
if (!Array.isArray(issues) || issues.length === 0) return null;
|
|
16537
16760
|
return issues.map((rawIssue, index) => {
|
|
16538
16761
|
const issue = rawIssue && typeof rawIssue === "object" ? rawIssue : {};
|
|
@@ -16564,39 +16787,39 @@ function formatHarnessRefusal(message, details) {
|
|
|
16564
16787
|
return issues ? `${message}
|
|
16565
16788
|
${issues}` : message;
|
|
16566
16789
|
}
|
|
16567
|
-
function sha256Text2(
|
|
16568
|
-
return import_node_crypto7.default.createHash("sha256").update(
|
|
16790
|
+
function sha256Text2(value2) {
|
|
16791
|
+
return import_node_crypto7.default.createHash("sha256").update(value2).digest("hex");
|
|
16569
16792
|
}
|
|
16570
|
-
function byteLength(
|
|
16571
|
-
return Buffer.byteLength(
|
|
16793
|
+
function byteLength(value2) {
|
|
16794
|
+
return Buffer.byteLength(value2, "utf8");
|
|
16572
16795
|
}
|
|
16573
|
-
function slugify2(
|
|
16574
|
-
const slug =
|
|
16796
|
+
function slugify2(value2, fallback2 = "operator") {
|
|
16797
|
+
const slug = value2.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
16575
16798
|
return slug || fallback2;
|
|
16576
16799
|
}
|
|
16577
16800
|
function folderPath2(folder) {
|
|
16578
|
-
return
|
|
16801
|
+
return import_node_path10.default.resolve(process.cwd(), folder);
|
|
16579
16802
|
}
|
|
16580
16803
|
function apexDir(folder) {
|
|
16581
|
-
return
|
|
16804
|
+
return import_node_path10.default.join(folder, ".apex");
|
|
16582
16805
|
}
|
|
16583
16806
|
function sessionPath(folder) {
|
|
16584
|
-
return
|
|
16807
|
+
return import_node_path10.default.join(apexDir(folder), "session.json");
|
|
16585
16808
|
}
|
|
16586
16809
|
function readJsonFile(filePath) {
|
|
16587
|
-
if (!
|
|
16588
|
-
return JSON.parse(
|
|
16810
|
+
if (!import_node_fs12.default.existsSync(filePath)) return null;
|
|
16811
|
+
return JSON.parse(import_node_fs12.default.readFileSync(filePath, "utf8"));
|
|
16589
16812
|
}
|
|
16590
|
-
function writeJsonFile(filePath,
|
|
16591
|
-
|
|
16592
|
-
|
|
16813
|
+
function writeJsonFile(filePath, value2) {
|
|
16814
|
+
import_node_fs12.default.mkdirSync(import_node_path10.default.dirname(filePath), { recursive: true });
|
|
16815
|
+
import_node_fs12.default.writeFileSync(filePath, `${JSON.stringify(value2, null, 2)}
|
|
16593
16816
|
`, "utf8");
|
|
16594
16817
|
}
|
|
16595
16818
|
function readSession(folder) {
|
|
16596
16819
|
const session = readJsonFile(sessionPath(folder));
|
|
16597
16820
|
if (!session) {
|
|
16598
|
-
const filesystemMarker =
|
|
16599
|
-
if (
|
|
16821
|
+
const filesystemMarker = import_node_path10.default.join(apexDir(folder), "experiment-filesystem.json");
|
|
16822
|
+
if (import_node_fs12.default.existsSync(filesystemMarker)) {
|
|
16600
16823
|
throw new CliError(
|
|
16601
16824
|
"This folder is an experiment filesystem (apex experiments \u2026), not an operator workspace \u2014 run `apex experiments plan` here, or `apex workspace checkout` into a different folder.",
|
|
16602
16825
|
EXIT_CODES.general,
|
|
@@ -16626,9 +16849,9 @@ function readSession(folder) {
|
|
|
16626
16849
|
return session;
|
|
16627
16850
|
}
|
|
16628
16851
|
function writeSession(folder, session) {
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
|
|
16852
|
+
import_node_fs12.default.mkdirSync(apexDir(folder), { recursive: true });
|
|
16853
|
+
import_node_fs12.default.writeFileSync(
|
|
16854
|
+
import_node_path10.default.join(apexDir(folder), ".gitignore"),
|
|
16632
16855
|
"session.json\nharness-session.json\n",
|
|
16633
16856
|
"utf8"
|
|
16634
16857
|
);
|
|
@@ -16652,15 +16875,15 @@ function listLocalWorkspaceFiles(folder) {
|
|
|
16652
16875
|
"brand.md"
|
|
16653
16876
|
];
|
|
16654
16877
|
function visit2(dir) {
|
|
16655
|
-
if (!
|
|
16656
|
-
for (const entry of
|
|
16657
|
-
const absPath =
|
|
16878
|
+
if (!import_node_fs12.default.existsSync(dir)) return;
|
|
16879
|
+
for (const entry of import_node_fs12.default.readdirSync(dir, { withFileTypes: true })) {
|
|
16880
|
+
const absPath = import_node_path10.default.join(dir, entry.name);
|
|
16658
16881
|
if (entry.isDirectory()) {
|
|
16659
16882
|
visit2(absPath);
|
|
16660
16883
|
continue;
|
|
16661
16884
|
}
|
|
16662
|
-
const relativePath = validateCanonicalPath(
|
|
16663
|
-
const content =
|
|
16885
|
+
const relativePath = validateCanonicalPath(import_node_path10.default.relative(folder, absPath));
|
|
16886
|
+
const content = import_node_fs12.default.readFileSync(absPath, "utf8");
|
|
16664
16887
|
files.push({
|
|
16665
16888
|
path: relativePath,
|
|
16666
16889
|
absPath,
|
|
@@ -16670,11 +16893,11 @@ function listLocalWorkspaceFiles(folder) {
|
|
|
16670
16893
|
});
|
|
16671
16894
|
}
|
|
16672
16895
|
}
|
|
16673
|
-
for (const root of roots) visit2(
|
|
16896
|
+
for (const root of roots) visit2(import_node_path10.default.join(folder, root));
|
|
16674
16897
|
for (const file of topLevel) {
|
|
16675
|
-
const absPath =
|
|
16676
|
-
if (!
|
|
16677
|
-
const content =
|
|
16898
|
+
const absPath = import_node_path10.default.join(folder, file);
|
|
16899
|
+
if (!import_node_fs12.default.existsSync(absPath)) continue;
|
|
16900
|
+
const content = import_node_fs12.default.readFileSync(absPath, "utf8");
|
|
16678
16901
|
files.push({
|
|
16679
16902
|
path: file,
|
|
16680
16903
|
absPath,
|
|
@@ -16698,7 +16921,7 @@ function validateJsonFiles(files) {
|
|
|
16698
16921
|
}
|
|
16699
16922
|
}
|
|
16700
16923
|
function readExperimentConfig(folder) {
|
|
16701
|
-
return readJsonFile(
|
|
16924
|
+
return readJsonFile(import_node_path10.default.join(folder, "experiment.config.json")) ?? {};
|
|
16702
16925
|
}
|
|
16703
16926
|
function resolveVariation(exp, variationArg) {
|
|
16704
16927
|
const variations = exp.variations ?? [];
|
|
@@ -16715,9 +16938,9 @@ function resolveVariation(exp, variationArg) {
|
|
|
16715
16938
|
function writeWorkspaceFiles(folder, workspace) {
|
|
16716
16939
|
for (const file of workspace.files) {
|
|
16717
16940
|
const relativePath = validateCanonicalPath(file.path);
|
|
16718
|
-
const absPath =
|
|
16719
|
-
|
|
16720
|
-
|
|
16941
|
+
const absPath = import_node_path10.default.join(folder, relativePath);
|
|
16942
|
+
import_node_fs12.default.mkdirSync(import_node_path10.default.dirname(absPath), { recursive: true });
|
|
16943
|
+
import_node_fs12.default.writeFileSync(absPath, file.content, "utf8");
|
|
16721
16944
|
}
|
|
16722
16945
|
}
|
|
16723
16946
|
function sessionFromWorkspace(input) {
|
|
@@ -16785,10 +17008,10 @@ async function uploadCurrentArtifactVersion(folder, sessionId) {
|
|
|
16785
17008
|
form.append(
|
|
16786
17009
|
"js",
|
|
16787
17010
|
new Blob([js.content], { type: "application/javascript" }),
|
|
16788
|
-
|
|
17011
|
+
import_node_path10.default.basename(js.path)
|
|
16789
17012
|
);
|
|
16790
17013
|
if (css && css.content.trim()) {
|
|
16791
|
-
form.append("css", new Blob([css.content], { type: "text/css" }),
|
|
17014
|
+
form.append("css", new Blob([css.content], { type: "text/css" }), import_node_path10.default.basename(css.path));
|
|
16792
17015
|
}
|
|
16793
17016
|
form.append("manifest", JSON.stringify(manifest));
|
|
16794
17017
|
const res = await uploadHarnessVersion(creds, sessionId, form);
|
|
@@ -16915,7 +17138,7 @@ operatorCommand.command("checkout").argument("<experiment-id>", "Apex experiment
|
|
|
16915
17138
|
classifyStatus(workspace.status),
|
|
16916
17139
|
workspace.errorDetails
|
|
16917
17140
|
);
|
|
16918
|
-
|
|
17141
|
+
import_node_fs12.default.mkdirSync(folder, { recursive: true });
|
|
16919
17142
|
writeWorkspaceFiles(folder, workspace.data);
|
|
16920
17143
|
writeSession(
|
|
16921
17144
|
folder,
|
|
@@ -16982,8 +17205,8 @@ operatorCommand.command("dev").argument("[folder]", "Operator workspace folder",
|
|
|
16982
17205
|
const session = readSession(folder);
|
|
16983
17206
|
const harnessSession = await createExactHarnessSession(folder, session);
|
|
16984
17207
|
const version = await uploadCurrentArtifactVersion(folder, harnessSession.sessionId);
|
|
16985
|
-
|
|
16986
|
-
writeJsonFile(
|
|
17208
|
+
import_node_fs12.default.mkdirSync(apexDir(folder), { recursive: true });
|
|
17209
|
+
writeJsonFile(import_node_path10.default.join(apexDir(folder), "harness-session.json"), {
|
|
16987
17210
|
sessionId: harnessSession.sessionId,
|
|
16988
17211
|
experimentId: harnessSession.experimentId,
|
|
16989
17212
|
variationId: harnessSession.variationId,
|
|
@@ -17038,7 +17261,7 @@ operatorCommand.command("dev").argument("[folder]", "Operator workspace folder",
|
|
|
17038
17261
|
}
|
|
17039
17262
|
};
|
|
17040
17263
|
let timer = null;
|
|
17041
|
-
const watcher =
|
|
17264
|
+
const watcher = import_node_fs12.default.watch(folder, { recursive: true }, (_event, filename) => {
|
|
17042
17265
|
const name = String(filename ?? "");
|
|
17043
17266
|
if (!name || name.startsWith(".apex/") || name.includes("/.apex/")) return;
|
|
17044
17267
|
if (timer) clearTimeout(timer);
|
|
@@ -17073,17 +17296,17 @@ operatorCommand.command("publish").argument("[folder]", "Operator workspace fold
|
|
|
17073
17296
|
|
|
17074
17297
|
// src/commands/roadmap.ts
|
|
17075
17298
|
init_source();
|
|
17076
|
-
var
|
|
17077
|
-
var
|
|
17299
|
+
var import_node_fs13 = __toESM(require("node:fs"));
|
|
17300
|
+
var import_node_path11 = __toESM(require("node:path"));
|
|
17078
17301
|
var LEGACY_OUTPUT_REMOVAL_VERSION = "0.7.0";
|
|
17079
|
-
function truncate(
|
|
17080
|
-
const text2 = typeof
|
|
17302
|
+
function truncate(value2, max) {
|
|
17303
|
+
const text2 = typeof value2 === "string" ? value2 : value2 == null ? "" : String(value2);
|
|
17081
17304
|
if (text2.length <= max) return text2;
|
|
17082
17305
|
return `${text2.slice(0, Math.max(0, max - 3))}...`;
|
|
17083
17306
|
}
|
|
17084
|
-
function score(
|
|
17085
|
-
if (typeof
|
|
17086
|
-
return Number.isInteger(
|
|
17307
|
+
function score(value2) {
|
|
17308
|
+
if (typeof value2 !== "number" || !Number.isFinite(value2)) return "-";
|
|
17309
|
+
return Number.isInteger(value2) ? String(value2) : value2.toFixed(1);
|
|
17087
17310
|
}
|
|
17088
17311
|
function experimentState(item) {
|
|
17089
17312
|
const linked = item.linked_experiments ?? [];
|
|
@@ -17184,9 +17407,9 @@ var handoff = new Command("handoff").description(
|
|
|
17184
17407
|
`;
|
|
17185
17408
|
const outputData = opts.instructions ? { roadmapItemId: id, instructions: String(payload.instructions ?? "") } : payload;
|
|
17186
17409
|
if (opts.out || opts.output) {
|
|
17187
|
-
const target =
|
|
17188
|
-
|
|
17189
|
-
|
|
17410
|
+
const target = import_node_path11.default.resolve(process.cwd(), opts.out ?? opts.output);
|
|
17411
|
+
import_node_fs13.default.mkdirSync(import_node_path11.default.dirname(target), { recursive: true });
|
|
17412
|
+
import_node_fs13.default.writeFileSync(target, rendered, "utf8");
|
|
17190
17413
|
output(this, { path: target, roadmapItemId: id }, () => printSuccess(`Wrote ${target}`));
|
|
17191
17414
|
return;
|
|
17192
17415
|
}
|
|
@@ -17200,13 +17423,13 @@ roadmapCommand.addCommand(handoff);
|
|
|
17200
17423
|
|
|
17201
17424
|
// src/commands/tracking.ts
|
|
17202
17425
|
init_source();
|
|
17203
|
-
var
|
|
17204
|
-
var
|
|
17426
|
+
var import_node_fs14 = __toESM(require("node:fs"));
|
|
17427
|
+
var import_node_path12 = __toESM(require("node:path"));
|
|
17205
17428
|
function normalizeUrl(input) {
|
|
17206
|
-
const
|
|
17207
|
-
if (!
|
|
17429
|
+
const value2 = input.trim();
|
|
17430
|
+
if (!value2) throw new Error("URL cannot be empty");
|
|
17208
17431
|
try {
|
|
17209
|
-
return new URL(
|
|
17432
|
+
return new URL(value2.includes("://") ? value2 : `https://${value2}`);
|
|
17210
17433
|
} catch {
|
|
17211
17434
|
throw new Error(`Invalid URL: ${input}`);
|
|
17212
17435
|
}
|
|
@@ -17248,14 +17471,14 @@ function commonCookieDomain(hostnames) {
|
|
|
17248
17471
|
}
|
|
17249
17472
|
var DEFAULT_MANIFEST_PATH = ".apex/tracking-manifest.json";
|
|
17250
17473
|
function readManifest(filePath) {
|
|
17251
|
-
if (!
|
|
17252
|
-
const parsed = JSON.parse(
|
|
17474
|
+
if (!import_node_fs14.default.existsSync(filePath)) throw new Error(`Manifest not found: ${filePath}`);
|
|
17475
|
+
const parsed = JSON.parse(import_node_fs14.default.readFileSync(filePath, "utf8"));
|
|
17253
17476
|
if (parsed.schemaVersion !== 1) throw new Error("Unsupported tracking manifest schema");
|
|
17254
17477
|
return parsed;
|
|
17255
17478
|
}
|
|
17256
17479
|
function writeManifest(filePath, manifest) {
|
|
17257
|
-
|
|
17258
|
-
|
|
17480
|
+
import_node_fs14.default.mkdirSync(import_node_path12.default.dirname(filePath), { recursive: true });
|
|
17481
|
+
import_node_fs14.default.writeFileSync(filePath, `${JSON.stringify(manifest, null, 2)}
|
|
17259
17482
|
`, "utf8");
|
|
17260
17483
|
}
|
|
17261
17484
|
function buildSnippet(shopId, endpoint) {
|
|
@@ -17322,7 +17545,7 @@ function buildManifest(urlArgs, opts) {
|
|
|
17322
17545
|
};
|
|
17323
17546
|
}
|
|
17324
17547
|
function manifestPath(input) {
|
|
17325
|
-
return
|
|
17548
|
+
return import_node_path12.default.resolve(process.cwd(), input ?? DEFAULT_MANIFEST_PATH);
|
|
17326
17549
|
}
|
|
17327
17550
|
function printManifestPlan(manifest) {
|
|
17328
17551
|
console.log(source_default.bold("Apex tracking ingestion plan"));
|
|
@@ -17472,7 +17695,7 @@ trackingCommand.command("latency").description("Measure forced-preview versus na
|
|
|
17472
17695
|
["natural", summary.natural],
|
|
17473
17696
|
...summary.qa_session ? [["qa_session", summary.qa_session]] : []
|
|
17474
17697
|
];
|
|
17475
|
-
const ms = (
|
|
17698
|
+
const ms = (value2) => value2 === null ? "-" : String(Math.round(value2));
|
|
17476
17699
|
printTable(
|
|
17477
17700
|
[
|
|
17478
17701
|
"Bucket",
|
|
@@ -17508,7 +17731,7 @@ trackingCommand.command("latency").description("Measure forced-preview versus na
|
|
|
17508
17731
|
});
|
|
17509
17732
|
|
|
17510
17733
|
// src/commands/events.ts
|
|
17511
|
-
var
|
|
17734
|
+
var import_node_fs15 = __toESM(require("node:fs"));
|
|
17512
17735
|
var maxWindowMs = 31 * 864e5;
|
|
17513
17736
|
function correctedWindowStep(opts, nowMs) {
|
|
17514
17737
|
const fromMs = Date.parse(opts.from);
|
|
@@ -17519,7 +17742,7 @@ function correctedWindowStep(opts, nowMs) {
|
|
|
17519
17742
|
why: "No valid export window exists from this start; --to must be after --from and at or before now."
|
|
17520
17743
|
};
|
|
17521
17744
|
}
|
|
17522
|
-
const quote = (
|
|
17745
|
+
const quote = (value2) => `'${value2.replace(/'/g, "'\\''")}'`;
|
|
17523
17746
|
const args = [
|
|
17524
17747
|
"apex events export",
|
|
17525
17748
|
`--from ${quote(opts.from)}`,
|
|
@@ -17611,7 +17834,7 @@ eventsCommand.command("export").description(
|
|
|
17611
17834
|
if (opts.jsonSummary && !opts.out) {
|
|
17612
17835
|
fail(command, "--json-summary requires --out for the event rows", EXIT_CODES.validation);
|
|
17613
17836
|
}
|
|
17614
|
-
const output2 = opts.out ?
|
|
17837
|
+
const output2 = opts.out ? import_node_fs15.default.createWriteStream(opts.out, { flags: "wx" }) : null;
|
|
17615
17838
|
let outputError = null;
|
|
17616
17839
|
output2?.on("error", (error) => {
|
|
17617
17840
|
outputError = error;
|
|
@@ -17659,7 +17882,7 @@ eventsCommand.command("export").description(
|
|
|
17659
17882
|
from: opts.from,
|
|
17660
17883
|
to: opts.to,
|
|
17661
17884
|
experiment: opts.experiment,
|
|
17662
|
-
eventTypes: opts.eventType?.split(",").map((
|
|
17885
|
+
eventTypes: opts.eventType?.split(",").map((value2) => value2.trim()).filter(Boolean),
|
|
17663
17886
|
qa: opts.qa,
|
|
17664
17887
|
limit,
|
|
17665
17888
|
cursor
|
|
@@ -17750,7 +17973,7 @@ eventsCommand.command("export").description(
|
|
|
17750
17973
|
} catch (error) {
|
|
17751
17974
|
if (output2 && opts.out) {
|
|
17752
17975
|
output2.destroy();
|
|
17753
|
-
|
|
17976
|
+
import_node_fs15.default.rmSync(opts.out, { force: true });
|
|
17754
17977
|
const suffix = `The partial file ${opts.out} was removed.`;
|
|
17755
17978
|
if (error instanceof CliError)
|
|
17756
17979
|
throw new CliError(
|
|
@@ -17771,8 +17994,8 @@ eventsCommand.command("export").description(
|
|
|
17771
17994
|
|
|
17772
17995
|
// src/commands/goals.ts
|
|
17773
17996
|
init_source();
|
|
17774
|
-
var
|
|
17775
|
-
var
|
|
17997
|
+
var import_node_fs16 = __toESM(require("node:fs"));
|
|
17998
|
+
var import_node_path13 = __toESM(require("node:path"));
|
|
17776
17999
|
|
|
17777
18000
|
// ../sdk/src/safe-regex.ts
|
|
17778
18001
|
var MAX_PATTERN_LENGTH = 1024;
|
|
@@ -17949,10 +18172,10 @@ function printSuggestions(data) {
|
|
|
17949
18172
|
for (const trigger of data.triggers) console.log(`- ${trigger.page}: ${trigger.description}`);
|
|
17950
18173
|
}
|
|
17951
18174
|
}
|
|
17952
|
-
function parseCapture(command,
|
|
17953
|
-
if (!
|
|
17954
|
-
const source =
|
|
17955
|
-
const text2 =
|
|
18175
|
+
function parseCapture(command, value2) {
|
|
18176
|
+
if (!value2) return void 0;
|
|
18177
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
18178
|
+
const text2 = value2.startsWith("@") || import_node_fs16.default.existsSync(source) ? import_node_fs16.default.readFileSync(import_node_path13.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
17956
18179
|
try {
|
|
17957
18180
|
return JSON.parse(text2);
|
|
17958
18181
|
} catch (error) {
|
|
@@ -17961,10 +18184,10 @@ function parseCapture(command, value) {
|
|
|
17961
18184
|
}
|
|
17962
18185
|
}
|
|
17963
18186
|
function cleanBody(input) {
|
|
17964
|
-
return Object.fromEntries(Object.entries(input).filter(([,
|
|
18187
|
+
return Object.fromEntries(Object.entries(input).filter(([, value2]) => value2 !== void 0));
|
|
17965
18188
|
}
|
|
17966
|
-
async function resolveGoalPageId(command, creds,
|
|
17967
|
-
if (UUID_V1_TO_V8.test(
|
|
18189
|
+
async function resolveGoalPageId(command, creds, value2) {
|
|
18190
|
+
if (UUID_V1_TO_V8.test(value2)) return value2;
|
|
17968
18191
|
let cursor;
|
|
17969
18192
|
for (let page = 0; page < MAX_PAGE_LOOKUP_PAGES; page += 1) {
|
|
17970
18193
|
const response = await requestTargetingResource(
|
|
@@ -18002,7 +18225,7 @@ async function resolveGoalPageId(command, creds, value) {
|
|
|
18002
18225
|
}
|
|
18003
18226
|
if (!("data" in response.data) || !Array.isArray(response.data.data)) break;
|
|
18004
18227
|
const pageData = response.data;
|
|
18005
|
-
const match2 = pageData.data.find((item) => item.key ===
|
|
18228
|
+
const match2 = pageData.data.find((item) => item.key === value2);
|
|
18006
18229
|
if (match2) return match2.id;
|
|
18007
18230
|
const next = pageData.pagination?.next_cursor ?? null;
|
|
18008
18231
|
if (!pageData.pagination?.has_more || !next || next === cursor) break;
|
|
@@ -18010,7 +18233,7 @@ async function resolveGoalPageId(command, creds, value) {
|
|
|
18010
18233
|
}
|
|
18011
18234
|
fail(
|
|
18012
18235
|
command,
|
|
18013
|
-
`No active page with key ${
|
|
18236
|
+
`No active page with key ${value2} in this shop; list pages with apex pages list`,
|
|
18014
18237
|
EXIT_CODES.validation,
|
|
18015
18238
|
{ code: "page_not_found", next_steps: PAGE_NEXT_STEPS }
|
|
18016
18239
|
);
|
|
@@ -18235,8 +18458,8 @@ var suggest = new Command("suggest").description("Suggest goals and funnels from
|
|
|
18235
18458
|
"Confirmation required; rerun with --yes to create suggested goals.",
|
|
18236
18459
|
EXIT_CODES.confirmationRequired
|
|
18237
18460
|
);
|
|
18238
|
-
const
|
|
18239
|
-
const rl =
|
|
18461
|
+
const readline4 = await import("node:readline");
|
|
18462
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
18240
18463
|
const answer = await new Promise(
|
|
18241
18464
|
(resolve2) => rl.question(source_default.yellow("Create this goal? [y/N] "), resolve2)
|
|
18242
18465
|
);
|
|
@@ -18275,12 +18498,12 @@ Examples:
|
|
|
18275
18498
|
|
|
18276
18499
|
// src/commands/funnels.ts
|
|
18277
18500
|
init_source();
|
|
18278
|
-
var
|
|
18279
|
-
var
|
|
18501
|
+
var import_node_fs17 = __toESM(require("node:fs"));
|
|
18502
|
+
var import_node_path14 = __toESM(require("node:path"));
|
|
18280
18503
|
function readSteps(command, file) {
|
|
18281
18504
|
let parsed;
|
|
18282
18505
|
try {
|
|
18283
|
-
parsed = JSON.parse(
|
|
18506
|
+
parsed = JSON.parse(import_node_fs17.default.readFileSync(import_node_path14.default.resolve(process.cwd(), file), "utf8"));
|
|
18284
18507
|
} catch (error) {
|
|
18285
18508
|
fail(
|
|
18286
18509
|
command,
|
|
@@ -18410,8 +18633,8 @@ function printEnvironments(items) {
|
|
|
18410
18633
|
[24, 32, 8, 64]
|
|
18411
18634
|
);
|
|
18412
18635
|
}
|
|
18413
|
-
function normalizeEnvironmentDomain(
|
|
18414
|
-
const candidate =
|
|
18636
|
+
function normalizeEnvironmentDomain(value2) {
|
|
18637
|
+
const candidate = value2.trim().toLowerCase();
|
|
18415
18638
|
if (!candidate) return "";
|
|
18416
18639
|
try {
|
|
18417
18640
|
const parsed = new URL(
|
|
@@ -18470,11 +18693,11 @@ var setDomain = new Command("set-domain").description("Map a domain to a runtime
|
|
|
18470
18693
|
...item,
|
|
18471
18694
|
domains: item.key === opts.environment ? [
|
|
18472
18695
|
...item.domains.filter(
|
|
18473
|
-
(
|
|
18696
|
+
(value2) => normalizeEnvironmentDomain(value2) !== normalizedDomain
|
|
18474
18697
|
),
|
|
18475
18698
|
normalizedDomain
|
|
18476
18699
|
] : item.domains.filter(
|
|
18477
|
-
(
|
|
18700
|
+
(value2) => normalizeEnvironmentDomain(value2) !== normalizedDomain
|
|
18478
18701
|
)
|
|
18479
18702
|
}));
|
|
18480
18703
|
result = await updateEnvironments(requireCredentials(), {
|
|
@@ -18505,7 +18728,7 @@ var removeDomain = new Command("remove-domain").description("Remove a domain map
|
|
|
18505
18728
|
const items = current.environments.items.map((item) => ({
|
|
18506
18729
|
...item,
|
|
18507
18730
|
domains: item.domains.filter(
|
|
18508
|
-
(
|
|
18731
|
+
(value2) => normalizeEnvironmentDomain(value2) !== normalizedDomain
|
|
18509
18732
|
)
|
|
18510
18733
|
}));
|
|
18511
18734
|
result = await updateEnvironments(requireCredentials(), {
|
|
@@ -18594,8 +18817,8 @@ var off = new Command("off").description("Disable consent gating").action(async
|
|
|
18594
18817
|
var consentCommand = new Command("consent").description("Manage consent gating").addCommand(get2).addCommand(set).addCommand(off);
|
|
18595
18818
|
|
|
18596
18819
|
// src/commands/project-code.ts
|
|
18597
|
-
var
|
|
18598
|
-
var
|
|
18820
|
+
var import_node_fs18 = require("node:fs");
|
|
18821
|
+
var import_node_path15 = require("node:path");
|
|
18599
18822
|
|
|
18600
18823
|
// src/commands/runtime-settings-shop.ts
|
|
18601
18824
|
var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -18640,17 +18863,17 @@ var fields = ["enabled", "css", "helperJs", "js"];
|
|
|
18640
18863
|
function readPatch(command, file) {
|
|
18641
18864
|
let input;
|
|
18642
18865
|
try {
|
|
18643
|
-
input = JSON.parse((0,
|
|
18866
|
+
input = JSON.parse((0, import_node_fs18.readFileSync)(file, "utf8"));
|
|
18644
18867
|
} catch (error) {
|
|
18645
18868
|
fail(command, `Cannot read project code JSON: ${String(error)}`, EXIT_CODES.validation);
|
|
18646
18869
|
}
|
|
18647
18870
|
if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).length === 0) {
|
|
18648
18871
|
fail(command, "Project code must be a nonempty partial object", EXIT_CODES.validation);
|
|
18649
18872
|
}
|
|
18650
|
-
for (const [key,
|
|
18873
|
+
for (const [key, value2] of Object.entries(input)) {
|
|
18651
18874
|
if (!fields.includes(key))
|
|
18652
18875
|
fail(command, `Unknown project code field: ${key}`, EXIT_CODES.validation);
|
|
18653
|
-
if (key === "enabled" ? typeof
|
|
18876
|
+
if (key === "enabled" ? typeof value2 !== "boolean" : value2 !== null && (typeof value2 !== "string" || value2.length > 2e4)) {
|
|
18654
18877
|
fail(
|
|
18655
18878
|
command,
|
|
18656
18879
|
`${key} must be ${key === "enabled" ? "a boolean" : "null or a string of at most 20,000 characters"}`,
|
|
@@ -18743,9 +18966,9 @@ for (const mode of ["diff", "set"]) {
|
|
|
18743
18966
|
);
|
|
18744
18967
|
return;
|
|
18745
18968
|
}
|
|
18746
|
-
const backupPath = (0,
|
|
18969
|
+
const backupPath = (0, import_node_path15.resolve)(options.backup);
|
|
18747
18970
|
try {
|
|
18748
|
-
(0,
|
|
18971
|
+
(0, import_node_fs18.writeFileSync)(
|
|
18749
18972
|
backupPath,
|
|
18750
18973
|
`${JSON.stringify({ ...identity2, ...current, capturedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)}
|
|
18751
18974
|
`,
|
|
@@ -18804,17 +19027,17 @@ for (const mode of ["diff", "set"]) {
|
|
|
18804
19027
|
}
|
|
18805
19028
|
|
|
18806
19029
|
// src/commands/triggers.ts
|
|
18807
|
-
var
|
|
18808
|
-
var
|
|
19030
|
+
var import_node_fs19 = __toESM(require("node:fs"));
|
|
19031
|
+
var import_node_path16 = __toESM(require("node:path"));
|
|
18809
19032
|
|
|
18810
19033
|
// src/trigger-proposal.ts
|
|
18811
|
-
function runtimePath(
|
|
18812
|
-
return
|
|
19034
|
+
function runtimePath(path27) {
|
|
19035
|
+
return path27.replaceAll("[]", ".0");
|
|
18813
19036
|
}
|
|
18814
|
-
function fieldsFrom(
|
|
18815
|
-
if (!
|
|
18816
|
-
if (Array.isArray(
|
|
18817
|
-
return
|
|
19037
|
+
function fieldsFrom(value2, prefix = "", descriptorList = false) {
|
|
19038
|
+
if (!value2 || typeof value2 !== "object") return [];
|
|
19039
|
+
if (Array.isArray(value2)) {
|
|
19040
|
+
return value2.flatMap(
|
|
18818
19041
|
(item, index) => fieldsFrom(
|
|
18819
19042
|
item,
|
|
18820
19043
|
descriptorList ? prefix : prefix ? `${prefix}.${index}` : String(index),
|
|
@@ -18822,7 +19045,7 @@ function fieldsFrom(value, prefix = "", descriptorList = false) {
|
|
|
18822
19045
|
)
|
|
18823
19046
|
);
|
|
18824
19047
|
}
|
|
18825
|
-
const record4 =
|
|
19048
|
+
const record4 = value2;
|
|
18826
19049
|
const explicitPath = typeof record4.path === "string" ? record4.path : void 0;
|
|
18827
19050
|
if (descriptorList && explicitPath) {
|
|
18828
19051
|
const rawValues = record4.values ?? record4.samples ?? record4.examples ?? record4.example;
|
|
@@ -18849,7 +19072,7 @@ function fieldsFrom(value, prefix = "", descriptorList = false) {
|
|
|
18849
19072
|
return fieldsFrom(child, next);
|
|
18850
19073
|
});
|
|
18851
19074
|
}
|
|
18852
|
-
function isDescriptorArray(
|
|
19075
|
+
function isDescriptorArray(value2) {
|
|
18853
19076
|
const descriptorKeys = /* @__PURE__ */ new Set([
|
|
18854
19077
|
"path",
|
|
18855
19078
|
"values",
|
|
@@ -18864,7 +19087,7 @@ function isDescriptorArray(value) {
|
|
|
18864
19087
|
"seen",
|
|
18865
19088
|
"type_collision"
|
|
18866
19089
|
]);
|
|
18867
|
-
return Array.isArray(
|
|
19090
|
+
return Array.isArray(value2) && value2.length > 0 && value2.every((item) => {
|
|
18868
19091
|
if (!item || typeof item !== "object" || Array.isArray(item)) return false;
|
|
18869
19092
|
const record4 = item;
|
|
18870
19093
|
return typeof record4.path === "string" && record4.path.length > 0 && Object.keys(record4).every((key) => descriptorKeys.has(key));
|
|
@@ -18887,15 +19110,15 @@ function candidatesFrom(report) {
|
|
|
18887
19110
|
}
|
|
18888
19111
|
return [root];
|
|
18889
19112
|
}
|
|
18890
|
-
function score2(
|
|
19113
|
+
function score2(path27, patterns) {
|
|
18891
19114
|
return patterns.reduce(
|
|
18892
|
-
(total, pattern, index) => total + (pattern.test(
|
|
19115
|
+
(total, pattern, index) => total + (pattern.test(path27) ? patterns.length - index : 0),
|
|
18893
19116
|
0
|
|
18894
19117
|
);
|
|
18895
19118
|
}
|
|
18896
19119
|
function best(fields3, patterns, numeric2 = false) {
|
|
18897
19120
|
const ranked = fields3.filter(
|
|
18898
|
-
(field) => !numeric2 || field.numericType === true || field.values.some((
|
|
19121
|
+
(field) => !numeric2 || field.numericType === true || field.values.some((value2) => typeof value2 === "number") || field.magnitude !== void 0
|
|
18899
19122
|
).map((field) => ({ field, score: score2(field.path.toLowerCase(), patterns) })).filter((item) => item.score > 0).sort((a, b) => b.score - a.score || (b.field.magnitude ?? 0) - (a.field.magnitude ?? 0));
|
|
18900
19123
|
if (!ranked.length) return [];
|
|
18901
19124
|
const top = ranked[0].score;
|
|
@@ -19020,55 +19243,55 @@ var pathPattern = new RegExp(runtime_settings_trigger_constants_default.dotPathP
|
|
|
19020
19243
|
var signalPathPattern = new RegExp(runtime_settings_trigger_constants_default.signalPathPattern);
|
|
19021
19244
|
var valueTypes = new Set(runtime_settings_trigger_constants_default.valueTypes);
|
|
19022
19245
|
var whenOps = new Set(runtime_settings_trigger_constants_default.whenOps);
|
|
19023
|
-
function strictObject(
|
|
19024
|
-
if (!
|
|
19246
|
+
function strictObject(value2, location, keys) {
|
|
19247
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2))
|
|
19025
19248
|
throw new Error(`${location} must be an object`);
|
|
19026
|
-
const record4 =
|
|
19249
|
+
const record4 = value2;
|
|
19027
19250
|
for (const key of Object.keys(record4))
|
|
19028
19251
|
if (!keys.has(key)) throw new Error(`${location}.${key} is not allowed`);
|
|
19029
19252
|
return record4;
|
|
19030
19253
|
}
|
|
19031
|
-
function optionalType(
|
|
19032
|
-
if (
|
|
19254
|
+
function optionalType(value2, type, location) {
|
|
19255
|
+
if (value2 !== void 0 && typeof value2 !== type)
|
|
19033
19256
|
throw new Error(`${location} must be a ${type}`);
|
|
19034
19257
|
}
|
|
19035
|
-
function strictPath(
|
|
19036
|
-
if (
|
|
19037
|
-
if (typeof
|
|
19258
|
+
function strictPath(value2, location, required = false) {
|
|
19259
|
+
if (value2 === void 0 && !required) return;
|
|
19260
|
+
if (typeof value2 !== "string" || !pathPattern.test(value2))
|
|
19038
19261
|
throw new Error(
|
|
19039
19262
|
`${location} must use dot-path syntax with property or array-index segments (for example: ecommerce.items.0.price); bracket syntax is not accepted`
|
|
19040
19263
|
);
|
|
19041
19264
|
}
|
|
19042
|
-
function strictSource(
|
|
19043
|
-
if (
|
|
19044
|
-
const sources = Array.isArray(
|
|
19045
|
-
if (Array.isArray(
|
|
19265
|
+
function strictSource(value2, location, allowSignal, required = false) {
|
|
19266
|
+
if (value2 === void 0 && !required) return;
|
|
19267
|
+
const sources = Array.isArray(value2) ? value2 : [value2];
|
|
19268
|
+
if (Array.isArray(value2) && (value2.length < 1 || value2.length > runtime_settings_trigger_constants_default.maxSourcePaths))
|
|
19046
19269
|
throw new Error(`${location} must contain 1 to ${runtime_settings_trigger_constants_default.maxSourcePaths} paths`);
|
|
19047
19270
|
sources.forEach((source, index) => {
|
|
19048
|
-
const sourceLocation = Array.isArray(
|
|
19271
|
+
const sourceLocation = Array.isArray(value2) ? `${location}[${index}]` : location;
|
|
19049
19272
|
if (allowSignal && typeof source === "string" && signalPathPattern.test(source)) return;
|
|
19050
19273
|
strictPath(source, sourceLocation, true);
|
|
19051
19274
|
});
|
|
19052
19275
|
}
|
|
19053
|
-
function defaultMatchesValueType(
|
|
19276
|
+
function defaultMatchesValueType(value2, valueType) {
|
|
19054
19277
|
if (valueType === "number") {
|
|
19055
|
-
if (typeof
|
|
19056
|
-
const text2 = String(
|
|
19278
|
+
if (typeof value2 !== "string") return Number.isFinite(Number(value2));
|
|
19279
|
+
const text2 = String(value2).trim();
|
|
19057
19280
|
const normalized = /^-?\d{1,3}(\.\d{3})+,\d+$/.test(text2) ? text2.replace(/\./g, "").replace(",", ".") : /^-?\d+,\d+$/.test(text2) ? text2.replace(",", ".") : text2;
|
|
19058
19281
|
return Number.isFinite(Number(normalized));
|
|
19059
19282
|
}
|
|
19060
19283
|
if (valueType === "boolean") {
|
|
19061
|
-
if (typeof
|
|
19284
|
+
if (typeof value2 === "boolean") return true;
|
|
19062
19285
|
return ["1", "true", "yes", "on", "0", "false", "no", "off"].includes(
|
|
19063
|
-
String(
|
|
19286
|
+
String(value2).trim().toLowerCase()
|
|
19064
19287
|
);
|
|
19065
19288
|
}
|
|
19066
19289
|
return true;
|
|
19067
19290
|
}
|
|
19068
|
-
function strictTransform(
|
|
19069
|
-
if (
|
|
19291
|
+
function strictTransform(value2, valueType, location) {
|
|
19292
|
+
if (value2 === void 0) return;
|
|
19070
19293
|
const transform = strictObject(
|
|
19071
|
-
|
|
19294
|
+
value2,
|
|
19072
19295
|
location,
|
|
19073
19296
|
/* @__PURE__ */ new Set(["trim", "lowercase", "map", "scale", "default"])
|
|
19074
19297
|
);
|
|
@@ -19101,7 +19324,7 @@ function strictTransform(value, valueType, location) {
|
|
|
19101
19324
|
if (transform.default !== void 0 && !defaultMatchesValueType(transform.default, valueType))
|
|
19102
19325
|
throw new Error(`${location}.default must coerce to the mapping valueType`);
|
|
19103
19326
|
}
|
|
19104
|
-
function strictMapping(
|
|
19327
|
+
function strictMapping(value2, location, revenueProperty) {
|
|
19105
19328
|
const keys = /* @__PURE__ */ new Set([
|
|
19106
19329
|
"from",
|
|
19107
19330
|
"to",
|
|
@@ -19109,7 +19332,7 @@ function strictMapping(value, location, revenueProperty) {
|
|
|
19109
19332
|
"transform",
|
|
19110
19333
|
...revenueProperty ? [] : ["ttlDays", "persist"]
|
|
19111
19334
|
]);
|
|
19112
|
-
const mapping = strictObject(
|
|
19335
|
+
const mapping = strictObject(value2, location, keys);
|
|
19113
19336
|
strictSource(mapping.from, `${location}.from`, revenueProperty, true);
|
|
19114
19337
|
strictPath(mapping.to, `${location}.to`, true);
|
|
19115
19338
|
if (mapping.valueType !== void 0 && !valueTypes.has(String(mapping.valueType)))
|
|
@@ -19120,12 +19343,12 @@ function strictMapping(value, location, revenueProperty) {
|
|
|
19120
19343
|
optionalType(mapping.persist, "boolean", `${location}.persist`);
|
|
19121
19344
|
}
|
|
19122
19345
|
}
|
|
19123
|
-
function strictWhen(
|
|
19124
|
-
if (
|
|
19125
|
-
if (!Array.isArray(
|
|
19346
|
+
function strictWhen(value2, location) {
|
|
19347
|
+
if (value2 === void 0) return;
|
|
19348
|
+
if (!Array.isArray(value2) || value2.length < 1 || value2.length > runtime_settings_trigger_constants_default.maxWhenEntries) {
|
|
19126
19349
|
throw new Error(`${location} must contain 1 to ${runtime_settings_trigger_constants_default.maxWhenEntries} entries`);
|
|
19127
19350
|
}
|
|
19128
|
-
|
|
19351
|
+
value2.forEach((entry, index) => {
|
|
19129
19352
|
const entryLocation = `${location}[${index}]`;
|
|
19130
19353
|
const condition = strictObject(entry, entryLocation, /* @__PURE__ */ new Set(["path", "op", "value"]));
|
|
19131
19354
|
strictPath(condition.path, `${entryLocation}.path`, true);
|
|
@@ -19154,12 +19377,12 @@ function strictWhen(value, location) {
|
|
|
19154
19377
|
}
|
|
19155
19378
|
});
|
|
19156
19379
|
}
|
|
19157
|
-
function strictTriggers(
|
|
19158
|
-
if (!Array.isArray(
|
|
19380
|
+
function strictTriggers(value2) {
|
|
19381
|
+
if (!Array.isArray(value2) || value2.length > runtime_settings_trigger_constants_default.maxTriggers)
|
|
19159
19382
|
throw new Error(
|
|
19160
19383
|
`trigger file must contain an array of at most ${runtime_settings_trigger_constants_default.maxTriggers} triggers`
|
|
19161
19384
|
);
|
|
19162
|
-
return
|
|
19385
|
+
return value2.map((item, index) => {
|
|
19163
19386
|
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
19164
19387
|
throw new Error(`trigger[${index}] must be an object`);
|
|
19165
19388
|
const record4 = item;
|
|
@@ -19314,7 +19537,7 @@ var get3 = new Command("get").description("Get data layer triggers").requiredOpt
|
|
|
19314
19537
|
var set2 = new Command("set").requiredOption("--file <json>", "JSON trigger array").requiredOption("--shop <domain-or-id>", "Shop domain or Apex shop ID").action(async function(opts) {
|
|
19315
19538
|
let triggers;
|
|
19316
19539
|
try {
|
|
19317
|
-
triggers = strictTriggers(JSON.parse(
|
|
19540
|
+
triggers = strictTriggers(JSON.parse(import_node_fs19.default.readFileSync(import_node_path16.default.resolve(opts.file), "utf8")));
|
|
19318
19541
|
} catch (error) {
|
|
19319
19542
|
fail(
|
|
19320
19543
|
this,
|
|
@@ -19341,7 +19564,7 @@ var propose = new Command("propose").requiredOption("--from-file <u2-report.json
|
|
|
19341
19564
|
let proposals;
|
|
19342
19565
|
let report;
|
|
19343
19566
|
try {
|
|
19344
|
-
report = JSON.parse(
|
|
19567
|
+
report = JSON.parse(import_node_fs19.default.readFileSync(import_node_path16.default.resolve(opts.fromFile), "utf8"));
|
|
19345
19568
|
proposals = proposeTriggers(report);
|
|
19346
19569
|
} catch (error) {
|
|
19347
19570
|
fail(this, error instanceof Error ? error.message : String(error), EXIT_CODES.validation);
|
|
@@ -19369,28 +19592,28 @@ var propose = new Command("propose").requiredOption("--from-file <u2-report.json
|
|
|
19369
19592
|
`);
|
|
19370
19593
|
});
|
|
19371
19594
|
});
|
|
19372
|
-
function
|
|
19373
|
-
return [...previous,
|
|
19595
|
+
function collect2(value2, previous) {
|
|
19596
|
+
return [...previous, value2];
|
|
19374
19597
|
}
|
|
19375
|
-
function parseParamValue(
|
|
19376
|
-
if (!
|
|
19598
|
+
function parseParamValue(value2) {
|
|
19599
|
+
if (!value2.startsWith("[") && !value2.startsWith("{")) return value2;
|
|
19377
19600
|
try {
|
|
19378
|
-
return JSON.parse(
|
|
19601
|
+
return JSON.parse(value2);
|
|
19379
19602
|
} catch {
|
|
19380
|
-
return
|
|
19603
|
+
return value2;
|
|
19381
19604
|
}
|
|
19382
19605
|
}
|
|
19383
|
-
var recipe = new Command("apply-recipe").argument("<recipeId>").requiredOption("--shop <domain-or-id>", "Shop domain or Apex shop ID").option("--param <k=v>", "Recipe parameter",
|
|
19606
|
+
var recipe = new Command("apply-recipe").argument("<recipeId>").requiredOption("--shop <domain-or-id>", "Shop domain or Apex shop ID").option("--param <k=v>", "Recipe parameter", collect2, []).action(async function(recipeId, opts) {
|
|
19384
19607
|
const params = Object.fromEntries(
|
|
19385
|
-
opts.param.map((
|
|
19386
|
-
const i =
|
|
19608
|
+
opts.param.map((pair2) => {
|
|
19609
|
+
const i = pair2.indexOf("=");
|
|
19387
19610
|
if (i < 1)
|
|
19388
19611
|
fail(
|
|
19389
19612
|
this,
|
|
19390
|
-
`TRIGGERS_CONFIG_ABSENT: invalid --param ${
|
|
19613
|
+
`TRIGGERS_CONFIG_ABSENT: invalid --param ${pair2}; expected k=v`,
|
|
19391
19614
|
EXIT_CODES.validation
|
|
19392
19615
|
);
|
|
19393
|
-
return [
|
|
19616
|
+
return [pair2.slice(0, i), parseParamValue(pair2.slice(i + 1))];
|
|
19394
19617
|
})
|
|
19395
19618
|
);
|
|
19396
19619
|
const identity2 = await identify(this, opts.shop);
|
|
@@ -19417,7 +19640,7 @@ var recipe = new Command("apply-recipe").argument("<recipeId>").requiredOption("
|
|
|
19417
19640
|
writeWarnings(result);
|
|
19418
19641
|
});
|
|
19419
19642
|
});
|
|
19420
|
-
var enable = new Command("enable-capture").requiredOption("--hours <n>").requiredOption("--shop <domain-or-id>", "Shop domain or Apex shop ID").option("--url-pattern <p>", "URL pattern",
|
|
19643
|
+
var enable = new Command("enable-capture").requiredOption("--hours <n>").requiredOption("--shop <domain-or-id>", "Shop domain or Apex shop ID").option("--url-pattern <p>", "URL pattern", collect2, []).action(async function(opts) {
|
|
19421
19644
|
const hours = Number(opts.hours);
|
|
19422
19645
|
if (!Number.isFinite(hours) || hours <= 0 || hours > 48)
|
|
19423
19646
|
fail(
|
|
@@ -19461,11 +19684,11 @@ var triggersCommand = new Command("triggers").description("Manage runtime data l
|
|
|
19461
19684
|
|
|
19462
19685
|
// src/commands/domains.ts
|
|
19463
19686
|
init_source();
|
|
19464
|
-
function normalizeDomain(
|
|
19465
|
-
return
|
|
19687
|
+
function normalizeDomain(value2) {
|
|
19688
|
+
return value2.trim().replace(/^https?:\/\//i, "").replace(/[/?#].*$/, "").replace(/\.$/, "").toLowerCase();
|
|
19466
19689
|
}
|
|
19467
|
-
function landingHost(
|
|
19468
|
-
const trimmed =
|
|
19690
|
+
function landingHost(value2) {
|
|
19691
|
+
const trimmed = value2.trim();
|
|
19469
19692
|
try {
|
|
19470
19693
|
const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
19471
19694
|
return new URL(withScheme).hostname.toLowerCase().replace(/\.$/, "") || normalizeDomain(trimmed);
|
|
@@ -19643,8 +19866,8 @@ var register = new Command("register").description("Register a new domain on the
|
|
|
19643
19866
|
`apex domains register ${host} --years ${years} --confirm-price "${quote.total} ${quote.currency}"`
|
|
19644
19867
|
);
|
|
19645
19868
|
}
|
|
19646
|
-
const
|
|
19647
|
-
const rl =
|
|
19869
|
+
const readline4 = await import("node:readline");
|
|
19870
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
19648
19871
|
console.error(describeQuote(quote));
|
|
19649
19872
|
const answer = await new Promise(
|
|
19650
19873
|
(resolve2) => rl.question(
|
|
@@ -19731,9 +19954,9 @@ var domainsCommand = new Command("domains").description("Manage install domains
|
|
|
19731
19954
|
|
|
19732
19955
|
// src/commands/handover.ts
|
|
19733
19956
|
init_source();
|
|
19734
|
-
function normalizeDomain2(
|
|
19957
|
+
function normalizeDomain2(value2) {
|
|
19735
19958
|
try {
|
|
19736
|
-
const candidate =
|
|
19959
|
+
const candidate = value2.trim().toLowerCase();
|
|
19737
19960
|
const parsed = new URL(
|
|
19738
19961
|
/^[a-z][a-z0-9+.-]*:\/\//.test(candidate) ? candidate : `http://${candidate}`
|
|
19739
19962
|
);
|
|
@@ -19756,8 +19979,8 @@ var NAMED_HTML_ENTITIES = {
|
|
|
19756
19979
|
apos: "'",
|
|
19757
19980
|
nbsp: "\xA0"
|
|
19758
19981
|
};
|
|
19759
|
-
function decodeHtmlEntities(
|
|
19760
|
-
return
|
|
19982
|
+
function decodeHtmlEntities(value2) {
|
|
19983
|
+
return value2.replace(/&(#[0-9]+|#[xX][0-9a-fA-F]+|[a-zA-Z]+);/g, (match2, entity2) => {
|
|
19761
19984
|
if (entity2.startsWith("#")) {
|
|
19762
19985
|
const hex = entity2[1] === "x" || entity2[1] === "X";
|
|
19763
19986
|
const code = Number.parseInt(hex ? entity2.slice(2) : entity2.slice(1), hex ? 16 : 10);
|
|
@@ -19917,9 +20140,9 @@ var qa2 = new Command("qa").description("Check static link/form handover paramet
|
|
|
19917
20140
|
var handoverCommand = new Command("handover").description("Manage cross-domain identity handover").addCommand(get4).addCommand(set4).addCommand(off2).addCommand(qa2);
|
|
19918
20141
|
|
|
19919
20142
|
// src/commands/order-journey.ts
|
|
19920
|
-
function instant(
|
|
20143
|
+
function instant(value2) {
|
|
19921
20144
|
const m = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|[+-]\d{2}:\d{2})$/.exec(
|
|
19922
|
-
|
|
20145
|
+
value2
|
|
19923
20146
|
);
|
|
19924
20147
|
if (!m) return null;
|
|
19925
20148
|
const year = Number(m[1]), month = Number(m[2]), day = Number(m[3]);
|
|
@@ -20223,22 +20446,22 @@ var CAVEAT = "Labeled estimate only: fail-closed consent tracking makes decliner
|
|
|
20223
20446
|
var PRODUCTION_WORKER_BASE_URL = "https://events.drip-apex.com";
|
|
20224
20447
|
var PRODUCTION_ENVIRONMENT_KEY = "production";
|
|
20225
20448
|
var VISITOR_SERIES_DAYS = 60;
|
|
20226
|
-
function hostOnly(
|
|
20227
|
-
if (!
|
|
20449
|
+
function hostOnly(value2) {
|
|
20450
|
+
if (!value2) return null;
|
|
20228
20451
|
try {
|
|
20229
|
-
return new URL(
|
|
20452
|
+
return new URL(value2.includes("://") ? value2 : `https://${value2}`).hostname.toLowerCase();
|
|
20230
20453
|
} catch {
|
|
20231
|
-
return
|
|
20454
|
+
return value2.toLowerCase().replace(/^https?:\/\//, "").split("/")[0] || null;
|
|
20232
20455
|
}
|
|
20233
20456
|
}
|
|
20234
20457
|
function configuredHosts(domains, envs) {
|
|
20235
20458
|
const set7 = /* @__PURE__ */ new Set();
|
|
20236
|
-
for (const
|
|
20459
|
+
for (const value2 of [
|
|
20237
20460
|
domains.domain,
|
|
20238
20461
|
...domains.additionalDomains ?? [],
|
|
20239
20462
|
...domains.storeOrigins ?? []
|
|
20240
20463
|
]) {
|
|
20241
|
-
const host = hostOnly(
|
|
20464
|
+
const host = hostOnly(value2);
|
|
20242
20465
|
if (host) set7.add(host);
|
|
20243
20466
|
}
|
|
20244
20467
|
for (const env2 of envs?.environments.items ?? [])
|
|
@@ -20339,8 +20562,8 @@ var PURCHASE_CADENCE_WINDOW_MINUTES = PURCHASE_WINDOW_MINUTES * 4;
|
|
|
20339
20562
|
var MIN_CAPTURE_WINDOW_MINUTES = 60;
|
|
20340
20563
|
var DUPLICATE_RATE_THRESHOLD = 0.02;
|
|
20341
20564
|
var MAGNITUDE_TOLERANCE_RATE = 0.1;
|
|
20342
|
-
function record3(
|
|
20343
|
-
return
|
|
20565
|
+
function record3(value2) {
|
|
20566
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
20344
20567
|
}
|
|
20345
20568
|
function purchasePlane(config) {
|
|
20346
20569
|
if (!config) return { present: false, names: [] };
|
|
@@ -20355,13 +20578,13 @@ function purchasePlane(config) {
|
|
|
20355
20578
|
return { present: names.length > 0, names };
|
|
20356
20579
|
}
|
|
20357
20580
|
function publicationTime(config) {
|
|
20358
|
-
for (const
|
|
20581
|
+
for (const value2 of [
|
|
20359
20582
|
config?.generated_at,
|
|
20360
20583
|
config?.publicationTimestamp,
|
|
20361
20584
|
config?.publishedAt,
|
|
20362
20585
|
config?.updatedAt
|
|
20363
20586
|
]) {
|
|
20364
|
-
if (typeof
|
|
20587
|
+
if (typeof value2 === "string" && Number.isFinite(Date.parse(value2))) return Date.parse(value2);
|
|
20365
20588
|
}
|
|
20366
20589
|
return null;
|
|
20367
20590
|
}
|
|
@@ -20382,14 +20605,14 @@ function eventTime(event) {
|
|
|
20382
20605
|
const raw = event.timestamp;
|
|
20383
20606
|
return typeof raw === "string" && Number.isFinite(Date.parse(raw)) ? Date.parse(raw) : null;
|
|
20384
20607
|
}
|
|
20385
|
-
function numeric(
|
|
20386
|
-
const parsed = typeof
|
|
20608
|
+
function numeric(value2) {
|
|
20609
|
+
const parsed = typeof value2 === "number" ? value2 : typeof value2 === "string" && value2.trim() !== "" ? Number(value2) : NaN;
|
|
20387
20610
|
return Number.isFinite(parsed) ? parsed : null;
|
|
20388
20611
|
}
|
|
20389
|
-
function lineItemSum(
|
|
20390
|
-
if (!Array.isArray(
|
|
20612
|
+
function lineItemSum(value2) {
|
|
20613
|
+
if (!Array.isArray(value2)) return null;
|
|
20391
20614
|
let sum = 0;
|
|
20392
|
-
for (const item of
|
|
20615
|
+
for (const item of value2) {
|
|
20393
20616
|
const row = record3(item);
|
|
20394
20617
|
const price = numeric(row?.price);
|
|
20395
20618
|
if (price === null) return null;
|
|
@@ -20592,8 +20815,8 @@ async function fetchServedConfig(workerBase, shopId) {
|
|
|
20592
20815
|
}
|
|
20593
20816
|
function originHosts(values) {
|
|
20594
20817
|
const set7 = /* @__PURE__ */ new Set();
|
|
20595
|
-
for (const
|
|
20596
|
-
const host = hostOnly(
|
|
20818
|
+
for (const value2 of values) {
|
|
20819
|
+
const host = hostOnly(value2);
|
|
20597
20820
|
if (host) set7.add(host);
|
|
20598
20821
|
}
|
|
20599
20822
|
return [...set7].sort();
|
|
@@ -20970,15 +21193,15 @@ function withCaveat(check, caveat) {
|
|
|
20970
21193
|
return caveat.length ? { ...check, evidence: [...check.evidence, ...caveat] } : check;
|
|
20971
21194
|
}
|
|
20972
21195
|
var DAY_MS = 864e5;
|
|
20973
|
-
function parseDay(
|
|
20974
|
-
const text2 =
|
|
21196
|
+
function parseDay(value2) {
|
|
21197
|
+
const text2 = value2?.trim();
|
|
20975
21198
|
if (!text2 || !/^\d{4}-\d{2}-\d{2}$/.test(text2)) return null;
|
|
20976
21199
|
const parsed = Date.parse(`${text2}T00:00:00.000Z`);
|
|
20977
21200
|
if (Number.isNaN(parsed)) return null;
|
|
20978
21201
|
return toDay(parsed) === text2 ? parsed : null;
|
|
20979
21202
|
}
|
|
20980
|
-
function toDay(
|
|
20981
|
-
return new Date(
|
|
21203
|
+
function toDay(value2) {
|
|
21204
|
+
return new Date(value2).toISOString().slice(0, 10);
|
|
20982
21205
|
}
|
|
20983
21206
|
function windowDays(from, to) {
|
|
20984
21207
|
return to < from ? 0 : Math.round((to - from) / DAY_MS) + 1;
|
|
@@ -21085,18 +21308,18 @@ ${CAVEAT}`
|
|
|
21085
21308
|
});
|
|
21086
21309
|
|
|
21087
21310
|
// src/commands/analytics.ts
|
|
21088
|
-
function display(
|
|
21089
|
-
if (
|
|
21090
|
-
if (typeof
|
|
21091
|
-
return String(
|
|
21092
|
-
}
|
|
21093
|
-
function positiveInteger(command,
|
|
21094
|
-
if (
|
|
21095
|
-
const parsed = Number(
|
|
21311
|
+
function display(value2) {
|
|
21312
|
+
if (value2 === null || value2 === void 0) return "\u2014";
|
|
21313
|
+
if (typeof value2 === "object") return JSON.stringify(value2);
|
|
21314
|
+
return String(value2);
|
|
21315
|
+
}
|
|
21316
|
+
function positiveInteger(command, value2, option) {
|
|
21317
|
+
if (value2 === void 0) return void 0;
|
|
21318
|
+
const parsed = Number(value2);
|
|
21096
21319
|
if (!Number.isInteger(parsed) || parsed <= 0)
|
|
21097
21320
|
fail(command, `${option} must be a positive integer`, EXIT_CODES.validation, {
|
|
21098
21321
|
field: option.slice(2),
|
|
21099
|
-
actual:
|
|
21322
|
+
actual: value2
|
|
21100
21323
|
});
|
|
21101
21324
|
return parsed;
|
|
21102
21325
|
}
|
|
@@ -21227,7 +21450,7 @@ Examples:
|
|
|
21227
21450
|
);
|
|
21228
21451
|
|
|
21229
21452
|
// src/commands/install.ts
|
|
21230
|
-
var
|
|
21453
|
+
var import_promises4 = require("node:dns/promises");
|
|
21231
21454
|
var import_node_http2 = require("node:http");
|
|
21232
21455
|
var import_node_https = require("node:https");
|
|
21233
21456
|
var import_node_net = require("node:net");
|
|
@@ -21285,7 +21508,7 @@ var testResolver;
|
|
|
21285
21508
|
var testFetch;
|
|
21286
21509
|
async function resolveHost(hostname) {
|
|
21287
21510
|
const mocked = testResolver?.(hostname) ?? null;
|
|
21288
|
-
const addresses = mocked ?? await (0,
|
|
21511
|
+
const addresses = mocked ?? await (0, import_promises4.lookup)(hostname, { all: true });
|
|
21289
21512
|
return addresses.map((entry) => entry.address);
|
|
21290
21513
|
}
|
|
21291
21514
|
async function validateUrl(raw, allowedHosts) {
|
|
@@ -21334,8 +21557,8 @@ function decoderFor(encoding) {
|
|
|
21334
21557
|
return (0, import_node_zlib.createBrotliDecompress)();
|
|
21335
21558
|
}
|
|
21336
21559
|
function normalizeEncoding(header) {
|
|
21337
|
-
const
|
|
21338
|
-
return !
|
|
21560
|
+
const value2 = (header ?? "").trim().toLowerCase();
|
|
21561
|
+
return !value2 || value2 === "identity" ? null : value2;
|
|
21339
21562
|
}
|
|
21340
21563
|
function decodeBody(raw, header, limits, hostname, inputTruncated = false) {
|
|
21341
21564
|
const encoding = normalizeEncoding(header);
|
|
@@ -21398,9 +21621,9 @@ function overLimitMessage(hostname, maxBytes) {
|
|
|
21398
21621
|
function responseFromIncoming(res, body5, decoded) {
|
|
21399
21622
|
const status4 = res.statusCode ?? 0;
|
|
21400
21623
|
const headers = new Headers();
|
|
21401
|
-
for (const [key,
|
|
21402
|
-
if (Array.isArray(
|
|
21403
|
-
else if (typeof
|
|
21624
|
+
for (const [key, value2] of Object.entries(res.headers)) {
|
|
21625
|
+
if (Array.isArray(value2)) for (const entry of value2) headers.append(key, entry);
|
|
21626
|
+
else if (typeof value2 === "string") headers.set(key, value2);
|
|
21404
21627
|
}
|
|
21405
21628
|
if (decoded) {
|
|
21406
21629
|
headers.delete("content-encoding");
|
|
@@ -21651,11 +21874,11 @@ function buildConfigUrl(workerBaseUrl, shopId, environmentKey) {
|
|
|
21651
21874
|
if (normalized && normalized !== "production") url.searchParams.set("env", normalized);
|
|
21652
21875
|
return url.toString();
|
|
21653
21876
|
}
|
|
21654
|
-
function readNumber(
|
|
21655
|
-
return typeof
|
|
21877
|
+
function readNumber(value2) {
|
|
21878
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : null;
|
|
21656
21879
|
}
|
|
21657
|
-
function readString(
|
|
21658
|
-
return typeof
|
|
21880
|
+
function readString(value2) {
|
|
21881
|
+
return typeof value2 === "string" && value2.trim() ? value2 : null;
|
|
21659
21882
|
}
|
|
21660
21883
|
function isRecognizedConfig(config) {
|
|
21661
21884
|
const hasRevision = readNumber(config.publicationRevision) !== null || readNumber(config.publication_revision) !== null;
|
|
@@ -21927,7 +22150,7 @@ var installCommand = new Command("install").description("Check Apex storefront i
|
|
|
21927
22150
|
"trackRevenue.enabled",
|
|
21928
22151
|
servedConfig.revenueTriggerEnabled === null ? "unknown" : servedConfig.revenueTriggerEnabled ? "yes" : "no"
|
|
21929
22152
|
]
|
|
21930
|
-
].map(([field,
|
|
22153
|
+
].map(([field, value2]) => [String(field), String(value2)])
|
|
21931
22154
|
);
|
|
21932
22155
|
if (warnings.length)
|
|
21933
22156
|
printTable(
|
|
@@ -21961,15 +22184,15 @@ var installCommand = new Command("install").description("Check Apex storefront i
|
|
|
21961
22184
|
|
|
21962
22185
|
// src/commands/flags.ts
|
|
21963
22186
|
init_source();
|
|
21964
|
-
var
|
|
21965
|
-
var
|
|
22187
|
+
var import_node_fs20 = __toESM(require("node:fs"));
|
|
22188
|
+
var import_node_path17 = __toESM(require("node:path"));
|
|
21966
22189
|
|
|
21967
22190
|
// src/edge-status.ts
|
|
21968
22191
|
function getEdgeDeliveryStatus(deliveryType, expectedWorstCaseSeconds = 360) {
|
|
21969
22192
|
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 };
|
|
21970
22193
|
}
|
|
21971
|
-
function parsePublicationMetadata(
|
|
21972
|
-
const record4 =
|
|
22194
|
+
function parsePublicationMetadata(value2) {
|
|
22195
|
+
const record4 = value2 && typeof value2 === "object" ? value2 : {};
|
|
21973
22196
|
return {
|
|
21974
22197
|
publication_revision: Number.isSafeInteger(record4.publication_revision) && record4.publication_revision >= 0 ? record4.publication_revision : null,
|
|
21975
22198
|
generated_at: typeof record4.generated_at === "string" && !Number.isNaN(Date.parse(record4.generated_at)) ? record4.generated_at : null
|
|
@@ -22000,11 +22223,11 @@ function formatEdgePropagationStatus(status4) {
|
|
|
22000
22223
|
|
|
22001
22224
|
// src/commands/flags.ts
|
|
22002
22225
|
var kind = "flags";
|
|
22003
|
-
function body(command,
|
|
22226
|
+
function body(command, value2, opts) {
|
|
22004
22227
|
let parsed = {};
|
|
22005
|
-
if (
|
|
22006
|
-
const source =
|
|
22007
|
-
const text2 =
|
|
22228
|
+
if (value2) {
|
|
22229
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
22230
|
+
const text2 = value2.startsWith("@") || import_node_fs20.default.existsSync(source) ? import_node_fs20.default.readFileSync(import_node_path17.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
22008
22231
|
try {
|
|
22009
22232
|
parsed = JSON.parse(text2);
|
|
22010
22233
|
} catch (e) {
|
|
@@ -22106,8 +22329,8 @@ function write(name) {
|
|
|
22106
22329
|
c.action(async function(...args) {
|
|
22107
22330
|
const o = this.opts();
|
|
22108
22331
|
const id = name === "update" ? String(args[0]) : void 0;
|
|
22109
|
-
const
|
|
22110
|
-
const b = body(this,
|
|
22332
|
+
const value2 = o.file ? `@${o.file}` : String(args[name === "update" ? 1 : 0] ?? "") || void 0;
|
|
22333
|
+
const b = body(this, value2, o);
|
|
22111
22334
|
if (name === "update" && !Object.keys(b).length)
|
|
22112
22335
|
fail(this, "Provide at least one field to update.", EXIT_CODES.validation);
|
|
22113
22336
|
const r = name === "create" ? await createManagedDelivery(requireCredentials(), kind, b) : await updateManagedDelivery(requireCredentials(), kind, id, b);
|
|
@@ -22137,16 +22360,16 @@ Examples:
|
|
|
22137
22360
|
);
|
|
22138
22361
|
|
|
22139
22362
|
// src/commands/backlog.ts
|
|
22140
|
-
var
|
|
22141
|
-
var
|
|
22363
|
+
var import_node_fs21 = __toESM(require("node:fs"));
|
|
22364
|
+
var import_node_path18 = __toESM(require("node:path"));
|
|
22142
22365
|
init_source();
|
|
22143
22366
|
var kind2 = "backlog";
|
|
22144
22367
|
var singular = "backlog item";
|
|
22145
|
-
function parse(command,
|
|
22146
|
-
if (!
|
|
22368
|
+
function parse(command, value2) {
|
|
22369
|
+
if (!value2) return {};
|
|
22147
22370
|
try {
|
|
22148
|
-
const source =
|
|
22149
|
-
const text2 =
|
|
22371
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
22372
|
+
const text2 = value2.startsWith("@") || import_node_fs21.default.existsSync(source) ? import_node_fs21.default.readFileSync(import_node_path18.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
22150
22373
|
const body5 = JSON.parse(text2);
|
|
22151
22374
|
if (!body5 || typeof body5 !== "object" || Array.isArray(body5))
|
|
22152
22375
|
throw new Error("body must be an object");
|
|
@@ -22159,11 +22382,11 @@ function parse(command, value) {
|
|
|
22159
22382
|
);
|
|
22160
22383
|
}
|
|
22161
22384
|
}
|
|
22162
|
-
function
|
|
22163
|
-
return [...previous,
|
|
22385
|
+
function collect3(value2, previous) {
|
|
22386
|
+
return [...previous, value2];
|
|
22164
22387
|
}
|
|
22165
|
-
function customFieldsRecord(
|
|
22166
|
-
return
|
|
22388
|
+
function customFieldsRecord(value2) {
|
|
22389
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : {};
|
|
22167
22390
|
}
|
|
22168
22391
|
function typedFieldValue(definition, raw) {
|
|
22169
22392
|
if (raw === "null") return null;
|
|
@@ -22185,11 +22408,11 @@ function typedFieldValue(definition, raw) {
|
|
|
22185
22408
|
}
|
|
22186
22409
|
async function customFieldsFromPairs(command, pairs) {
|
|
22187
22410
|
if (pairs.length === 0) return void 0;
|
|
22188
|
-
const parsedPairs = pairs.map((
|
|
22189
|
-
const separator =
|
|
22411
|
+
const parsedPairs = pairs.map((pair2) => {
|
|
22412
|
+
const separator = pair2.indexOf("=");
|
|
22190
22413
|
if (separator <= 0)
|
|
22191
|
-
fail(command, `Invalid --field "${
|
|
22192
|
-
return { key:
|
|
22414
|
+
fail(command, `Invalid --field "${pair2}": use key=value.`, EXIT_CODES.validation);
|
|
22415
|
+
return { key: pair2.slice(0, separator), raw: pair2.slice(separator + 1) };
|
|
22193
22416
|
});
|
|
22194
22417
|
const fields3 = await listBacklogFields(requireCredentials());
|
|
22195
22418
|
if (!fields3.ok || !fields3.data) {
|
|
@@ -22213,8 +22436,8 @@ function detail2(x, labels) {
|
|
|
22213
22436
|
const custom = customFieldsRecord(x.custom_fields);
|
|
22214
22437
|
if (Object.keys(custom).length > 0) {
|
|
22215
22438
|
console.log();
|
|
22216
|
-
for (const [key,
|
|
22217
|
-
console.log(` ${labels.get(key) ?? key}: ${
|
|
22439
|
+
for (const [key, value2] of Object.entries(custom)) {
|
|
22440
|
+
console.log(` ${labels.get(key) ?? key}: ${value2 === null ? "-" : String(value2)}`);
|
|
22218
22441
|
}
|
|
22219
22442
|
}
|
|
22220
22443
|
console.log();
|
|
@@ -22266,7 +22489,7 @@ function write2(action78) {
|
|
|
22266
22489
|
c.argument("[json]", "Inline JSON, @file, or file path").option("--file <path>", "JSON body file").option(
|
|
22267
22490
|
"--field <key=value>",
|
|
22268
22491
|
"Set one of the shop's own fields; repeatable. Use key=null to clear it.",
|
|
22269
|
-
|
|
22492
|
+
collect3,
|
|
22270
22493
|
[]
|
|
22271
22494
|
);
|
|
22272
22495
|
c.action(async function(...args) {
|
|
@@ -22312,8 +22535,8 @@ var remove = new Command("delete").description("Delete a backlog item").argument
|
|
|
22312
22535
|
"Deleting a backlog item requires confirmation in non-TTY mode.",
|
|
22313
22536
|
`apex backlog delete ${id} --force`
|
|
22314
22537
|
);
|
|
22315
|
-
const
|
|
22316
|
-
const rl =
|
|
22538
|
+
const readline4 = await import("node:readline");
|
|
22539
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
22317
22540
|
const answer = await new Promise(
|
|
22318
22541
|
(resolve2) => rl.question(source_default.yellow(`Delete backlog item ${id}? [y/N] `), resolve2)
|
|
22319
22542
|
);
|
|
@@ -22340,12 +22563,12 @@ function fieldDetail(field) {
|
|
|
22340
22563
|
if (field.archived_at) console.log(` Archived: ${field.archived_at}`);
|
|
22341
22564
|
console.log();
|
|
22342
22565
|
}
|
|
22343
|
-
function boolOption(command, flag,
|
|
22344
|
-
if (
|
|
22345
|
-
const trimmed =
|
|
22566
|
+
function boolOption(command, flag, value2) {
|
|
22567
|
+
if (value2 === void 0) return void 0;
|
|
22568
|
+
const trimmed = value2.trim().toLowerCase();
|
|
22346
22569
|
if (["true", "yes", "y", "1"].includes(trimmed)) return true;
|
|
22347
22570
|
if (["false", "no", "n", "0"].includes(trimmed)) return false;
|
|
22348
|
-
fail(command, `Invalid ${flag} "${
|
|
22571
|
+
fail(command, `Invalid ${flag} "${value2}": use true or false.`, EXIT_CODES.validation);
|
|
22349
22572
|
}
|
|
22350
22573
|
var fieldsList = new Command("list").alias("ls").description("List the shop's idea fields").option("--include-archived", "Include archived fields").action(async function(o) {
|
|
22351
22574
|
const r = await listBacklogFields(requireCredentials(), o.includeArchived);
|
|
@@ -22373,7 +22596,7 @@ var fieldsCreate = new Command("create").description("Add an idea field").requir
|
|
|
22373
22596
|
).option("--key <key>", "Field key; derived from the label when omitted").option(
|
|
22374
22597
|
"--option <value>",
|
|
22375
22598
|
"A choice for a single_choice field; repeatable",
|
|
22376
|
-
|
|
22599
|
+
collect3,
|
|
22377
22600
|
[]
|
|
22378
22601
|
).option("--required <true|false>", "Every idea must carry a value").option("--client-visible <true|false>", "Share the value with the client").action(async function(o) {
|
|
22379
22602
|
const required = boolOption(this, "--required", o.required);
|
|
@@ -22393,7 +22616,7 @@ var fieldsCreate = new Command("create").description("Add an idea field").requir
|
|
|
22393
22616
|
var fieldsUpdate = new Command("update").description("Update an idea field").argument("<id>", "field ID").option("--label <text>", "What the field is called").option(
|
|
22394
22617
|
"--option <value>",
|
|
22395
22618
|
"Replace the choices of a single_choice field; repeatable",
|
|
22396
|
-
|
|
22619
|
+
collect3,
|
|
22397
22620
|
[]
|
|
22398
22621
|
).option("--required <true|false>", "Every idea must carry a value").option("--client-visible <true|false>", "Share the value with the client").option("--archived <true|false>", "Archive or restore the field").action(async function(id, o) {
|
|
22399
22622
|
const required = boolOption(this, "--required", o.required);
|
|
@@ -22423,16 +22646,16 @@ var fields2 = new Command("fields").description("Manage the shop's own idea fiel
|
|
|
22423
22646
|
var backlogCommand = new Command("backlog").description("Manage backlog").addCommand(list7).addCommand(get6).addCommand(write2("create")).addCommand(write2("update")).addCommand(archive).addCommand(restore).addCommand(remove).addCommand(fields2);
|
|
22424
22647
|
|
|
22425
22648
|
// src/commands/signals.ts
|
|
22426
|
-
var
|
|
22427
|
-
var
|
|
22649
|
+
var import_node_fs22 = __toESM(require("node:fs"));
|
|
22650
|
+
var import_node_path19 = __toESM(require("node:path"));
|
|
22428
22651
|
init_source();
|
|
22429
22652
|
var kind3 = "signals";
|
|
22430
22653
|
var singular2 = "signal";
|
|
22431
|
-
function parse2(command,
|
|
22432
|
-
if (!
|
|
22654
|
+
function parse2(command, value2) {
|
|
22655
|
+
if (!value2) return {};
|
|
22433
22656
|
try {
|
|
22434
|
-
const source =
|
|
22435
|
-
const text2 =
|
|
22657
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
22658
|
+
const text2 = value2.startsWith("@") || import_node_fs22.default.existsSync(source) ? import_node_fs22.default.readFileSync(import_node_path19.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
22436
22659
|
const body5 = JSON.parse(text2);
|
|
22437
22660
|
if (!body5 || typeof body5 !== "object" || Array.isArray(body5))
|
|
22438
22661
|
throw new Error("body must be an object");
|
|
@@ -22514,14 +22737,14 @@ var signalsCommand = new Command("signals").description("Manage signals").addCom
|
|
|
22514
22737
|
|
|
22515
22738
|
// src/commands/personalizations.ts
|
|
22516
22739
|
init_source();
|
|
22517
|
-
var
|
|
22518
|
-
var
|
|
22740
|
+
var import_node_fs23 = __toESM(require("node:fs"));
|
|
22741
|
+
var import_node_path20 = __toESM(require("node:path"));
|
|
22519
22742
|
var kind4 = "personalizations";
|
|
22520
|
-
function body2(command,
|
|
22743
|
+
function body2(command, value2, opts) {
|
|
22521
22744
|
let parsed = {};
|
|
22522
|
-
if (
|
|
22523
|
-
const source =
|
|
22524
|
-
const text2 =
|
|
22745
|
+
if (value2) {
|
|
22746
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
22747
|
+
const text2 = value2.startsWith("@") || import_node_fs23.default.existsSync(source) ? import_node_fs23.default.readFileSync(import_node_path20.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
22525
22748
|
try {
|
|
22526
22749
|
parsed = JSON.parse(text2);
|
|
22527
22750
|
} catch (e) {
|
|
@@ -22580,8 +22803,8 @@ function write4(name) {
|
|
|
22580
22803
|
c.action(async function(...args) {
|
|
22581
22804
|
const o = this.opts();
|
|
22582
22805
|
const id = name === "update" ? String(args[0]) : void 0;
|
|
22583
|
-
const
|
|
22584
|
-
const b = body2(this,
|
|
22806
|
+
const value2 = o.file ? `@${o.file}` : String(args[name === "update" ? 1 : 0] ?? "") || void 0;
|
|
22807
|
+
const b = body2(this, value2, o);
|
|
22585
22808
|
if (name === "update" && !Object.keys(b).length)
|
|
22586
22809
|
fail(this, "Provide at least one field to update.", EXIT_CODES.validation);
|
|
22587
22810
|
const r = name === "create" ? await createManagedDelivery(requireCredentials(), kind4, b) : await updateManagedDelivery(requireCredentials(), kind4, id, b);
|
|
@@ -22603,8 +22826,8 @@ var personalizationsCommand = new Command("personalizations").description("Manag
|
|
|
22603
22826
|
|
|
22604
22827
|
// src/commands/targeting-resources.ts
|
|
22605
22828
|
init_source();
|
|
22606
|
-
var
|
|
22607
|
-
var
|
|
22829
|
+
var import_node_fs24 = __toESM(require("node:fs"));
|
|
22830
|
+
var import_node_path21 = __toESM(require("node:path"));
|
|
22608
22831
|
|
|
22609
22832
|
// src/generated/exclusion-group-body.schema.json
|
|
22610
22833
|
var exclusion_group_body_schema_default = {
|
|
@@ -22857,11 +23080,11 @@ function exclusionFailureDetails(kind5, action78, status4, details) {
|
|
|
22857
23080
|
]
|
|
22858
23081
|
};
|
|
22859
23082
|
}
|
|
22860
|
-
function body3(command,
|
|
22861
|
-
if (!
|
|
22862
|
-
const source =
|
|
23083
|
+
function body3(command, value2) {
|
|
23084
|
+
if (!value2) return {};
|
|
23085
|
+
const source = value2.startsWith("@") ? value2.slice(1) : value2;
|
|
22863
23086
|
try {
|
|
22864
|
-
const text2 =
|
|
23087
|
+
const text2 = value2.startsWith("@") || import_node_fs24.default.existsSync(source) ? import_node_fs24.default.readFileSync(import_node_path21.default.resolve(process.cwd(), source), "utf8") : value2;
|
|
22865
23088
|
return JSON.parse(text2);
|
|
22866
23089
|
} catch (error) {
|
|
22867
23090
|
fail(
|
|
@@ -22940,8 +23163,8 @@ function targetingResourceCommand(kind5) {
|
|
|
22940
23163
|
).option("--file <path>", "JSON body file").action(async function(...args) {
|
|
22941
23164
|
const opts = this.opts();
|
|
22942
23165
|
const id = action78 === "update" ? String(args[0]) : void 0;
|
|
22943
|
-
const
|
|
22944
|
-
const requestBody = body3(this,
|
|
23166
|
+
const value2 = opts.file ? `@${opts.file}` : String(args[action78 === "update" ? 1 : 0] ?? "") || void 0;
|
|
23167
|
+
const requestBody = body3(this, value2);
|
|
22945
23168
|
if (action78 === "update" && typeof requestBody === "object" && requestBody !== null && !Array.isArray(requestBody) && Object.keys(requestBody).length === 0)
|
|
22946
23169
|
fail(this, `Updating a ${singular3} requires at least one field.`, EXIT_CODES.validation);
|
|
22947
23170
|
const response = await requestTargetingResource(
|
|
@@ -22974,8 +23197,8 @@ function targetingResourceCommand(kind5) {
|
|
|
22974
23197
|
"Deleting an exclusion group requires confirmation in non-TTY mode.",
|
|
22975
23198
|
`apex exclusion-groups delete ${id} --force`
|
|
22976
23199
|
);
|
|
22977
|
-
const
|
|
22978
|
-
const rl =
|
|
23200
|
+
const readline4 = await import("node:readline");
|
|
23201
|
+
const rl = readline4.createInterface({
|
|
22979
23202
|
input: process.stdin,
|
|
22980
23203
|
output: process.stderr
|
|
22981
23204
|
});
|
|
@@ -23001,13 +23224,13 @@ function targetingResourceCommand(kind5) {
|
|
|
23001
23224
|
);
|
|
23002
23225
|
if (kind5 === "exclusion-groups") {
|
|
23003
23226
|
root.addCommand(
|
|
23004
|
-
new Command("replace-members").description("Replace exclusion group members").argument("<id>").argument("<json>", "Request body as inline JSON, @file, or a file path (shape below)").action(async function(id,
|
|
23227
|
+
new Command("replace-members").description("Replace exclusion group members").argument("<id>").argument("<json>", "Request body as inline JSON, @file, or a file path (shape below)").action(async function(id, value2) {
|
|
23005
23228
|
const response = await requestTargetingResource(
|
|
23006
23229
|
requireCredentials(),
|
|
23007
23230
|
"PUT",
|
|
23008
23231
|
kind5,
|
|
23009
23232
|
`${id}/members`,
|
|
23010
|
-
body3(this,
|
|
23233
|
+
body3(this, value2)
|
|
23011
23234
|
);
|
|
23012
23235
|
if (!response.ok || !response.data)
|
|
23013
23236
|
fail(
|
|
@@ -23116,8 +23339,8 @@ var targetingCommand = new Command("targeting").description("Test experiment tar
|
|
|
23116
23339
|
// src/commands/sos.ts
|
|
23117
23340
|
var import_node_crypto8 = require("node:crypto");
|
|
23118
23341
|
init_source();
|
|
23119
|
-
var
|
|
23120
|
-
var
|
|
23342
|
+
var import_node_fs25 = __toESM(require("node:fs"));
|
|
23343
|
+
var import_node_path22 = __toESM(require("node:path"));
|
|
23121
23344
|
var SOS_TYPES = /* @__PURE__ */ new Set([
|
|
23122
23345
|
"full_handover",
|
|
23123
23346
|
"design",
|
|
@@ -23127,10 +23350,10 @@ var SOS_TYPES = /* @__PURE__ */ new Set([
|
|
|
23127
23350
|
"bug",
|
|
23128
23351
|
"help"
|
|
23129
23352
|
]);
|
|
23130
|
-
function readText(
|
|
23131
|
-
if (!
|
|
23132
|
-
if (!
|
|
23133
|
-
return
|
|
23353
|
+
function readText(value2) {
|
|
23354
|
+
if (!value2) return void 0;
|
|
23355
|
+
if (!value2.startsWith("@")) return value2;
|
|
23356
|
+
return import_node_fs25.default.readFileSync(import_node_path22.default.resolve(process.cwd(), value2.slice(1)), "utf8");
|
|
23134
23357
|
}
|
|
23135
23358
|
function printTicket(ticket, reused) {
|
|
23136
23359
|
console.log();
|
|
@@ -23184,12 +23407,12 @@ var create4 = new Command("create").description("Create an Apex SOS ticket").opt
|
|
|
23184
23407
|
};
|
|
23185
23408
|
if (opts.attach.length > 5) fail(this, "Attach no more than 5 files", 3);
|
|
23186
23409
|
const files = opts.attach.map((file) => {
|
|
23187
|
-
const filename =
|
|
23188
|
-
const content_type = mediaTypes[
|
|
23410
|
+
const filename = import_node_path22.default.basename(file);
|
|
23411
|
+
const content_type = mediaTypes[import_node_path22.default.extname(file).toLowerCase()];
|
|
23189
23412
|
if (!content_type) fail(this, "Unsupported attachment type", 3);
|
|
23190
23413
|
let size;
|
|
23191
23414
|
try {
|
|
23192
|
-
size =
|
|
23415
|
+
size = import_node_fs25.default.statSync(file).size;
|
|
23193
23416
|
} catch {
|
|
23194
23417
|
fail(this, `Attachment not found: ${file}`, 3);
|
|
23195
23418
|
}
|
|
@@ -23197,7 +23420,7 @@ var create4 = new Command("create").description("Create an Apex SOS ticket").opt
|
|
|
23197
23420
|
if (size <= 0 || size > cap) fail(this, "Attachment exceeds its size limit or is empty", 3);
|
|
23198
23421
|
let bytes;
|
|
23199
23422
|
try {
|
|
23200
|
-
bytes =
|
|
23423
|
+
bytes = import_node_fs25.default.readFileSync(file);
|
|
23201
23424
|
} catch {
|
|
23202
23425
|
fail(this, `Attachment not found: ${file}`, 3);
|
|
23203
23426
|
}
|
|
@@ -23333,17 +23556,17 @@ var markRead = new Command("mark-read").option("--channel <key>", "Mark one chan
|
|
|
23333
23556
|
var inboxCommand = new Command("inbox").description("Read and send inbox messages").addCommand(list11).addCommand(send2).addCommand(markRead);
|
|
23334
23557
|
|
|
23335
23558
|
// src/commands/shops.ts
|
|
23336
|
-
var
|
|
23337
|
-
var
|
|
23559
|
+
var import_node_fs26 = __toESM(require("node:fs"));
|
|
23560
|
+
var import_node_path23 = __toESM(require("node:path"));
|
|
23338
23561
|
function body4(command, raw) {
|
|
23339
23562
|
if (!raw) return {};
|
|
23340
23563
|
try {
|
|
23341
23564
|
const source = raw.startsWith("@") ? raw.slice(1) : raw;
|
|
23342
|
-
const text2 = raw.startsWith("@") ||
|
|
23343
|
-
const
|
|
23344
|
-
if (!
|
|
23565
|
+
const text2 = raw.startsWith("@") || import_node_fs26.default.existsSync(source) ? import_node_fs26.default.readFileSync(import_node_path23.default.resolve(source), "utf8") : raw;
|
|
23566
|
+
const value2 = JSON.parse(text2);
|
|
23567
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2))
|
|
23345
23568
|
throw new Error("body must be an object");
|
|
23346
|
-
return
|
|
23569
|
+
return value2;
|
|
23347
23570
|
} catch (e) {
|
|
23348
23571
|
fail(
|
|
23349
23572
|
command,
|
|
@@ -23448,15 +23671,15 @@ function settings(name, description, toggle) {
|
|
|
23448
23671
|
}
|
|
23449
23672
|
var profile = new Command("store-profile").description("Read and review a store profile");
|
|
23450
23673
|
function printStoreProfile(data) {
|
|
23451
|
-
const
|
|
23674
|
+
const value2 = data;
|
|
23452
23675
|
console.log(
|
|
23453
|
-
`${
|
|
23676
|
+
`${value2.shop?.name ?? "Store profile"}${value2.shop?.domain ? ` (${value2.shop.domain})` : ""}`
|
|
23454
23677
|
);
|
|
23455
23678
|
console.log(
|
|
23456
|
-
`Audit: ${
|
|
23679
|
+
`Audit: ${value2.latestRun?.status ?? "not run"}; findings: ${value2.findings?.length ?? 0} (${value2.unreviewedCount ?? 0} unreviewed)`
|
|
23457
23680
|
);
|
|
23458
|
-
console.log(`Facts: ${
|
|
23459
|
-
console.log(`Learning run: ${
|
|
23681
|
+
console.log(`Facts: ${value2.facts?.length ?? 0}; open reviews: ${value2.openReviewCount ?? 0}`);
|
|
23682
|
+
console.log(`Learning run: ${value2.latestLearningRun?.status ?? "none"}`);
|
|
23460
23683
|
}
|
|
23461
23684
|
profile.addCommand(
|
|
23462
23685
|
new Command("get").argument("<id>").action(async function(id) {
|
|
@@ -23603,13 +23826,13 @@ function dataJson(source) {
|
|
|
23603
23826
|
error: { code: "malformed_container", message: "GTM container data is not balanced JSON" }
|
|
23604
23827
|
};
|
|
23605
23828
|
}
|
|
23606
|
-
function visit(
|
|
23607
|
-
if (!
|
|
23608
|
-
if (Array.isArray(
|
|
23609
|
-
for (const item of
|
|
23829
|
+
function visit(value2, callback) {
|
|
23830
|
+
if (!value2 || typeof value2 !== "object") return;
|
|
23831
|
+
if (Array.isArray(value2)) {
|
|
23832
|
+
for (const item of value2) visit(item, callback);
|
|
23610
23833
|
return;
|
|
23611
23834
|
}
|
|
23612
|
-
const object =
|
|
23835
|
+
const object = value2;
|
|
23613
23836
|
callback(object);
|
|
23614
23837
|
for (const nested of Object.values(object)) visit(nested, callback);
|
|
23615
23838
|
}
|
|
@@ -23656,13 +23879,13 @@ function parseContainer(source, id, dataLayerName = "dataLayer") {
|
|
|
23656
23879
|
for (const rule of rules) {
|
|
23657
23880
|
if (!Array.isArray(rule)) continue;
|
|
23658
23881
|
const predicateIndexes = rule.flatMap(
|
|
23659
|
-
(part) => Array.isArray(part) && part[0] === "if" ? part.slice(1).filter((
|
|
23882
|
+
(part) => Array.isArray(part) && part[0] === "if" ? part.slice(1).filter((value2) => typeof value2 === "number") : []
|
|
23660
23883
|
);
|
|
23661
23884
|
const predicateText = predicateIndexes.map((index) => JSON.stringify(predicates[index] ?? "")).join(" ");
|
|
23662
23885
|
if (!/consent/i.test(predicateText) || !purchaseRelevantEventNames.some((name) => predicateText.includes(name)))
|
|
23663
23886
|
continue;
|
|
23664
23887
|
const tagIndexes = rule.flatMap(
|
|
23665
|
-
(part) => Array.isArray(part) && part[0] === "add" ? part.slice(1).filter((
|
|
23888
|
+
(part) => Array.isArray(part) && part[0] === "add" ? part.slice(1).filter((value2) => typeof value2 === "number") : []
|
|
23666
23889
|
);
|
|
23667
23890
|
for (const index of tagIndexes) {
|
|
23668
23891
|
const tag = recordObject(tags[index]);
|
|
@@ -23682,12 +23905,12 @@ function parseContainer(source, id, dataLayerName = "dataLayer") {
|
|
|
23682
23905
|
vtpPaths,
|
|
23683
23906
|
ecommerceFrom: [...ecommerce][0] ?? null,
|
|
23684
23907
|
serverContainerUrl: [...serverUrls][0] ?? null,
|
|
23685
|
-
piiPaths: vtpPaths.filter((
|
|
23908
|
+
piiPaths: vtpPaths.filter((path27) => /email|phone|address|name/i.test(path27))
|
|
23686
23909
|
}
|
|
23687
23910
|
};
|
|
23688
23911
|
}
|
|
23689
|
-
function recordObject(
|
|
23690
|
-
return
|
|
23912
|
+
function recordObject(value2) {
|
|
23913
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
23691
23914
|
}
|
|
23692
23915
|
async function mineGtm(input, fetcher = fetch, explicitContainerUrl = false) {
|
|
23693
23916
|
let refs;
|
|
@@ -23732,11 +23955,11 @@ async function mineGtm(input, fetcher = fetch, explicitContainerUrl = false) {
|
|
|
23732
23955
|
}
|
|
23733
23956
|
|
|
23734
23957
|
// src/commands/discover.ts
|
|
23735
|
-
function minutesValue(
|
|
23736
|
-
if (
|
|
23737
|
-
if (!/^\d+$/.test(
|
|
23958
|
+
function minutesValue(value2) {
|
|
23959
|
+
if (value2 === void 0) return void 0;
|
|
23960
|
+
if (!/^\d+$/.test(value2))
|
|
23738
23961
|
throw new CliError("--minutes must be an integer between 1 and 20160", EXIT_CODES.validation);
|
|
23739
|
-
const parsed = Number(
|
|
23962
|
+
const parsed = Number(value2);
|
|
23740
23963
|
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 20160)
|
|
23741
23964
|
throw new CliError("--minutes must be an integer between 1 and 20160", EXIT_CODES.validation);
|
|
23742
23965
|
return parsed;
|
|
@@ -23751,11 +23974,11 @@ function isContainerField(field) {
|
|
|
23751
23974
|
const types = baseFieldTypes(field);
|
|
23752
23975
|
return types.has("obj") || types.has("arr");
|
|
23753
23976
|
}
|
|
23754
|
-
function hasSyntheticPlaceholder(
|
|
23755
|
-
return
|
|
23977
|
+
function hasSyntheticPlaceholder(path27) {
|
|
23978
|
+
return path27.split(".").map((segment) => segment.replace(/\[\]$/, "")).some((segment) => /^<[^>]+>$/.test(segment));
|
|
23756
23979
|
}
|
|
23757
|
-
function ambiguousDottedPrefix(event,
|
|
23758
|
-
const segments =
|
|
23980
|
+
function ambiguousDottedPrefix(event, path27) {
|
|
23981
|
+
const segments = path27.split(".");
|
|
23759
23982
|
for (let index = 1; index < segments.length; index += 1) {
|
|
23760
23983
|
const prefix = segments.slice(0, index).join(".");
|
|
23761
23984
|
const parent = event.fields.find((field) => field.path === prefix);
|
|
@@ -23764,42 +23987,42 @@ function ambiguousDottedPrefix(event, path26) {
|
|
|
23764
23987
|
return void 0;
|
|
23765
23988
|
}
|
|
23766
23989
|
function dimensionEligibility(event, field) {
|
|
23767
|
-
const
|
|
23768
|
-
if (hasSyntheticPlaceholder(
|
|
23990
|
+
const path27 = field.path;
|
|
23991
|
+
if (hasSyntheticPlaceholder(path27)) {
|
|
23769
23992
|
return {
|
|
23770
23993
|
eligible: false,
|
|
23771
|
-
message: `Path ${JSON.stringify(
|
|
23994
|
+
message: `Path ${JSON.stringify(path27)} is a synthetic placeholder and cannot create a dimension. Choose an observed scalar path.`
|
|
23772
23995
|
};
|
|
23773
23996
|
}
|
|
23774
23997
|
if (isContainerField(field)) {
|
|
23775
23998
|
return {
|
|
23776
23999
|
eligible: false,
|
|
23777
|
-
message: `Path ${JSON.stringify(
|
|
24000
|
+
message: `Path ${JSON.stringify(path27)} is container-typed. Choose an observed scalar path.`
|
|
23778
24001
|
};
|
|
23779
24002
|
}
|
|
23780
|
-
if (
|
|
24003
|
+
if (path27.includes("[]")) {
|
|
23781
24004
|
return {
|
|
23782
24005
|
eligible: false,
|
|
23783
|
-
message: `Path ${JSON.stringify(
|
|
24006
|
+
message: `Path ${JSON.stringify(path27)} includes an array-element segment and cannot create a reliable dimension. Choose a scalar path outside an array.`
|
|
23784
24007
|
};
|
|
23785
24008
|
}
|
|
23786
24009
|
if (!isStableField(field)) {
|
|
23787
24010
|
return {
|
|
23788
24011
|
eligible: false,
|
|
23789
|
-
message: `Path ${JSON.stringify(
|
|
24012
|
+
message: `Path ${JSON.stringify(path27)} does not have a stable observed type. Choose a path without a type collision.`
|
|
23790
24013
|
};
|
|
23791
24014
|
}
|
|
23792
24015
|
if (!event.event) {
|
|
23793
24016
|
return {
|
|
23794
24017
|
eligible: false,
|
|
23795
|
-
message: `Path ${JSON.stringify(
|
|
24018
|
+
message: `Path ${JSON.stringify(path27)} has no observed event name. Choose a path from a named event.`
|
|
23796
24019
|
};
|
|
23797
24020
|
}
|
|
23798
|
-
const ambiguousPrefix = ambiguousDottedPrefix(event,
|
|
24021
|
+
const ambiguousPrefix = ambiguousDottedPrefix(event, path27);
|
|
23799
24022
|
if (ambiguousPrefix) {
|
|
23800
24023
|
return {
|
|
23801
24024
|
eligible: false,
|
|
23802
|
-
message: `Path ${JSON.stringify(
|
|
24025
|
+
message: `Path ${JSON.stringify(path27)} could be a literal key containing dots because the discovery report has no observed container at ${JSON.stringify(ambiguousPrefix)}. Apex cannot safely create a capture for it.`
|
|
23803
24026
|
};
|
|
23804
24027
|
}
|
|
23805
24028
|
return { eligible: true };
|
|
@@ -23808,24 +24031,24 @@ function isNumericField(field) {
|
|
|
23808
24031
|
const numericTypes = /* @__PURE__ */ new Set(["num", "numstr", "numstr_comma"]);
|
|
23809
24032
|
return field.types.length > 0 && field.types.every((type) => numericTypes.has(type.split(":")[0]));
|
|
23810
24033
|
}
|
|
23811
|
-
function defaultDimensionLabel(
|
|
23812
|
-
const words =
|
|
23813
|
-
return words ? `${words[0].toUpperCase()}${words.slice(1)}` :
|
|
24034
|
+
function defaultDimensionLabel(path27) {
|
|
24035
|
+
const words = path27.split(/[._-]+/).filter(Boolean).join(" ");
|
|
24036
|
+
return words ? `${words[0].toUpperCase()}${words.slice(1)}` : path27;
|
|
23814
24037
|
}
|
|
23815
|
-
function quoteShellArgument(
|
|
23816
|
-
return "'" +
|
|
24038
|
+
function quoteShellArgument(value2) {
|
|
24039
|
+
return "'" + value2.replaceAll("'", "'\\''") + "'";
|
|
23817
24040
|
}
|
|
23818
|
-
function createDimensionInvocation(
|
|
23819
|
-
return `apex discover --create-dimension ${quoteShellArgument(
|
|
24041
|
+
function createDimensionInvocation(path27, eventName) {
|
|
24042
|
+
return `apex discover --create-dimension ${quoteShellArgument(path27)} --event ${quoteShellArgument(eventName)}`;
|
|
23820
24043
|
}
|
|
23821
|
-
function resolveDimensionObservation(command, report,
|
|
24044
|
+
function resolveDimensionObservation(command, report, path27, eventName) {
|
|
23822
24045
|
const matches = report.data_layer.flatMap(
|
|
23823
|
-
(event) => event.fields.filter((field) => field.path ===
|
|
24046
|
+
(event) => event.fields.filter((field) => field.path === path27).map((field) => ({ event, field }))
|
|
23824
24047
|
);
|
|
23825
24048
|
if (!matches.length) {
|
|
23826
24049
|
fail(
|
|
23827
24050
|
command,
|
|
23828
|
-
`Path ${JSON.stringify(
|
|
24051
|
+
`Path ${JSON.stringify(path27)} was not found in the current discovery report. Run apex discover and copy an observed path exactly.`,
|
|
23829
24052
|
EXIT_CODES.validation
|
|
23830
24053
|
);
|
|
23831
24054
|
}
|
|
@@ -23835,7 +24058,7 @@ function resolveDimensionObservation(command, report, path26, eventName) {
|
|
|
23835
24058
|
if (!eventMatches.length) {
|
|
23836
24059
|
fail(
|
|
23837
24060
|
command,
|
|
23838
|
-
`Path ${JSON.stringify(
|
|
24061
|
+
`Path ${JSON.stringify(path27)} was not observed on event ${JSON.stringify(eventName)}. Run apex discover and copy the event name exactly.`,
|
|
23839
24062
|
EXIT_CODES.validation
|
|
23840
24063
|
);
|
|
23841
24064
|
}
|
|
@@ -23843,7 +24066,7 @@ function resolveDimensionObservation(command, report, path26, eventName) {
|
|
|
23843
24066
|
if (layers.length > 1) {
|
|
23844
24067
|
fail(
|
|
23845
24068
|
command,
|
|
23846
|
-
`Path ${JSON.stringify(
|
|
24069
|
+
`Path ${JSON.stringify(path27)} on event ${JSON.stringify(eventName)} was observed on multiple data layers: ${layers.join(", ")}. Dimensions bind to one layer; this ambiguity cannot be resolved automatically \u2014 capture the value under one layer, or define the dimension in the dashboard with the data layer name set explicitly.`,
|
|
23847
24070
|
EXIT_CODES.validation
|
|
23848
24071
|
);
|
|
23849
24072
|
}
|
|
@@ -23855,7 +24078,7 @@ function resolveDimensionObservation(command, report, path26, eventName) {
|
|
|
23855
24078
|
if (namedEvents.length > 1) {
|
|
23856
24079
|
fail(
|
|
23857
24080
|
command,
|
|
23858
|
-
`Path ${JSON.stringify(
|
|
24081
|
+
`Path ${JSON.stringify(path27)} was observed on multiple events: ${namedEvents.join(", ")}. Retry with --event <name>.`,
|
|
23859
24082
|
EXIT_CODES.validation
|
|
23860
24083
|
);
|
|
23861
24084
|
}
|
|
@@ -23864,7 +24087,7 @@ function resolveDimensionObservation(command, report, path26, eventName) {
|
|
|
23864
24087
|
if (layers.length > 1) {
|
|
23865
24088
|
fail(
|
|
23866
24089
|
command,
|
|
23867
|
-
`Path ${JSON.stringify(
|
|
24090
|
+
`Path ${JSON.stringify(path27)} on event ${JSON.stringify(namedEvents[0] ?? "")} was observed on multiple data layers: ${layers.join(", ")}. Dimensions bind to one layer; this ambiguity cannot be resolved automatically \u2014 capture the value under one layer, or define the dimension in the dashboard with the data layer name set explicitly.`,
|
|
23868
24091
|
EXIT_CODES.validation
|
|
23869
24092
|
);
|
|
23870
24093
|
}
|
|
@@ -23899,9 +24122,9 @@ function renderDiscovery(report) {
|
|
|
23899
24122
|
`
|
|
23900
24123
|
${event.event || "(unnamed event)"} [${event.dlName}] \u2014 ${event.count} observation(s)${event.matched ? " \u2014 matched" : ""}; t_ms p50=${event.t_ms_p50 ?? "n/a"}, p95=${event.t_ms_p95 ?? "n/a"}, pre-init=${event.pre_init_count}`
|
|
23901
24124
|
);
|
|
23902
|
-
for (const
|
|
24125
|
+
for (const path27 of event.paths)
|
|
23903
24126
|
lines.push(
|
|
23904
|
-
` URL ${
|
|
24127
|
+
` URL ${path27.path}: ${path27.pageviews} pageviews, ${path27.count} pushes, ${path27.pspReturn_count} PSP returns`
|
|
23905
24128
|
);
|
|
23906
24129
|
for (const field of event.fields) {
|
|
23907
24130
|
lines.push(
|
|
@@ -23964,7 +24187,7 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
23964
24187
|
let report;
|
|
23965
24188
|
let apiSucceeded = false;
|
|
23966
24189
|
let discoveryCredentials;
|
|
23967
|
-
let
|
|
24190
|
+
let apiFailure3;
|
|
23968
24191
|
try {
|
|
23969
24192
|
discoveryCredentials = requireCredentials();
|
|
23970
24193
|
const result = await discoverTrackingSchema(discoveryCredentials, minutes);
|
|
@@ -23972,24 +24195,24 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
23972
24195
|
report = result.data;
|
|
23973
24196
|
apiSucceeded = true;
|
|
23974
24197
|
} else
|
|
23975
|
-
|
|
24198
|
+
apiFailure3 = {
|
|
23976
24199
|
message: result.error ?? "Discovery API unavailable",
|
|
23977
24200
|
status: result.status,
|
|
23978
24201
|
details: result.errorDetails
|
|
23979
24202
|
};
|
|
23980
24203
|
} catch (error) {
|
|
23981
|
-
|
|
24204
|
+
apiFailure3 = {
|
|
23982
24205
|
message: error instanceof Error ? error.message : String(error),
|
|
23983
24206
|
...error instanceof CliError ? { details: error.details, cliError: error } : {}
|
|
23984
24207
|
};
|
|
23985
24208
|
}
|
|
23986
24209
|
if (!report && (!gtmInput || opts.createDimension)) {
|
|
23987
|
-
if (
|
|
24210
|
+
if (apiFailure3?.cliError) throw apiFailure3.cliError;
|
|
23988
24211
|
fail(
|
|
23989
24212
|
this,
|
|
23990
|
-
|
|
23991
|
-
classifyStatus(
|
|
23992
|
-
|
|
24213
|
+
apiFailure3?.message ?? "Failed to discover tracking schema",
|
|
24214
|
+
classifyStatus(apiFailure3?.status ?? 0),
|
|
24215
|
+
apiFailure3?.details
|
|
23993
24216
|
);
|
|
23994
24217
|
}
|
|
23995
24218
|
report ??= {
|
|
@@ -24004,7 +24227,7 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
24004
24227
|
trigger_diagnoses: [],
|
|
24005
24228
|
storage: [],
|
|
24006
24229
|
notes: [
|
|
24007
|
-
`GTM static analysis completed without discovery API data: ${
|
|
24230
|
+
`GTM static analysis completed without discovery API data: ${apiFailure3?.message ?? "platform credentials were not provided"}`
|
|
24008
24231
|
]
|
|
24009
24232
|
};
|
|
24010
24233
|
if (gtmInput) {
|
|
@@ -24042,9 +24265,9 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
24042
24265
|
if (!apiSucceeded || !discoveryCredentials) {
|
|
24043
24266
|
fail(
|
|
24044
24267
|
this,
|
|
24045
|
-
|
|
24046
|
-
classifyStatus(
|
|
24047
|
-
|
|
24268
|
+
apiFailure3?.message ?? "Discovery API data is required to create a dimension",
|
|
24269
|
+
classifyStatus(apiFailure3?.status ?? 0),
|
|
24270
|
+
apiFailure3?.details
|
|
24048
24271
|
);
|
|
24049
24272
|
}
|
|
24050
24273
|
const observation = resolveDimensionObservation(
|
|
@@ -24114,16 +24337,16 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
24114
24337
|
});
|
|
24115
24338
|
|
|
24116
24339
|
// src/commands/skills.ts
|
|
24117
|
-
var
|
|
24118
|
-
var
|
|
24340
|
+
var import_node_fs27 = __toESM(require("node:fs"));
|
|
24341
|
+
var import_node_path24 = __toESM(require("node:path"));
|
|
24119
24342
|
function packageRoot() {
|
|
24120
24343
|
const candidates = [
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24344
|
+
import_node_path24.default.resolve(__dirname, ".."),
|
|
24345
|
+
import_node_path24.default.resolve(import_node_path24.default.dirname(process.argv[1] ?? process.cwd()), ".."),
|
|
24346
|
+
import_node_path24.default.resolve(process.cwd(), "packages/cli")
|
|
24124
24347
|
];
|
|
24125
24348
|
for (const candidate of candidates) {
|
|
24126
|
-
if (
|
|
24349
|
+
if (import_node_fs27.default.existsSync(import_node_path24.default.join(candidate, "AGENTS.md"))) return candidate;
|
|
24127
24350
|
}
|
|
24128
24351
|
throw new Error(
|
|
24129
24352
|
`Apex CLI package files not found. Looked for AGENTS.md in: ${candidates.join(", ")}`
|
|
@@ -24132,19 +24355,19 @@ function packageRoot() {
|
|
|
24132
24355
|
function skillPaths() {
|
|
24133
24356
|
const root = packageRoot();
|
|
24134
24357
|
return {
|
|
24135
|
-
agents:
|
|
24136
|
-
skill:
|
|
24358
|
+
agents: import_node_path24.default.join(root, "AGENTS.md"),
|
|
24359
|
+
skill: import_node_path24.default.join(root, "skills", "apex-cli", "SKILL.md")
|
|
24137
24360
|
};
|
|
24138
24361
|
}
|
|
24139
24362
|
function installSkill(paths, targetRoot) {
|
|
24140
|
-
const missing = [paths.skill, paths.agents].filter((filePath) => !
|
|
24363
|
+
const missing = [paths.skill, paths.agents].filter((filePath) => !import_node_fs27.default.existsSync(filePath));
|
|
24141
24364
|
if (missing.length > 0) {
|
|
24142
24365
|
throw new Error(`Apex CLI package files not found. Missing: ${missing.join(", ")}`);
|
|
24143
24366
|
}
|
|
24144
|
-
const target =
|
|
24145
|
-
|
|
24146
|
-
|
|
24147
|
-
|
|
24367
|
+
const target = import_node_path24.default.resolve(targetRoot, "apex-cli");
|
|
24368
|
+
import_node_fs27.default.mkdirSync(target, { recursive: true });
|
|
24369
|
+
import_node_fs27.default.copyFileSync(paths.skill, import_node_path24.default.join(target, "SKILL.md"));
|
|
24370
|
+
import_node_fs27.default.copyFileSync(paths.agents, import_node_path24.default.join(target, "AGENTS.md"));
|
|
24148
24371
|
return target;
|
|
24149
24372
|
}
|
|
24150
24373
|
var skillsCommand = new Command("skills").description("Print or install the Apex CLI agent skill files").option("--install", "Copy the Apex CLI skill into ./.claude/skills/apex-cli").option("--target <dir>", "Install target skills directory", ".claude/skills").option("--json", "Print JSON").action(function action71(opts) {
|
|
@@ -24179,9 +24402,9 @@ function validateMoveInput(shopIds, toOrgId) {
|
|
|
24179
24402
|
|
|
24180
24403
|
// src/commands/admin.ts
|
|
24181
24404
|
var uuid2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
24182
|
-
function switchValue(
|
|
24183
|
-
if (
|
|
24184
|
-
if (
|
|
24405
|
+
function switchValue(value2) {
|
|
24406
|
+
if (value2 === "on") return true;
|
|
24407
|
+
if (value2 === "off") return false;
|
|
24185
24408
|
throw new Error("Use on or off");
|
|
24186
24409
|
}
|
|
24187
24410
|
var settingsGet = new Command("settings").description("Show platform operator settings").action(async function() {
|
|
@@ -24250,8 +24473,8 @@ async function confirmArchive(command, shopId, force) {
|
|
|
24250
24473
|
`apex admin shops archive ${JSON.stringify(shopId)} --force`
|
|
24251
24474
|
);
|
|
24252
24475
|
}
|
|
24253
|
-
const
|
|
24254
|
-
const rl =
|
|
24476
|
+
const readline4 = await import("node:readline");
|
|
24477
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
24255
24478
|
const answer = await new Promise((resolve2) => {
|
|
24256
24479
|
rl.question("Archive this shop? Apex delivery will be disabled. [y/N] ", resolve2);
|
|
24257
24480
|
});
|
|
@@ -24292,7 +24515,115 @@ var restore2 = new Command("restore").description("Restore an archived shop").ar
|
|
|
24292
24515
|
() => console.log("Shop restored. Delivery remains controlled by the kill switch.")
|
|
24293
24516
|
);
|
|
24294
24517
|
});
|
|
24295
|
-
|
|
24518
|
+
function settingValueText(value2) {
|
|
24519
|
+
return value2 === null ? "null" : typeof value2 === "object" ? JSON.stringify(value2) : String(value2);
|
|
24520
|
+
}
|
|
24521
|
+
function printShopSettings(settings2) {
|
|
24522
|
+
printTable(
|
|
24523
|
+
["KEY", "VALUE", "OVERRIDE", "GROUP"],
|
|
24524
|
+
settings2.map((entry) => [
|
|
24525
|
+
entry.key,
|
|
24526
|
+
settingValueText(entry.value),
|
|
24527
|
+
settingValueText(entry.override),
|
|
24528
|
+
entry.group
|
|
24529
|
+
])
|
|
24530
|
+
);
|
|
24531
|
+
}
|
|
24532
|
+
async function loadShopSettings(command, shopRef) {
|
|
24533
|
+
const res = await getAdminShopSettings(requireUserCredentials(), shopRef);
|
|
24534
|
+
if (!res.ok || !res.data) {
|
|
24535
|
+
const candidates = res.errorDetails?.candidates;
|
|
24536
|
+
const hint = res.status === 409 && Array.isArray(candidates) ? ` Candidate IDs: ${candidates.join(", ")}. Use --shop <uuid>.` : "";
|
|
24537
|
+
fail(
|
|
24538
|
+
command,
|
|
24539
|
+
`${res.error ?? "Failed to read shop settings"}${hint}`,
|
|
24540
|
+
classifyStatus(res.status),
|
|
24541
|
+
res.errorDetails
|
|
24542
|
+
);
|
|
24543
|
+
}
|
|
24544
|
+
return res.data;
|
|
24545
|
+
}
|
|
24546
|
+
function findShopSetting(command, settings2, key) {
|
|
24547
|
+
const entry = settings2.find((setting) => setting.key === key);
|
|
24548
|
+
if (!entry)
|
|
24549
|
+
fail(
|
|
24550
|
+
command,
|
|
24551
|
+
`Unknown shop setting ${key}. Registry keys: ${settings2.map((setting) => setting.key).join(", ")}`,
|
|
24552
|
+
3
|
|
24553
|
+
);
|
|
24554
|
+
return entry;
|
|
24555
|
+
}
|
|
24556
|
+
var shopSettings = new Command("settings").description(
|
|
24557
|
+
"Read and write registered per-shop settings"
|
|
24558
|
+
);
|
|
24559
|
+
shopSettings.addCommand(
|
|
24560
|
+
new Command("list").description("List every registered shop setting").requiredOption("--shop <uuid-or-domain>").option("--json", "Output JSON").action(async function(opts) {
|
|
24561
|
+
const res = await loadShopSettings(this, opts.shop);
|
|
24562
|
+
output(this, res, () => printShopSettings(res.data.settings));
|
|
24563
|
+
})
|
|
24564
|
+
);
|
|
24565
|
+
shopSettings.addCommand(
|
|
24566
|
+
new Command("get").description("Read one registered shop setting").requiredOption("--shop <uuid-or-domain>").requiredOption("--key <key>").option("--json", "Output JSON").action(async function(opts) {
|
|
24567
|
+
const res = await loadShopSettings(this, opts.shop);
|
|
24568
|
+
const entry = findShopSetting(this, res.data.settings, opts.key);
|
|
24569
|
+
output(this, { data: { ...res.data, settings: [entry] } }, () => printShopSettings([entry]));
|
|
24570
|
+
})
|
|
24571
|
+
);
|
|
24572
|
+
shopSettings.addCommand(
|
|
24573
|
+
new Command("set").description("Write a registered shop setting through the audited admin path").requiredOption("--shop <uuid-or-domain>").requiredOption("--key <key>").requiredOption("--value <value>").option("--reason <text>", "Audit reason").option("--expected-version <v>", "Expected storage version").option("--confirm", "Confirm sensitive setting change").option("--json", "Output JSON").action(async function(opts) {
|
|
24574
|
+
const resolved = (await loadShopSettings(this, opts.shop)).data;
|
|
24575
|
+
const entry = findShopSetting(this, resolved.settings, opts.key);
|
|
24576
|
+
let value2 = opts.value;
|
|
24577
|
+
if (opts.value === "null") value2 = null;
|
|
24578
|
+
else if (entry.value_type === "boolean") {
|
|
24579
|
+
if (["on", "true"].includes(opts.value)) value2 = true;
|
|
24580
|
+
else if (["off", "false"].includes(opts.value)) value2 = false;
|
|
24581
|
+
else fail(this, "Boolean values must be on, off, true or false", 3);
|
|
24582
|
+
} else if (entry.value_type === "number") {
|
|
24583
|
+
if (!opts.value.trim() || !Number.isFinite(Number(opts.value)))
|
|
24584
|
+
fail(this, "Number values must be finite numbers", 3);
|
|
24585
|
+
value2 = Number(opts.value);
|
|
24586
|
+
}
|
|
24587
|
+
if (entry.sensitive && !opts.confirm) {
|
|
24588
|
+
const quote = (text2) => "'" + text2.replaceAll("'", `'"'"'`) + "'";
|
|
24589
|
+
const args = [
|
|
24590
|
+
`--shop ${quote(resolved.shop_id)}`,
|
|
24591
|
+
`--key ${quote(opts.key)}`,
|
|
24592
|
+
`--value ${quote(opts.value)}`
|
|
24593
|
+
];
|
|
24594
|
+
if (opts.reason !== void 0) args.push(`--reason ${quote(opts.reason)}`);
|
|
24595
|
+
if (opts.expectedVersion !== void 0)
|
|
24596
|
+
args.push(`--expected-version ${quote(opts.expectedVersion)}`);
|
|
24597
|
+
if (this.optsWithGlobals().json) args.push("--json");
|
|
24598
|
+
confirmationRequired(
|
|
24599
|
+
this,
|
|
24600
|
+
"--confirm is required because this changes a sensitive shop setting",
|
|
24601
|
+
`apex admin shops settings set ${args.join(" ")} --confirm`
|
|
24602
|
+
);
|
|
24603
|
+
}
|
|
24604
|
+
const res = await setAdminShopSetting(requireUserCredentials(), resolved.shop_id, {
|
|
24605
|
+
key: opts.key,
|
|
24606
|
+
value: value2,
|
|
24607
|
+
...opts.reason !== void 0 ? { reason: opts.reason } : {},
|
|
24608
|
+
...opts.expectedVersion !== void 0 ? { expectedVersion: opts.expectedVersion } : {}
|
|
24609
|
+
});
|
|
24610
|
+
if (!res.ok || !res.data)
|
|
24611
|
+
fail(
|
|
24612
|
+
this,
|
|
24613
|
+
res.error ?? "Failed to write shop setting",
|
|
24614
|
+
classifyStatus(res.status),
|
|
24615
|
+
res.errorDetails
|
|
24616
|
+
);
|
|
24617
|
+
if (res.data.data?.shop_id !== resolved.shop_id)
|
|
24618
|
+
fail(this, "The write response has a different shop identity", 2);
|
|
24619
|
+
output(
|
|
24620
|
+
this,
|
|
24621
|
+
res.data,
|
|
24622
|
+
() => console.log(`Setting ${opts.key} set to ${settingValueText(value2)} on ${resolved.domain}.`)
|
|
24623
|
+
);
|
|
24624
|
+
})
|
|
24625
|
+
);
|
|
24626
|
+
var shops = new Command("shops").description("Manage shops and their settings on the platform admin plane").addCommand(archive2).addCommand(restore2).addCommand(shopSettings);
|
|
24296
24627
|
var create6 = new Command("create").description("Create an internal, demo or dogfood account").requiredOption("--name <text>").requiredOption("--category <category>", "internal, demo or dogfood").option("--type <type>", "company or agency", "company").option("--plan <plan>", "self_managed, apex_managed or drip_managed", "self_managed").option("--domain <host>").option("--platform <platform>", "shopify, shopware, woo or other").option("--claim-shop <uuid>").option("--owner <email>").option("--consultant <uuid>", "Platform access ID").option("--consultant-title <text>").requiredOption("--reason <text>", "Audit reason, 8 to 500 characters").option("--confirm", "Confirm account creation").option("--json", "Output JSON").action(async function(opts) {
|
|
24297
24628
|
if (opts.category === "customer") fail(this, "Create customer accounts in Admin, Links", 3);
|
|
24298
24629
|
if (!["internal", "demo", "dogfood"].includes(opts.category))
|
|
@@ -24346,7 +24677,7 @@ var create6 = new Command("create").description("Create an internal, demo or dog
|
|
|
24346
24677
|
["consultant", opts.consultant],
|
|
24347
24678
|
["consultant-title", opts.consultantTitle]
|
|
24348
24679
|
];
|
|
24349
|
-
const retry = flags.filter((entry) => entry[1] !== void 0).map(([flag,
|
|
24680
|
+
const retry = flags.filter((entry) => entry[1] !== void 0).map(([flag, value2]) => `--${flag} '${value2.replaceAll("'", "'\\''")}'`).join(" ");
|
|
24350
24681
|
confirmationRequired(
|
|
24351
24682
|
this,
|
|
24352
24683
|
"--confirm is required to create an account",
|
|
@@ -24398,7 +24729,7 @@ var setCategory = new Command("set-category").description("Change an existing ac
|
|
|
24398
24729
|
if (reason2.length < 8 || reason2.length > 500)
|
|
24399
24730
|
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
24400
24731
|
if (!opts.confirm) {
|
|
24401
|
-
const quote = (
|
|
24732
|
+
const quote = (value2) => `'${value2.replaceAll("'", "'\\''")}'`;
|
|
24402
24733
|
confirmationRequired(
|
|
24403
24734
|
this,
|
|
24404
24735
|
"--confirm is required to change an account category",
|
|
@@ -24430,7 +24761,7 @@ var setManagedBy = new Command("set-managed-by").description("Assign or clear a
|
|
|
24430
24761
|
if (reason2.length < 8 || reason2.length > 500)
|
|
24431
24762
|
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
24432
24763
|
if (!opts.confirm) {
|
|
24433
|
-
const quote = (
|
|
24764
|
+
const quote = (value2) => `'${value2.replaceAll("'", "'\\''")}'`;
|
|
24434
24765
|
confirmationRequired(
|
|
24435
24766
|
this,
|
|
24436
24767
|
"--confirm is required to change a managing agency",
|
|
@@ -24465,7 +24796,7 @@ var setWorkspaceType = new Command("set-workspace-type").description("Change a w
|
|
|
24465
24796
|
if (reason2.length < 8 || reason2.length > 500)
|
|
24466
24797
|
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
24467
24798
|
if (!opts.confirm) {
|
|
24468
|
-
const quote = (
|
|
24799
|
+
const quote = (value2) => `'${value2.replaceAll("'", "'\\''")}'`;
|
|
24469
24800
|
confirmationRequired(
|
|
24470
24801
|
this,
|
|
24471
24802
|
"--confirm is required to change a workspace type",
|
|
@@ -24510,7 +24841,7 @@ function storeMoveRequest(opts) {
|
|
|
24510
24841
|
var moveStores = new Command("move-stores").description("Preview or confirm an audited set of store moves").requiredOption("--to <org-id>", "Destination organization UUID").requiredOption(
|
|
24511
24842
|
"--shop <shop-id>",
|
|
24512
24843
|
"Store UUID, repeat for each store",
|
|
24513
|
-
(
|
|
24844
|
+
(value2, previous) => [...previous, value2],
|
|
24514
24845
|
[]
|
|
24515
24846
|
).requiredOption("--reason <text>", "Audit reason, 8 to 500 characters").option("--keep-grants", "Preserve explicit store roles and overrides").option("--confirm", "Perform the move; otherwise return a read-only plan").option("--json", "Output JSON").action(async function(opts) {
|
|
24516
24847
|
let request2;
|
|
@@ -24534,7 +24865,7 @@ var moveStores = new Command("move-stores").description("Preview or confirm an a
|
|
|
24534
24865
|
output(this, res.data, () => {
|
|
24535
24866
|
printTable(
|
|
24536
24867
|
["FIELD", "VALUE"],
|
|
24537
|
-
Object.entries(res.data.data).map(([key,
|
|
24868
|
+
Object.entries(res.data.data).map(([key, value2]) => [key, JSON.stringify(value2)])
|
|
24538
24869
|
);
|
|
24539
24870
|
});
|
|
24540
24871
|
});
|
|
@@ -24560,8 +24891,8 @@ async function confirm(c, force, label, retry) {
|
|
|
24560
24891
|
if (force) return true;
|
|
24561
24892
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
24562
24893
|
confirmationRequired(c, `${label} requires confirmation in non-TTY mode.`, retry);
|
|
24563
|
-
const
|
|
24564
|
-
const rl =
|
|
24894
|
+
const readline4 = await import("node:readline");
|
|
24895
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
24565
24896
|
const answer = await new Promise(
|
|
24566
24897
|
(resolve2) => rl.question(source_default.yellow(`${label}? [y/N] `), resolve2)
|
|
24567
24898
|
);
|
|
@@ -24800,6 +25131,48 @@ ${res.data.data.avatarDataUrl ?? "(no avatar)"}`
|
|
|
24800
25131
|
}).addCommand(set6);
|
|
24801
25132
|
var accountCommand = new Command("account").description("Manage your Apex account").addCommand(profile2);
|
|
24802
25133
|
|
|
25134
|
+
// src/commands/commerce.ts
|
|
25135
|
+
async function run3(command, params) {
|
|
25136
|
+
const response = await lookupCommerceCatalog(requireCredentials(), params);
|
|
25137
|
+
if (!response.ok || !response.data)
|
|
25138
|
+
fail(
|
|
25139
|
+
command,
|
|
25140
|
+
response.error ?? "Catalog lookup failed",
|
|
25141
|
+
classifyStatus(response.status),
|
|
25142
|
+
response.errorDetails
|
|
25143
|
+
);
|
|
25144
|
+
output(command, response.data, () => {
|
|
25145
|
+
const data = response.data.data;
|
|
25146
|
+
const products = data.mode === "product" ? [data.product] : data.products;
|
|
25147
|
+
const rows = products.flatMap(
|
|
25148
|
+
(product) => product.variants.map((variant) => [
|
|
25149
|
+
variant.id,
|
|
25150
|
+
variant.title,
|
|
25151
|
+
variant.sku ?? "",
|
|
25152
|
+
variant.price,
|
|
25153
|
+
variant.unit_cost ?? "unknown",
|
|
25154
|
+
// Search results carry no exclusion data; never present them as eligible.
|
|
25155
|
+
variant.price_test_exclusion ?? "unknown"
|
|
25156
|
+
])
|
|
25157
|
+
);
|
|
25158
|
+
printTable(
|
|
25159
|
+
["GID", "TITLE", "SKU", "PRICE", "COST", "EXCLUSION"],
|
|
25160
|
+
rows,
|
|
25161
|
+
[42, 24, 18, 12, 12, 14]
|
|
25162
|
+
);
|
|
25163
|
+
});
|
|
25164
|
+
}
|
|
25165
|
+
var search = new Command("search").description("Search the commerce product catalog").argument("[query]", "Product search query").option("--cursor <cursor>").option("--limit <limit>", "Products per page", (v) => Number(v)).action(async function(query, opts) {
|
|
25166
|
+
await run3(this, { query, ...opts });
|
|
25167
|
+
});
|
|
25168
|
+
var get10 = new Command("get").description("Get one product and its variants").argument("[handle]", "Exact product handle").option("--product-id <id>", "Shopify product ID").option("--cursor <cursor>").action(async function(handle, opts) {
|
|
25169
|
+
if (!handle && !opts.productId || handle && opts.productId)
|
|
25170
|
+
fail(this, "Provide exactly one of <handle> or --product-id", 3);
|
|
25171
|
+
await run3(this, { handle, product_id: opts.productId, cursor: opts.cursor });
|
|
25172
|
+
});
|
|
25173
|
+
var catalog = new Command("catalog").description("Look up products for commerce drafts").addCommand(search).addCommand(get10);
|
|
25174
|
+
var commerceCommand = new Command("commerce").description("Commerce catalog tools").addCommand(catalog);
|
|
25175
|
+
|
|
24803
25176
|
// src/commands/keys.ts
|
|
24804
25177
|
function selected() {
|
|
24805
25178
|
const credentials = requireUserCredentials();
|
|
@@ -24884,17 +25257,17 @@ async function readResponseText(res) {
|
|
|
24884
25257
|
let totalBytes = 0;
|
|
24885
25258
|
try {
|
|
24886
25259
|
while (totalBytes < MAX_RESPONSE_BYTES) {
|
|
24887
|
-
const { done: done2, value } = await reader.read();
|
|
25260
|
+
const { done: done2, value: value2 } = await reader.read();
|
|
24888
25261
|
if (done2) break;
|
|
24889
25262
|
const remainingBytes = MAX_RESPONSE_BYTES - totalBytes;
|
|
24890
|
-
if (
|
|
24891
|
-
chunks.push(
|
|
25263
|
+
if (value2.byteLength >= remainingBytes) {
|
|
25264
|
+
chunks.push(value2.byteLength === remainingBytes ? value2 : value2.slice(0, remainingBytes));
|
|
24892
25265
|
totalBytes += remainingBytes;
|
|
24893
25266
|
await reader.cancel().catch(() => void 0);
|
|
24894
25267
|
break;
|
|
24895
25268
|
}
|
|
24896
|
-
chunks.push(
|
|
24897
|
-
totalBytes +=
|
|
25269
|
+
chunks.push(value2);
|
|
25270
|
+
totalBytes += value2.byteLength;
|
|
24898
25271
|
}
|
|
24899
25272
|
} finally {
|
|
24900
25273
|
reader.releaseLock();
|
|
@@ -24924,8 +25297,8 @@ async function fetchText(url) {
|
|
|
24924
25297
|
});
|
|
24925
25298
|
return { status: res.status, text: await readResponseText(res), finalUrl: res.url };
|
|
24926
25299
|
}
|
|
24927
|
-
function abs(base,
|
|
24928
|
-
return new URL(
|
|
25300
|
+
function abs(base, path27) {
|
|
25301
|
+
return new URL(path27, base).toString();
|
|
24929
25302
|
}
|
|
24930
25303
|
function looksLikeShopifyCart(text2) {
|
|
24931
25304
|
try {
|
|
@@ -24945,9 +25318,9 @@ async function collectSignals(url) {
|
|
|
24945
25318
|
const chunks = [`__apex_primary_status_${primary.status}__`, primary.text];
|
|
24946
25319
|
const protectedHit = primary.status === 403 || primary.status === 429 || matchDetectionMarkers(primary.text, "protected").length > 0;
|
|
24947
25320
|
if (!protectedHit) {
|
|
24948
|
-
for (const
|
|
25321
|
+
for (const path27 of ["/cart.js"]) {
|
|
24949
25322
|
try {
|
|
24950
|
-
const secondary = await fetchText(abs(primary.finalUrl || url,
|
|
25323
|
+
const secondary = await fetchText(abs(primary.finalUrl || url, path27));
|
|
24951
25324
|
if (secondary.status >= 200 && secondary.status < 300 && looksLikeShopifyCart(secondary.text)) {
|
|
24952
25325
|
chunks.push("__apex_secondary_shopify_cart_js__", secondary.text.slice(0, 2e3));
|
|
24953
25326
|
}
|
|
@@ -25133,7 +25506,7 @@ var list14 = new Command("list").alias("ls").description(
|
|
|
25133
25506
|
var create8 = new Command("create").description(`Create a webhook. Prints the signing secret once. Signature docs: ${SIGNATURE_DOC}`).requiredOption("--url <url>", "HTTPS callback URL").option(
|
|
25134
25507
|
"--event <event>",
|
|
25135
25508
|
"Webhook event to subscribe to; repeat for multiple events",
|
|
25136
|
-
(
|
|
25509
|
+
(value2, previous = []) => [...previous, value2],
|
|
25137
25510
|
[]
|
|
25138
25511
|
).action(async function action73(opts) {
|
|
25139
25512
|
const events = selectedEvents(opts);
|
|
@@ -25188,7 +25561,7 @@ var deliveries = new Command("deliveries").description("List webhook deliveries
|
|
|
25188
25561
|
var update5 = new Command("update").description("Update a webhook URL, events, or active state").argument("<id>", "Webhook id").option("--url <url>", "HTTPS callback URL").option(
|
|
25189
25562
|
"--event <event>",
|
|
25190
25563
|
"Replacement event; repeat for multiple events",
|
|
25191
|
-
(
|
|
25564
|
+
(value2, previous = []) => [...previous, value2],
|
|
25192
25565
|
[]
|
|
25193
25566
|
).option("--active", "Enable the webhook").option("--inactive", "Disable the webhook").action(async function action76(id, opts) {
|
|
25194
25567
|
if (opts.active && opts.inactive)
|
|
@@ -25242,10 +25615,10 @@ var webhooksCommand = new Command("webhooks").description("Manage shop webhooks"
|
|
|
25242
25615
|
|
|
25243
25616
|
// src/commands/simulate.ts
|
|
25244
25617
|
init_source();
|
|
25245
|
-
var
|
|
25246
|
-
var
|
|
25618
|
+
var import_node_fs28 = __toESM(require("node:fs"));
|
|
25619
|
+
var import_node_path25 = __toESM(require("node:path"));
|
|
25247
25620
|
function readJson2(file) {
|
|
25248
|
-
const text2 = file === "-" ?
|
|
25621
|
+
const text2 = file === "-" ? import_node_fs28.default.readFileSync(0, "utf8") : import_node_fs28.default.readFileSync(import_node_path25.default.resolve(file), "utf8");
|
|
25249
25622
|
try {
|
|
25250
25623
|
return JSON.parse(text2);
|
|
25251
25624
|
} catch (error) {
|
|
@@ -25257,21 +25630,21 @@ function readJson2(file) {
|
|
|
25257
25630
|
function plural(count2, singular3) {
|
|
25258
25631
|
return `${count2} ${singular3}${count2 === 1 ? "" : "s"}`;
|
|
25259
25632
|
}
|
|
25260
|
-
function isGtagEventTuple(
|
|
25261
|
-
return Array.isArray(
|
|
25633
|
+
function isGtagEventTuple(value2) {
|
|
25634
|
+
return Array.isArray(value2) && value2[0] === "event" && typeof value2[1] === "string";
|
|
25262
25635
|
}
|
|
25263
|
-
function isPlainObject(
|
|
25264
|
-
if (
|
|
25265
|
-
const prototype = Object.getPrototypeOf(
|
|
25636
|
+
function isPlainObject(value2) {
|
|
25637
|
+
if (value2 === null || typeof value2 !== "object" || Array.isArray(value2)) return false;
|
|
25638
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
25266
25639
|
return prototype === Object.prototype || prototype === null;
|
|
25267
25640
|
}
|
|
25268
|
-
function isExplicitPayloadBatch(
|
|
25269
|
-
if (!Array.isArray(
|
|
25270
|
-
if (
|
|
25641
|
+
function isExplicitPayloadBatch(value2) {
|
|
25642
|
+
if (!Array.isArray(value2) || isGtagEventTuple(value2)) return false;
|
|
25643
|
+
if (value2.length > 0 && value2.every((entry) => isPlainObject(entry) || isGtagEventTuple(entry))) {
|
|
25271
25644
|
return true;
|
|
25272
25645
|
}
|
|
25273
|
-
if (
|
|
25274
|
-
return
|
|
25646
|
+
if (value2.length > 0 && typeof value2[0] === "string") return false;
|
|
25647
|
+
return value2.some((entry) => isPlainObject(entry) || isGtagEventTuple(entry));
|
|
25275
25648
|
}
|
|
25276
25649
|
var simulateCommand = new Command("simulate").description("Simulate data-layer triggers without emitting events").option("--config <file>", "Trigger config JSON file").requiredOption("--payload <file|->", "Payload JSON file or stdin").option("--from-shop", "Load live triggers from the selected shop").action(async function(opts) {
|
|
25277
25650
|
if (Boolean(opts.config) === Boolean(opts.fromShop)) {
|
|
@@ -25354,7 +25727,7 @@ var simulateCommand = new Command("simulate").description("Simulate data-layer t
|
|
|
25354
25727
|
}
|
|
25355
25728
|
if (!result.matches.length) {
|
|
25356
25729
|
const numericPaths = result.diagnostics.numericPaths.map(
|
|
25357
|
-
({ path: numericPath, value }) => `${numericPath}=${
|
|
25730
|
+
({ path: numericPath, value: value2 }) => `${numericPath}=${value2}`
|
|
25358
25731
|
).join(", ");
|
|
25359
25732
|
console.log(` numeric paths: ${numericPaths || "none"}`);
|
|
25360
25733
|
}
|
|
@@ -25367,14 +25740,14 @@ var simulateCommand = new Command("simulate").description("Simulate data-layer t
|
|
|
25367
25740
|
});
|
|
25368
25741
|
|
|
25369
25742
|
// src/commands/config-resources.ts
|
|
25370
|
-
var
|
|
25371
|
-
var
|
|
25743
|
+
var import_node_fs30 = __toESM(require("node:fs"));
|
|
25744
|
+
var import_node_path27 = __toESM(require("node:path"));
|
|
25372
25745
|
|
|
25373
25746
|
// src/commands/landing-pages.ts
|
|
25374
25747
|
var import_node_crypto9 = __toESM(require("node:crypto"));
|
|
25375
|
-
var
|
|
25376
|
-
var
|
|
25377
|
-
function
|
|
25748
|
+
var import_node_fs29 = __toESM(require("node:fs"));
|
|
25749
|
+
var import_node_path26 = __toESM(require("node:path"));
|
|
25750
|
+
function apiFailure2(command, response, fallback2) {
|
|
25378
25751
|
if (!response.ok || response.data === void 0) {
|
|
25379
25752
|
fail(
|
|
25380
25753
|
command,
|
|
@@ -25388,13 +25761,13 @@ function sha256(body5) {
|
|
|
25388
25761
|
return import_node_crypto9.default.createHash("sha256").update(body5).digest("hex");
|
|
25389
25762
|
}
|
|
25390
25763
|
function markerPath(folder) {
|
|
25391
|
-
return
|
|
25764
|
+
return import_node_path26.default.join(folder, LANDING_PAGE_CHECKOUT_MARKER);
|
|
25392
25765
|
}
|
|
25393
25766
|
function readMarker(folder) {
|
|
25394
25767
|
const file = markerPath(folder);
|
|
25395
|
-
if (!
|
|
25768
|
+
if (!import_node_fs29.default.existsSync(file)) return null;
|
|
25396
25769
|
try {
|
|
25397
|
-
return JSON.parse(
|
|
25770
|
+
return JSON.parse(import_node_fs29.default.readFileSync(file, "utf8"));
|
|
25398
25771
|
} catch (error) {
|
|
25399
25772
|
throw new CliError(
|
|
25400
25773
|
`${LANDING_PAGE_CHECKOUT_MARKER} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -25412,14 +25785,14 @@ function readMarker(folder) {
|
|
|
25412
25785
|
}
|
|
25413
25786
|
}
|
|
25414
25787
|
function writeMarker(folder, marker) {
|
|
25415
|
-
|
|
25416
|
-
|
|
25417
|
-
|
|
25788
|
+
import_node_fs29.default.mkdirSync(import_node_path26.default.dirname(markerPath(folder)), { recursive: true });
|
|
25789
|
+
import_node_fs29.default.writeFileSync(import_node_path26.default.join(folder, ".apex", ".gitignore"), "landing-page.json\n", "utf8");
|
|
25790
|
+
import_node_fs29.default.writeFileSync(markerPath(folder), `${JSON.stringify(marker, null, 2)}
|
|
25418
25791
|
`, "utf8");
|
|
25419
25792
|
}
|
|
25420
25793
|
function requireCheckout(command, folderArg) {
|
|
25421
|
-
const folder =
|
|
25422
|
-
const marker =
|
|
25794
|
+
const folder = import_node_path26.default.resolve(process.cwd(), folderArg);
|
|
25795
|
+
const marker = import_node_fs29.default.existsSync(folder) && import_node_fs29.default.statSync(folder).isDirectory() ? readMarker(folder) : null;
|
|
25423
25796
|
if (!marker) {
|
|
25424
25797
|
fail(command, `${folderArg} is not a landing-page checkout.`, EXIT_CODES.validation, {
|
|
25425
25798
|
code: "validation_failed",
|
|
@@ -25431,8 +25804,8 @@ function requireCheckout(command, folderArg) {
|
|
|
25431
25804
|
return { folder, marker };
|
|
25432
25805
|
}
|
|
25433
25806
|
function resolvePageId(target) {
|
|
25434
|
-
const folder =
|
|
25435
|
-
if (
|
|
25807
|
+
const folder = import_node_path26.default.resolve(process.cwd(), target);
|
|
25808
|
+
if (import_node_fs29.default.existsSync(folder) && import_node_fs29.default.statSync(folder).isDirectory()) {
|
|
25436
25809
|
const marker = readMarker(folder);
|
|
25437
25810
|
if (marker) return marker.landingPageId;
|
|
25438
25811
|
throw new CliError(
|
|
@@ -25454,16 +25827,16 @@ function resolvePageId(target) {
|
|
|
25454
25827
|
function readCheckoutFiles(folder) {
|
|
25455
25828
|
const files = [];
|
|
25456
25829
|
const visit2 = (directory) => {
|
|
25457
|
-
for (const entry of
|
|
25458
|
-
const absolute =
|
|
25459
|
-
const relative =
|
|
25830
|
+
for (const entry of import_node_fs29.default.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
25831
|
+
const absolute = import_node_path26.default.join(directory, entry.name);
|
|
25832
|
+
const relative = import_node_path26.default.relative(folder, absolute).split(import_node_path26.default.sep).join("/");
|
|
25460
25833
|
if (!isLandingPageCheckoutPath(relative)) continue;
|
|
25461
25834
|
if (entry.isDirectory()) visit2(absolute);
|
|
25462
25835
|
else if (entry.isFile()) {
|
|
25463
25836
|
try {
|
|
25464
25837
|
validateLandingPageLocalFiles([
|
|
25465
25838
|
...files,
|
|
25466
|
-
{ path: relative, bytes:
|
|
25839
|
+
{ path: relative, bytes: import_node_fs29.default.statSync(absolute).size, sha256: "" }
|
|
25467
25840
|
]);
|
|
25468
25841
|
} catch (error) {
|
|
25469
25842
|
throw new CliError(
|
|
@@ -25471,7 +25844,7 @@ function readCheckoutFiles(folder) {
|
|
|
25471
25844
|
EXIT_CODES.validation
|
|
25472
25845
|
);
|
|
25473
25846
|
}
|
|
25474
|
-
const body5 =
|
|
25847
|
+
const body5 = import_node_fs29.default.readFileSync(absolute);
|
|
25475
25848
|
files.push({ path: relative, sha256: sha256(body5), bytes: body5.byteLength, body: body5 });
|
|
25476
25849
|
}
|
|
25477
25850
|
}
|
|
@@ -25488,8 +25861,8 @@ function readCheckoutFiles(folder) {
|
|
|
25488
25861
|
return files;
|
|
25489
25862
|
}
|
|
25490
25863
|
function readManifest2(command, folder) {
|
|
25491
|
-
const file =
|
|
25492
|
-
if (!
|
|
25864
|
+
const file = import_node_path26.default.join(folder, LANDING_PAGE_MANIFEST_FILE);
|
|
25865
|
+
if (!import_node_fs29.default.existsSync(file)) {
|
|
25493
25866
|
fail(
|
|
25494
25867
|
command,
|
|
25495
25868
|
`${LANDING_PAGE_MANIFEST_FILE} is missing from the checkout.`,
|
|
@@ -25500,7 +25873,7 @@ function readManifest2(command, folder) {
|
|
|
25500
25873
|
);
|
|
25501
25874
|
}
|
|
25502
25875
|
try {
|
|
25503
|
-
return JSON.parse(
|
|
25876
|
+
return JSON.parse(import_node_fs29.default.readFileSync(file, "utf8"));
|
|
25504
25877
|
} catch (error) {
|
|
25505
25878
|
fail(
|
|
25506
25879
|
command,
|
|
@@ -25546,15 +25919,15 @@ function printPlan(plan2) {
|
|
|
25546
25919
|
}
|
|
25547
25920
|
async function confirm2(message) {
|
|
25548
25921
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
|
|
25549
|
-
const
|
|
25550
|
-
const rl =
|
|
25922
|
+
const readline4 = await import("node:readline");
|
|
25923
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
25551
25924
|
const answer = await new Promise((resolve2) => rl.question(`${message} [y/N] `, resolve2));
|
|
25552
25925
|
rl.close();
|
|
25553
25926
|
return answer.trim().toLowerCase() === "y";
|
|
25554
25927
|
}
|
|
25555
25928
|
function manifestDigest(folder) {
|
|
25556
|
-
const file =
|
|
25557
|
-
return
|
|
25929
|
+
const file = import_node_path26.default.join(folder, LANDING_PAGE_MANIFEST_FILE);
|
|
25930
|
+
return import_node_fs29.default.existsSync(file) ? sha256(import_node_fs29.default.readFileSync(file)) : null;
|
|
25558
25931
|
}
|
|
25559
25932
|
function localChanges(folder, marker) {
|
|
25560
25933
|
const local = new Map(readCheckoutFiles(folder).map((file) => [file.path, file.sha256]));
|
|
@@ -25572,8 +25945,8 @@ function removeStaleFiles(folder, previous, next, added = []) {
|
|
|
25572
25945
|
if (!previous) return;
|
|
25573
25946
|
for (const file of [...Object.keys(previous.files), ...added]) {
|
|
25574
25947
|
if (next.has(file) || !isLandingPageCheckoutPath(file)) continue;
|
|
25575
|
-
const absolute =
|
|
25576
|
-
if (absolute.startsWith(folder +
|
|
25948
|
+
const absolute = import_node_path26.default.resolve(folder, file);
|
|
25949
|
+
if (absolute.startsWith(folder + import_node_path26.default.sep) && import_node_fs29.default.existsSync(absolute)) import_node_fs29.default.rmSync(absolute);
|
|
25577
25950
|
}
|
|
25578
25951
|
}
|
|
25579
25952
|
async function pullCheckout(command, creds, id, folder, force = false) {
|
|
@@ -25612,8 +25985,8 @@ async function pullCheckout(command, creds, id, folder, force = false) {
|
|
|
25612
25985
|
}
|
|
25613
25986
|
const api = landingPages(creds);
|
|
25614
25987
|
const listing = await api.checkout(id);
|
|
25615
|
-
|
|
25616
|
-
|
|
25988
|
+
apiFailure2(command, listing, "Failed to pull landing page");
|
|
25989
|
+
import_node_fs29.default.mkdirSync(folder, { recursive: true });
|
|
25617
25990
|
const written = {};
|
|
25618
25991
|
const downloaded = [];
|
|
25619
25992
|
for (const batch of landingPageBatches(listing.data.files, (file) => file.bytes)) {
|
|
@@ -25621,14 +25994,14 @@ async function pullCheckout(command, creds, id, folder, force = false) {
|
|
|
25621
25994
|
id,
|
|
25622
25995
|
batch.map((file) => file.path)
|
|
25623
25996
|
);
|
|
25624
|
-
|
|
25997
|
+
apiFailure2(command, contents, "Failed to pull landing page files");
|
|
25625
25998
|
const returned2 = new Set(contents.data.files.map((file) => file.path));
|
|
25626
25999
|
const missing = batch.filter((file) => !returned2.has(file.path)).map((file) => file.path);
|
|
25627
26000
|
if (missing.length)
|
|
25628
26001
|
fail(command, `The server did not return ${missing.slice(0, 5).join(", ")}. Pull again.`);
|
|
25629
26002
|
for (const file of contents.data.files) {
|
|
25630
|
-
const target =
|
|
25631
|
-
if (!target.startsWith(folder +
|
|
26003
|
+
const target = import_node_path26.default.resolve(folder, file.path);
|
|
26004
|
+
if (!target.startsWith(folder + import_node_path26.default.sep))
|
|
25632
26005
|
fail(command, `Refusing to write outside the checkout: ${file.path}`);
|
|
25633
26006
|
const download = file.download_url ? await fetch(file.download_url, { signal: AbortSignal.timeout(6e4) }) : null;
|
|
25634
26007
|
if (download && !download.ok)
|
|
@@ -25641,7 +26014,7 @@ async function pullCheckout(command, creds, id, folder, force = false) {
|
|
|
25641
26014
|
}
|
|
25642
26015
|
if (!existing && !force) {
|
|
25643
26016
|
const clobbered = downloaded.filter(
|
|
25644
|
-
({ target, sha256: digest }) =>
|
|
26017
|
+
({ target, sha256: digest }) => import_node_fs29.default.existsSync(target) && sha256(import_node_fs29.default.readFileSync(target)) !== digest
|
|
25645
26018
|
).map((file) => file.path);
|
|
25646
26019
|
if (clobbered.length) {
|
|
25647
26020
|
fail(
|
|
@@ -25665,8 +26038,8 @@ async function pullCheckout(command, creds, id, folder, force = false) {
|
|
|
25665
26038
|
}
|
|
25666
26039
|
}
|
|
25667
26040
|
for (const file of downloaded) {
|
|
25668
|
-
|
|
25669
|
-
|
|
26041
|
+
import_node_fs29.default.mkdirSync(import_node_path26.default.dirname(file.target), { recursive: true });
|
|
26042
|
+
import_node_fs29.default.writeFileSync(file.target, file.body);
|
|
25670
26043
|
written[file.path] = file.sha256;
|
|
25671
26044
|
}
|
|
25672
26045
|
removeStaleFiles(
|
|
@@ -25675,24 +26048,24 @@ async function pullCheckout(command, creds, id, folder, force = false) {
|
|
|
25675
26048
|
new Set(Object.keys(written)),
|
|
25676
26049
|
force ? readCheckoutFiles(folder).map((file) => file.path) : []
|
|
25677
26050
|
);
|
|
25678
|
-
|
|
25679
|
-
|
|
26051
|
+
import_node_fs29.default.writeFileSync(
|
|
26052
|
+
import_node_path26.default.join(folder, LANDING_PAGE_MANIFEST_FILE),
|
|
25680
26053
|
`${JSON.stringify(listing.data.manifest ?? {}, null, 2)}
|
|
25681
26054
|
`,
|
|
25682
26055
|
"utf8"
|
|
25683
26056
|
);
|
|
25684
|
-
const contextDir =
|
|
25685
|
-
|
|
26057
|
+
const contextDir = import_node_path26.default.join(folder, LANDING_PAGE_CONTEXT_DIR);
|
|
26058
|
+
import_node_fs29.default.mkdirSync(contextDir, { recursive: true });
|
|
25686
26059
|
const contextName = /^[a-z0-9_-]+\.json$/i;
|
|
25687
26060
|
const contextEntries = Object.entries(listing.data.context ?? {}).filter(
|
|
25688
26061
|
([name]) => contextName.test(name)
|
|
25689
26062
|
);
|
|
25690
26063
|
const returned = new Set(contextEntries.map(([name]) => name));
|
|
25691
|
-
for (const name of
|
|
25692
|
-
if (contextName.test(name) && !returned.has(name))
|
|
26064
|
+
for (const name of import_node_fs29.default.readdirSync(contextDir)) {
|
|
26065
|
+
if (contextName.test(name) && !returned.has(name)) import_node_fs29.default.rmSync(import_node_path26.default.join(contextDir, name));
|
|
25693
26066
|
}
|
|
25694
|
-
for (const [name,
|
|
25695
|
-
|
|
26067
|
+
for (const [name, value2] of contextEntries) {
|
|
26068
|
+
import_node_fs29.default.writeFileSync(import_node_path26.default.join(contextDir, name), `${JSON.stringify(value2, null, 2)}
|
|
25696
26069
|
`, "utf8");
|
|
25697
26070
|
}
|
|
25698
26071
|
writeMarker(folder, {
|
|
@@ -25723,8 +26096,8 @@ var create9 = new Command("create").description("Create a landing page to build
|
|
|
25723
26096
|
...opts.slug ? { slug: opts.slug } : {},
|
|
25724
26097
|
...opts.idea ? { idea_key: opts.idea } : {}
|
|
25725
26098
|
});
|
|
25726
|
-
|
|
25727
|
-
const pulled = opts.out ? await pullCheckout(this, creds, created.data.id,
|
|
26099
|
+
apiFailure2(this, created, "Failed to create landing page");
|
|
26100
|
+
const pulled = opts.out ? await pullCheckout(this, creds, created.data.id, import_node_path26.default.resolve(process.cwd(), opts.out)) : null;
|
|
25728
26101
|
output(
|
|
25729
26102
|
this,
|
|
25730
26103
|
{ landing_page: created.data, ...pulled ? { folder: pulled.folder } : {} },
|
|
@@ -25736,7 +26109,7 @@ var create9 = new Command("create").description("Create a landing page to build
|
|
|
25736
26109
|
});
|
|
25737
26110
|
var pull = new Command("pull").description("Pull a landing page into a checkout folder").argument("<id>", "Landing page id").option("--out <folder>", "Target folder (default: a folder named after the id)").option("--force", "Overwrite changes in the checkout that are not applied").action(async function(id, opts) {
|
|
25738
26111
|
const creds = requireCredentials();
|
|
25739
|
-
const folder =
|
|
26112
|
+
const folder = import_node_path26.default.resolve(process.cwd(), opts.out ?? id);
|
|
25740
26113
|
const result = await pullCheckout(this, creds, id, folder, opts.force === true);
|
|
25741
26114
|
output(this, result, () => {
|
|
25742
26115
|
console.log(
|
|
@@ -25754,7 +26127,7 @@ var plan = new Command("plan").description("Show what applying a checkout would
|
|
|
25754
26127
|
manifest: readManifest2(this, folder),
|
|
25755
26128
|
files: declared(files)
|
|
25756
26129
|
});
|
|
25757
|
-
|
|
26130
|
+
apiFailure2(this, response, "Failed to plan landing page");
|
|
25758
26131
|
output(
|
|
25759
26132
|
this,
|
|
25760
26133
|
{ folder, landingPageId: marker.landingPageId, plan: response.data },
|
|
@@ -25768,7 +26141,7 @@ var apply = new Command("apply").description("Apply a checkout as a new version"
|
|
|
25768
26141
|
const files = readCheckoutFiles(folder);
|
|
25769
26142
|
const manifest = readManifest2(this, folder);
|
|
25770
26143
|
const planned = await api.plan(marker.landingPageId, { manifest, files: declared(files) });
|
|
25771
|
-
|
|
26144
|
+
apiFailure2(this, planned, "Failed to plan landing page");
|
|
25772
26145
|
if (!planned.data.would_change) {
|
|
25773
26146
|
output(
|
|
25774
26147
|
this,
|
|
@@ -25801,7 +26174,7 @@ var apply = new Command("apply").description("Apply a checkout as a new version"
|
|
|
25801
26174
|
sha256: file.sha256,
|
|
25802
26175
|
base_version_id: planned.data.base_version_id
|
|
25803
26176
|
});
|
|
25804
|
-
|
|
26177
|
+
apiFailure2(this, granted, "Failed to grant video upload");
|
|
25805
26178
|
await uploadLandingVideo(granted.data, file.body, {
|
|
25806
26179
|
progress: (uploaded, total) => {
|
|
25807
26180
|
console.error(`Uploading ${file.path}: ${uploaded}/${total} bytes`);
|
|
@@ -25820,7 +26193,7 @@ var apply = new Command("apply").description("Apply a checkout as a new version"
|
|
|
25820
26193
|
encoding: "base64"
|
|
25821
26194
|
}))
|
|
25822
26195
|
);
|
|
25823
|
-
|
|
26196
|
+
apiFailure2(this, uploaded, "Failed to upload landing page files");
|
|
25824
26197
|
}
|
|
25825
26198
|
const applied = await api.apply(marker.landingPageId, {
|
|
25826
26199
|
manifest,
|
|
@@ -25847,7 +26220,7 @@ var apply = new Command("apply").description("Apply a checkout as a new version"
|
|
|
25847
26220
|
}
|
|
25848
26221
|
);
|
|
25849
26222
|
}
|
|
25850
|
-
|
|
26223
|
+
apiFailure2(this, applied, "Failed to apply landing page");
|
|
25851
26224
|
writeMarker(folder, {
|
|
25852
26225
|
...marker,
|
|
25853
26226
|
versionId: applied.data.version_id,
|
|
@@ -25873,7 +26246,7 @@ var preview = new Command("preview").description("Print a signed preview link (v
|
|
|
25873
26246
|
resolvePageId(target),
|
|
25874
26247
|
versionNumber
|
|
25875
26248
|
);
|
|
25876
|
-
|
|
26249
|
+
apiFailure2(this, response, "Failed to get preview link");
|
|
25877
26250
|
output(this, response.data, () => console.log(response.data.preview_url));
|
|
25878
26251
|
});
|
|
25879
26252
|
async function versionIdFor(command, creds, id, raw) {
|
|
@@ -25882,7 +26255,7 @@ async function versionIdFor(command, creds, id, raw) {
|
|
|
25882
26255
|
if (!Number.isInteger(number) || number < 1)
|
|
25883
26256
|
fail(command, "--version must be a version number.", EXIT_CODES.validation);
|
|
25884
26257
|
const versions2 = await landingPages(creds).versions(id);
|
|
25885
|
-
|
|
26258
|
+
apiFailure2(command, versions2, "Failed to list versions");
|
|
25886
26259
|
const match2 = versions2.data.find((version) => version.version_number === number);
|
|
25887
26260
|
if (!match2) fail(command, `Version ${number} not found.`, EXIT_CODES.validation);
|
|
25888
26261
|
return match2.id;
|
|
@@ -25902,7 +26275,7 @@ var deploy = new Command("deploy").description(
|
|
|
25902
26275
|
...opts.host ? { host: opts.host } : {},
|
|
25903
26276
|
...opts.path ? { path: opts.path } : {}
|
|
25904
26277
|
});
|
|
25905
|
-
|
|
26278
|
+
apiFailure2(this, response, "Failed to deploy landing page");
|
|
25906
26279
|
output(this, response.data, () => {
|
|
25907
26280
|
console.log(response.data.url);
|
|
25908
26281
|
console.log(`Version ${response.data.version_number} is live.`);
|
|
@@ -25910,7 +26283,7 @@ var deploy = new Command("deploy").description(
|
|
|
25910
26283
|
}).addHelpText("after", SPLIT_KEEPS_SERVING_HELP);
|
|
25911
26284
|
var versions = new Command("versions").description("List versions").argument("[folder-or-id]", "Checkout folder or landing page id", ".").action(async function(target) {
|
|
25912
26285
|
const response = await landingPages(requireCredentials()).versions(resolvePageId(target));
|
|
25913
|
-
|
|
26286
|
+
apiFailure2(this, response, "Failed to list versions");
|
|
25914
26287
|
output(
|
|
25915
26288
|
this,
|
|
25916
26289
|
response.data,
|
|
@@ -25935,7 +26308,7 @@ var rollback = new Command("rollback").description("Deploy an earlier version to
|
|
|
25935
26308
|
const response = await landingPages(requireCredentials()).rollback(resolvePageId(target), {
|
|
25936
26309
|
version_number: number
|
|
25937
26310
|
});
|
|
25938
|
-
|
|
26311
|
+
apiFailure2(this, response, "Failed to roll back landing page");
|
|
25939
26312
|
output(this, response.data, () => {
|
|
25940
26313
|
console.log(response.data.url);
|
|
25941
26314
|
console.log(`Version ${response.data.version_number} is live.`);
|
|
@@ -25948,8 +26321,8 @@ var experiment = new Command("experiment").description("Create a draft experimen
|
|
|
25948
26321
|
"--variant <number>",
|
|
25949
26322
|
"Variant version number (default: the manifest's experiment.variant)"
|
|
25950
26323
|
).option("--name <name>", "Experiment name").option("--primary-goal <key>", "Manifest goal key to make primary (default: the first goal)").action(async function(target, opts) {
|
|
25951
|
-
const folder =
|
|
25952
|
-
const fromManifest =
|
|
26324
|
+
const folder = import_node_path26.default.resolve(process.cwd(), target);
|
|
26325
|
+
const fromManifest = import_node_fs29.default.existsSync(import_node_path26.default.join(folder, LANDING_PAGE_MANIFEST_FILE)) ? readManifest2(this, folder)?.experiment ?? {} : {};
|
|
25953
26326
|
const control = Number(opts.control ?? fromManifest.control);
|
|
25954
26327
|
const variant = Number(opts.variant ?? fromManifest.variant);
|
|
25955
26328
|
if (!Number.isInteger(control) || !Number.isInteger(variant) || control < 1 || variant < 1) {
|
|
@@ -25965,7 +26338,7 @@ var experiment = new Command("experiment").description("Create a draft experimen
|
|
|
25965
26338
|
...opts.name ? { name: opts.name } : {},
|
|
25966
26339
|
...opts.primaryGoal ? { primary_goal: opts.primaryGoal } : {}
|
|
25967
26340
|
});
|
|
25968
|
-
|
|
26341
|
+
apiFailure2(this, response, "Failed to create experiment");
|
|
25969
26342
|
output(this, response.data, () => {
|
|
25970
26343
|
console.log(`Draft experiment ${String(response.data.experiment.id)} created.`);
|
|
25971
26344
|
console.log("Start it in the Apex dashboard when it is ready.");
|
|
@@ -26009,8 +26382,8 @@ var ALLOWED_ASSET_EXTENSIONS = Object.keys(ASSET_MIME_TYPES).join(", ");
|
|
|
26009
26382
|
var MAX_ASSET_SIZE_BYTES = 10 * 1024 * 1024;
|
|
26010
26383
|
async function confirmAssetDelete(id) {
|
|
26011
26384
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
|
|
26012
|
-
const
|
|
26013
|
-
const rl =
|
|
26385
|
+
const readline4 = await import("node:readline");
|
|
26386
|
+
const rl = readline4.createInterface({
|
|
26014
26387
|
input: process.stdin,
|
|
26015
26388
|
output: process.stderr
|
|
26016
26389
|
});
|
|
@@ -26044,22 +26417,22 @@ function readFamily(family, label) {
|
|
|
26044
26417
|
)
|
|
26045
26418
|
);
|
|
26046
26419
|
});
|
|
26047
|
-
const
|
|
26420
|
+
const get11 = new Command("get").description(`Get one ${label.slice(0, -1)}`).argument("<id>").action(async function(id) {
|
|
26048
26421
|
const r = await getConfigResource(requireCredentials(), family, id);
|
|
26049
26422
|
if (!r.ok || !r.data)
|
|
26050
26423
|
fail(this, r.error ?? "Failed to get resource", classifyStatus(r.status), r.errorDetails);
|
|
26051
26424
|
output(this, r.data, () => show(r.data));
|
|
26052
26425
|
});
|
|
26053
|
-
return { list: list15, get:
|
|
26426
|
+
return { list: list15, get: get11 };
|
|
26054
26427
|
}
|
|
26055
26428
|
var assetReads = readFamily("assets", "assets");
|
|
26056
26429
|
var upload = new Command("upload").description("Upload an asset").argument("<file>").action(async function(file) {
|
|
26057
|
-
const absolute =
|
|
26058
|
-
if (!
|
|
26059
|
-
const fileStat =
|
|
26430
|
+
const absolute = import_node_path27.default.resolve(process.cwd(), file);
|
|
26431
|
+
if (!import_node_fs30.default.existsSync(absolute)) fail(this, `File not found: ${file}`, 3);
|
|
26432
|
+
const fileStat = import_node_fs30.default.statSync(absolute);
|
|
26060
26433
|
if (!fileStat.isFile()) fail(this, `File not found: ${file}`, 3);
|
|
26061
26434
|
if (fileStat.size > MAX_ASSET_SIZE_BYTES) fail(this, `${file} is larger than 10 MB`, 3);
|
|
26062
|
-
const mimeType = ASSET_MIME_TYPES[
|
|
26435
|
+
const mimeType = ASSET_MIME_TYPES[import_node_path27.default.extname(absolute).toLowerCase()];
|
|
26063
26436
|
if (!mimeType)
|
|
26064
26437
|
fail(
|
|
26065
26438
|
this,
|
|
@@ -26068,8 +26441,8 @@ var upload = new Command("upload").description("Upload an asset").argument("<fil
|
|
|
26068
26441
|
);
|
|
26069
26442
|
const r = await uploadAssets(requireCredentials(), [
|
|
26070
26443
|
{
|
|
26071
|
-
name:
|
|
26072
|
-
bytes:
|
|
26444
|
+
name: import_node_path27.default.basename(absolute),
|
|
26445
|
+
bytes: import_node_fs30.default.readFileSync(absolute),
|
|
26073
26446
|
type: mimeType
|
|
26074
26447
|
}
|
|
26075
26448
|
]);
|
|
@@ -26101,7 +26474,7 @@ var landingPagesCommand = new Command("landing-pages").description(
|
|
|
26101
26474
|
for (const command of landingPageWorkspaceCommands) landingPagesCommand.addCommand(command);
|
|
26102
26475
|
var snippet = new Command("snippet").description("Generate an external purchase pixel snippet").option("--provider <name>").option("--handover-param <name>").option("--global-name <name>").action(async function(opts) {
|
|
26103
26476
|
const body5 = Object.fromEntries(
|
|
26104
|
-
Object.entries(opts).filter(([,
|
|
26477
|
+
Object.entries(opts).filter(([, value2]) => value2 !== void 0)
|
|
26105
26478
|
);
|
|
26106
26479
|
const r = await generateExternalPixelSnippet(requireCredentials(), body5);
|
|
26107
26480
|
if (!r.ok || !r.data)
|
|
@@ -26154,6 +26527,8 @@ program2.addCommand(prospectCommand, { hidden: true });
|
|
|
26154
26527
|
program2.addCommand(webhooksCommand);
|
|
26155
26528
|
program2.addCommand(simulateCommand);
|
|
26156
26529
|
program2.addCommand(experimentsCommand);
|
|
26530
|
+
program2.addCommand(resultsCommand);
|
|
26531
|
+
program2.addCommand(commerceCommand);
|
|
26157
26532
|
program2.addCommand(pushCommand);
|
|
26158
26533
|
program2.addCommand(previewCommand);
|
|
26159
26534
|
program2.addCommand(roadmapCommand);
|
|
@@ -26227,11 +26602,11 @@ function isExplicitJsonVersionRequest(args) {
|
|
|
26227
26602
|
} else if (arg === "--version" || arg === "-V") {
|
|
26228
26603
|
hasVersion = true;
|
|
26229
26604
|
} else if (arg === "--org" || arg === "--shop") {
|
|
26230
|
-
const
|
|
26231
|
-
if (!
|
|
26605
|
+
const value2 = args[++index];
|
|
26606
|
+
if (!value2 || value2.startsWith("-")) return false;
|
|
26232
26607
|
} else if (arg.startsWith("--org=") || arg.startsWith("--shop=")) {
|
|
26233
|
-
const
|
|
26234
|
-
if (!
|
|
26608
|
+
const value2 = arg.slice(arg.indexOf("=") + 1);
|
|
26609
|
+
if (!value2 || value2.startsWith("-")) return false;
|
|
26235
26610
|
} else {
|
|
26236
26611
|
return false;
|
|
26237
26612
|
}
|