@drip-apex/apex-cli 0.15.2 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli.js +1102 -36
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7325,7 +7325,7 @@ async function checkForUpdate(current) {
|
|
|
7325
7325
|
// package.json
|
|
7326
7326
|
var package_default = {
|
|
7327
7327
|
name: "@drip-apex/apex-cli",
|
|
7328
|
-
version: "0.15.
|
|
7328
|
+
version: "0.15.3",
|
|
7329
7329
|
license: "MIT",
|
|
7330
7330
|
description: "Apex CLI for managing experiments, approved roadmap ideas, and draft workspaces.",
|
|
7331
7331
|
private: false,
|
|
@@ -7589,7 +7589,8 @@ function classifyApiError(status4, details) {
|
|
|
7589
7589
|
const code = details?.code;
|
|
7590
7590
|
if (code === "shop_context_required" || code === "org_context_required")
|
|
7591
7591
|
return EXIT_CODES.validation;
|
|
7592
|
-
if (code === "shop_access_denied" || code === "org_access_denied"
|
|
7592
|
+
if (code === "shop_access_denied" || code === "org_access_denied" || code === "member_suspended")
|
|
7593
|
+
return EXIT_CODES.auth;
|
|
7593
7594
|
return classifyStatus(status4);
|
|
7594
7595
|
}
|
|
7595
7596
|
function confirmationRequired(command, message, retry) {
|
|
@@ -7686,7 +7687,7 @@ function errorReason(error) {
|
|
|
7686
7687
|
const body5 = error.api?.body;
|
|
7687
7688
|
const code = body5?.code ?? body5?.error?.code ?? (error.api ? details?.code : void 0);
|
|
7688
7689
|
if (typeof code === "string" && code) return code;
|
|
7689
|
-
if (["shop_context_required", "local_file_error", "validation_failed"].includes(
|
|
7690
|
+
if (["shop_context_required", "local_file_error", "validation_failed", "member_suspended"].includes(
|
|
7690
7691
|
String(details?.code)
|
|
7691
7692
|
))
|
|
7692
7693
|
return String(details?.code);
|
|
@@ -7704,6 +7705,13 @@ function errorReason(error) {
|
|
|
7704
7705
|
function errorNextSteps(error) {
|
|
7705
7706
|
const reason2 = errorReason(error);
|
|
7706
7707
|
const steps = [];
|
|
7708
|
+
if (reason2 === "member_suspended")
|
|
7709
|
+
return [
|
|
7710
|
+
{
|
|
7711
|
+
command: "contact organization admin",
|
|
7712
|
+
why: "Ask an organization owner or admin to reinstate your membership."
|
|
7713
|
+
}
|
|
7714
|
+
];
|
|
7707
7715
|
if (reason2 === "auth_required" || error.api?.status === 401) {
|
|
7708
7716
|
steps.push({ command: "apex login", why: "Authenticate with a valid API key." });
|
|
7709
7717
|
if (!error.api)
|
|
@@ -8438,6 +8446,7 @@ function listExperiments(creds, opts) {
|
|
|
8438
8446
|
if (opts?.includeArchived) params.set("archived", "1");
|
|
8439
8447
|
if (opts?.view) params.set("view", opts.view);
|
|
8440
8448
|
if (opts?.fields !== void 0) params.set("fields", opts.fields);
|
|
8449
|
+
if (opts?.url !== void 0) params.set("url", opts.url);
|
|
8441
8450
|
const qs = params.toString();
|
|
8442
8451
|
return request(creds, "GET", `/api/v1/experiments${qs ? `?${qs}` : ""}`);
|
|
8443
8452
|
}
|
|
@@ -8485,6 +8494,8 @@ function getExperimentFilesystem(creds, id) {
|
|
|
8485
8494
|
function getExperimentResults(creds, id, opts) {
|
|
8486
8495
|
const params = new URLSearchParams();
|
|
8487
8496
|
if (opts?.currency) params.set("currency", opts.currency);
|
|
8497
|
+
for (const key of ["segment", "exclude_segment"])
|
|
8498
|
+
if (opts?.[key] !== void 0) params.set(key, opts[key]);
|
|
8488
8499
|
const qs = params.toString();
|
|
8489
8500
|
return request(
|
|
8490
8501
|
creds,
|
|
@@ -8538,6 +8549,17 @@ function applyExperimentFilesystem(creds, id, body5) {
|
|
|
8538
8549
|
function getExperimentQaRun(creds, id) {
|
|
8539
8550
|
return request(creds, "GET", `/api/v1/experiments/${id}/qa/run`);
|
|
8540
8551
|
}
|
|
8552
|
+
function getExperimentQaEvents(creds, id, options = {}) {
|
|
8553
|
+
const params = new URLSearchParams();
|
|
8554
|
+
if (options.session) params.set("qa_session", options.session);
|
|
8555
|
+
if (options.minutes !== void 0) params.set("minutes", String(options.minutes));
|
|
8556
|
+
if (options.type) params.set("type", options.type);
|
|
8557
|
+
return request(
|
|
8558
|
+
creds,
|
|
8559
|
+
"GET",
|
|
8560
|
+
`/api/v1/experiments/${id}/qa/events${params.size ? `?${params}` : ""}`
|
|
8561
|
+
);
|
|
8562
|
+
}
|
|
8541
8563
|
function updateExperimentQaRun(creds, id, body5) {
|
|
8542
8564
|
return request(creds, "PATCH", `/api/v1/experiments/${id}/qa/run`, body5);
|
|
8543
8565
|
}
|
|
@@ -8891,6 +8913,12 @@ function createAdminCustomer(creds, body5) {
|
|
|
8891
8913
|
function setAdminCustomerCategory(creds, orgId, body5) {
|
|
8892
8914
|
return request(userCredentials(creds), "PATCH", `/api/v1/admin/customers/${orgId}`, body5);
|
|
8893
8915
|
}
|
|
8916
|
+
function setAdminCustomerManagedBy(creds, orgId, body5) {
|
|
8917
|
+
return request(userCredentials(creds), "PATCH", `/api/v1/admin/customers/${orgId}`, body5);
|
|
8918
|
+
}
|
|
8919
|
+
function setAdminCustomerWorkspaceType(creds, orgId, body5) {
|
|
8920
|
+
return request(userCredentials(creds), "PATCH", `/api/v1/admin/customers/${orgId}`, body5);
|
|
8921
|
+
}
|
|
8894
8922
|
function getAdminSettings(creds) {
|
|
8895
8923
|
return request(userCredentials(creds), "GET", "/api/v1/admin/settings");
|
|
8896
8924
|
}
|
|
@@ -9045,6 +9073,17 @@ function revokeOrgInvite(creds, id) {
|
|
|
9045
9073
|
function setOrgMember(creds, id, body5) {
|
|
9046
9074
|
return request(userCreds(creds), "PATCH", `/api/v1/org/members/${encodeURIComponent(id)}`, body5);
|
|
9047
9075
|
}
|
|
9076
|
+
function suspendOrgMember(creds, id, reason2) {
|
|
9077
|
+
return request(userCreds(creds), "PATCH", `/api/v1/org/members/${encodeURIComponent(id)}`, {
|
|
9078
|
+
suspended: true,
|
|
9079
|
+
...reason2 ? { reason: reason2 } : {}
|
|
9080
|
+
});
|
|
9081
|
+
}
|
|
9082
|
+
function reinstateOrgMember(creds, id) {
|
|
9083
|
+
return request(userCreds(creds), "PATCH", `/api/v1/org/members/${encodeURIComponent(id)}`, {
|
|
9084
|
+
suspended: false
|
|
9085
|
+
});
|
|
9086
|
+
}
|
|
9048
9087
|
function removeOrgMember(creds, id) {
|
|
9049
9088
|
return request(userCreds(creds), "DELETE", `/api/v1/org/members/${encodeURIComponent(id)}`);
|
|
9050
9089
|
}
|
|
@@ -9188,6 +9227,14 @@ function getOrderJourney(creds, opts) {
|
|
|
9188
9227
|
45e3
|
|
9189
9228
|
);
|
|
9190
9229
|
}
|
|
9230
|
+
function moveAdminCustomerStores(creds, orgId, body5) {
|
|
9231
|
+
return request(
|
|
9232
|
+
userCredentials(creds),
|
|
9233
|
+
"POST",
|
|
9234
|
+
`/api/v1/admin/customers/${orgId}/move-stores`,
|
|
9235
|
+
body5
|
|
9236
|
+
);
|
|
9237
|
+
}
|
|
9191
9238
|
|
|
9192
9239
|
// src/context.ts
|
|
9193
9240
|
var import_node_readline = __toESM(require("node:readline"));
|
|
@@ -9399,10 +9446,14 @@ async function waitForBrowserLogin(baseUrl, userMode = false) {
|
|
|
9399
9446
|
const returnedState = params.get("state");
|
|
9400
9447
|
const apiKey = params.get("apiKey");
|
|
9401
9448
|
const error = params.get("error");
|
|
9449
|
+
const code = params.get("code");
|
|
9402
9450
|
if (error) {
|
|
9403
9451
|
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
9404
9452
|
res.end("<h1>Apex CLI login failed</h1><p>You can close this window.</p>");
|
|
9405
|
-
|
|
9453
|
+
const details = code ? { code } : void 0;
|
|
9454
|
+
finish(
|
|
9455
|
+
details ? new CliError(error, classifyApiError(400, details), details) : new Error(error)
|
|
9456
|
+
);
|
|
9406
9457
|
return;
|
|
9407
9458
|
}
|
|
9408
9459
|
if (returnedState !== state) {
|
|
@@ -9486,6 +9537,7 @@ var loginCommand = new Command("login").description("Authenticate with Apex").op
|
|
|
9486
9537
|
try {
|
|
9487
9538
|
apiKey = await waitForBrowserLogin(baseUrl, true);
|
|
9488
9539
|
} catch (err) {
|
|
9540
|
+
if (err instanceof CliError) throw err;
|
|
9489
9541
|
fail(this, err instanceof Error ? err.message : "Browser login failed.");
|
|
9490
9542
|
}
|
|
9491
9543
|
}
|
|
@@ -9777,13 +9829,18 @@ function buildQaPreviewUrl(experiment2, options = {}) {
|
|
|
9777
9829
|
}
|
|
9778
9830
|
|
|
9779
9831
|
// src/lib/qa-preview-url.ts
|
|
9780
|
-
function buildQaPreviewUrl2(storeUrl, experimentId, variationId) {
|
|
9781
|
-
const url = buildQaPreviewUrl(
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9832
|
+
function buildQaPreviewUrl2(storeUrl, experimentId, variationId, qaSessionId) {
|
|
9833
|
+
const url = buildQaPreviewUrl(
|
|
9834
|
+
{
|
|
9835
|
+
id: experimentId,
|
|
9836
|
+
store_url: storeUrl,
|
|
9837
|
+
variations: [{ id: variationId, is_control: false }]
|
|
9838
|
+
},
|
|
9839
|
+
{ qaSessionId }
|
|
9840
|
+
);
|
|
9786
9841
|
if (!url) throw new TypeError("Invalid QA preview URL");
|
|
9842
|
+
if (qaSessionId && url.searchParams.get("drip_qa_session") !== qaSessionId)
|
|
9843
|
+
url.searchParams.set("drip_qa_session", qaSessionId);
|
|
9787
9844
|
return url;
|
|
9788
9845
|
}
|
|
9789
9846
|
|
|
@@ -10181,6 +10238,755 @@ function createAssetReferenceRewriter(options) {
|
|
|
10181
10238
|
return { rewrite, rewriteUnknown };
|
|
10182
10239
|
}
|
|
10183
10240
|
|
|
10241
|
+
// src/generated/experiment-filesystem.schema.json
|
|
10242
|
+
var experiment_filesystem_schema_default = {
|
|
10243
|
+
$id: "https://api.drip-apex.com/schemas/experiment-filesystem-v1.json",
|
|
10244
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10245
|
+
files: {
|
|
10246
|
+
"experiment.json": {
|
|
10247
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10248
|
+
additionalProperties: false,
|
|
10249
|
+
properties: {
|
|
10250
|
+
autoStopOverride: {
|
|
10251
|
+
anyOf: [
|
|
10252
|
+
{},
|
|
10253
|
+
{
|
|
10254
|
+
type: "null"
|
|
10255
|
+
}
|
|
10256
|
+
]
|
|
10257
|
+
},
|
|
10258
|
+
countingType: {
|
|
10259
|
+
anyOf: [
|
|
10260
|
+
{
|
|
10261
|
+
enum: ["standard", "setup_test", "aa_test", "non_program"],
|
|
10262
|
+
type: "string"
|
|
10263
|
+
},
|
|
10264
|
+
{
|
|
10265
|
+
type: "null"
|
|
10266
|
+
}
|
|
10267
|
+
]
|
|
10268
|
+
},
|
|
10269
|
+
description: {
|
|
10270
|
+
anyOf: [
|
|
10271
|
+
{
|
|
10272
|
+
type: "string"
|
|
10273
|
+
},
|
|
10274
|
+
{
|
|
10275
|
+
type: "null"
|
|
10276
|
+
}
|
|
10277
|
+
]
|
|
10278
|
+
},
|
|
10279
|
+
environmentKey: {
|
|
10280
|
+
type: "string"
|
|
10281
|
+
},
|
|
10282
|
+
experimentType: {
|
|
10283
|
+
enum: ["mutation", "redirect"],
|
|
10284
|
+
type: "string"
|
|
10285
|
+
},
|
|
10286
|
+
id: {
|
|
10287
|
+
anyOf: [
|
|
10288
|
+
{
|
|
10289
|
+
type: "string"
|
|
10290
|
+
},
|
|
10291
|
+
{
|
|
10292
|
+
type: "null"
|
|
10293
|
+
}
|
|
10294
|
+
]
|
|
10295
|
+
},
|
|
10296
|
+
name: {
|
|
10297
|
+
type: "string"
|
|
10298
|
+
},
|
|
10299
|
+
schemaVersion: {
|
|
10300
|
+
const: 1,
|
|
10301
|
+
type: "number"
|
|
10302
|
+
},
|
|
10303
|
+
sequentialTestingEnabled: {
|
|
10304
|
+
type: "boolean"
|
|
10305
|
+
},
|
|
10306
|
+
significanceLevel: {
|
|
10307
|
+
type: "number"
|
|
10308
|
+
},
|
|
10309
|
+
slug: {
|
|
10310
|
+
anyOf: [
|
|
10311
|
+
{
|
|
10312
|
+
type: "string"
|
|
10313
|
+
},
|
|
10314
|
+
{
|
|
10315
|
+
type: "null"
|
|
10316
|
+
}
|
|
10317
|
+
]
|
|
10318
|
+
},
|
|
10319
|
+
statisticalPower: {
|
|
10320
|
+
type: "number"
|
|
10321
|
+
},
|
|
10322
|
+
storeUrl: {
|
|
10323
|
+
anyOf: [
|
|
10324
|
+
{
|
|
10325
|
+
type: "string"
|
|
10326
|
+
},
|
|
10327
|
+
{
|
|
10328
|
+
type: "null"
|
|
10329
|
+
}
|
|
10330
|
+
]
|
|
10331
|
+
},
|
|
10332
|
+
testKey: {
|
|
10333
|
+
anyOf: [
|
|
10334
|
+
{
|
|
10335
|
+
type: "string"
|
|
10336
|
+
},
|
|
10337
|
+
{
|
|
10338
|
+
type: "null"
|
|
10339
|
+
}
|
|
10340
|
+
]
|
|
10341
|
+
},
|
|
10342
|
+
trafficAllocation: {
|
|
10343
|
+
maximum: 1,
|
|
10344
|
+
minimum: 0,
|
|
10345
|
+
type: "number"
|
|
10346
|
+
}
|
|
10347
|
+
},
|
|
10348
|
+
required: ["schemaVersion"],
|
|
10349
|
+
type: "object"
|
|
10350
|
+
},
|
|
10351
|
+
"experiment/index.css": {
|
|
10352
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10353
|
+
contentMediaType: "text/css",
|
|
10354
|
+
type: "string"
|
|
10355
|
+
},
|
|
10356
|
+
"experiment/index.js": {
|
|
10357
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10358
|
+
contentMediaType: "text/javascript",
|
|
10359
|
+
type: "string"
|
|
10360
|
+
},
|
|
10361
|
+
"experiment/reset.js": {
|
|
10362
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10363
|
+
contentMediaType: "text/javascript",
|
|
10364
|
+
type: "string"
|
|
10365
|
+
},
|
|
10366
|
+
"launch.json": {
|
|
10367
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10368
|
+
additionalProperties: false,
|
|
10369
|
+
properties: {
|
|
10370
|
+
endedAt: {
|
|
10371
|
+
anyOf: [
|
|
10372
|
+
{
|
|
10373
|
+
type: "string"
|
|
10374
|
+
},
|
|
10375
|
+
{
|
|
10376
|
+
type: "null"
|
|
10377
|
+
}
|
|
10378
|
+
]
|
|
10379
|
+
},
|
|
10380
|
+
launchApproval: {
|
|
10381
|
+
anyOf: [
|
|
10382
|
+
{
|
|
10383
|
+
additionalProperties: false,
|
|
10384
|
+
properties: {
|
|
10385
|
+
decidedAt: {
|
|
10386
|
+
anyOf: [
|
|
10387
|
+
{
|
|
10388
|
+
type: "string"
|
|
10389
|
+
},
|
|
10390
|
+
{
|
|
10391
|
+
type: "null"
|
|
10392
|
+
}
|
|
10393
|
+
]
|
|
10394
|
+
},
|
|
10395
|
+
note: {
|
|
10396
|
+
anyOf: [
|
|
10397
|
+
{
|
|
10398
|
+
type: "string"
|
|
10399
|
+
},
|
|
10400
|
+
{
|
|
10401
|
+
type: "null"
|
|
10402
|
+
}
|
|
10403
|
+
]
|
|
10404
|
+
},
|
|
10405
|
+
status: {
|
|
10406
|
+
type: "string"
|
|
10407
|
+
}
|
|
10408
|
+
},
|
|
10409
|
+
required: ["status", "decidedAt", "note"],
|
|
10410
|
+
type: "object"
|
|
10411
|
+
},
|
|
10412
|
+
{
|
|
10413
|
+
type: "null"
|
|
10414
|
+
}
|
|
10415
|
+
]
|
|
10416
|
+
},
|
|
10417
|
+
launchGate: {
|
|
10418
|
+
additionalProperties: false,
|
|
10419
|
+
properties: {
|
|
10420
|
+
qaApproved: {
|
|
10421
|
+
type: "boolean"
|
|
10422
|
+
},
|
|
10423
|
+
treatmentArtifactsApproved: {
|
|
10424
|
+
type: "boolean"
|
|
10425
|
+
}
|
|
10426
|
+
},
|
|
10427
|
+
required: ["qaApproved", "treatmentArtifactsApproved"],
|
|
10428
|
+
type: "object"
|
|
10429
|
+
},
|
|
10430
|
+
readonly: {
|
|
10431
|
+
const: true,
|
|
10432
|
+
type: "boolean"
|
|
10433
|
+
},
|
|
10434
|
+
scheduledEndAt: {
|
|
10435
|
+
anyOf: [
|
|
10436
|
+
{
|
|
10437
|
+
type: "string"
|
|
10438
|
+
},
|
|
10439
|
+
{
|
|
10440
|
+
type: "null"
|
|
10441
|
+
}
|
|
10442
|
+
]
|
|
10443
|
+
},
|
|
10444
|
+
scheduledStartAt: {
|
|
10445
|
+
anyOf: [
|
|
10446
|
+
{
|
|
10447
|
+
type: "string"
|
|
10448
|
+
},
|
|
10449
|
+
{
|
|
10450
|
+
type: "null"
|
|
10451
|
+
}
|
|
10452
|
+
]
|
|
10453
|
+
},
|
|
10454
|
+
schemaVersion: {
|
|
10455
|
+
const: 1,
|
|
10456
|
+
type: "number"
|
|
10457
|
+
},
|
|
10458
|
+
startedAt: {
|
|
10459
|
+
anyOf: [
|
|
10460
|
+
{
|
|
10461
|
+
type: "string"
|
|
10462
|
+
},
|
|
10463
|
+
{
|
|
10464
|
+
type: "null"
|
|
10465
|
+
}
|
|
10466
|
+
]
|
|
10467
|
+
},
|
|
10468
|
+
status: {
|
|
10469
|
+
type: "string"
|
|
10470
|
+
}
|
|
10471
|
+
},
|
|
10472
|
+
readOnly: true,
|
|
10473
|
+
required: [
|
|
10474
|
+
"schemaVersion",
|
|
10475
|
+
"readonly",
|
|
10476
|
+
"status",
|
|
10477
|
+
"scheduledStartAt",
|
|
10478
|
+
"scheduledEndAt",
|
|
10479
|
+
"startedAt",
|
|
10480
|
+
"endedAt",
|
|
10481
|
+
"launchApproval",
|
|
10482
|
+
"launchGate"
|
|
10483
|
+
],
|
|
10484
|
+
type: "object"
|
|
10485
|
+
},
|
|
10486
|
+
"metrics.json": {
|
|
10487
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10488
|
+
additionalProperties: false,
|
|
10489
|
+
properties: {
|
|
10490
|
+
goals: {
|
|
10491
|
+
items: {
|
|
10492
|
+
additionalProperties: false,
|
|
10493
|
+
properties: {
|
|
10494
|
+
capture: {
|
|
10495
|
+
anyOf: [
|
|
10496
|
+
{},
|
|
10497
|
+
{
|
|
10498
|
+
type: "null"
|
|
10499
|
+
}
|
|
10500
|
+
]
|
|
10501
|
+
},
|
|
10502
|
+
countOnce: {
|
|
10503
|
+
type: "boolean"
|
|
10504
|
+
},
|
|
10505
|
+
eventName: {
|
|
10506
|
+
anyOf: [
|
|
10507
|
+
{
|
|
10508
|
+
type: "string"
|
|
10509
|
+
},
|
|
10510
|
+
{
|
|
10511
|
+
type: "null"
|
|
10512
|
+
}
|
|
10513
|
+
]
|
|
10514
|
+
},
|
|
10515
|
+
filter: {
|
|
10516
|
+
anyOf: [
|
|
10517
|
+
{},
|
|
10518
|
+
{
|
|
10519
|
+
type: "null"
|
|
10520
|
+
}
|
|
10521
|
+
]
|
|
10522
|
+
},
|
|
10523
|
+
id: {
|
|
10524
|
+
anyOf: [
|
|
10525
|
+
{
|
|
10526
|
+
type: "string"
|
|
10527
|
+
},
|
|
10528
|
+
{
|
|
10529
|
+
type: "null"
|
|
10530
|
+
}
|
|
10531
|
+
]
|
|
10532
|
+
},
|
|
10533
|
+
isPrimary: {
|
|
10534
|
+
type: "boolean"
|
|
10535
|
+
},
|
|
10536
|
+
measurement: {},
|
|
10537
|
+
name: {
|
|
10538
|
+
type: "string"
|
|
10539
|
+
},
|
|
10540
|
+
pageId: {
|
|
10541
|
+
anyOf: [
|
|
10542
|
+
{
|
|
10543
|
+
type: "string"
|
|
10544
|
+
},
|
|
10545
|
+
{
|
|
10546
|
+
type: "null"
|
|
10547
|
+
}
|
|
10548
|
+
]
|
|
10549
|
+
},
|
|
10550
|
+
selector: {
|
|
10551
|
+
anyOf: [
|
|
10552
|
+
{
|
|
10553
|
+
type: "string"
|
|
10554
|
+
},
|
|
10555
|
+
{
|
|
10556
|
+
type: "null"
|
|
10557
|
+
}
|
|
10558
|
+
]
|
|
10559
|
+
},
|
|
10560
|
+
textMatch: {
|
|
10561
|
+
anyOf: [
|
|
10562
|
+
{
|
|
10563
|
+
type: "string"
|
|
10564
|
+
},
|
|
10565
|
+
{
|
|
10566
|
+
type: "null"
|
|
10567
|
+
}
|
|
10568
|
+
]
|
|
10569
|
+
},
|
|
10570
|
+
type: {
|
|
10571
|
+
enum: ["click", "pageview", "custom", "revenue"],
|
|
10572
|
+
type: "string"
|
|
10573
|
+
},
|
|
10574
|
+
urlPattern: {
|
|
10575
|
+
anyOf: [
|
|
10576
|
+
{
|
|
10577
|
+
type: "string"
|
|
10578
|
+
},
|
|
10579
|
+
{
|
|
10580
|
+
type: "null"
|
|
10581
|
+
}
|
|
10582
|
+
]
|
|
10583
|
+
},
|
|
10584
|
+
valueProperty: {
|
|
10585
|
+
anyOf: [
|
|
10586
|
+
{
|
|
10587
|
+
type: "string"
|
|
10588
|
+
},
|
|
10589
|
+
{
|
|
10590
|
+
type: "null"
|
|
10591
|
+
}
|
|
10592
|
+
]
|
|
10593
|
+
},
|
|
10594
|
+
valueUnit: {
|
|
10595
|
+
anyOf: [
|
|
10596
|
+
{
|
|
10597
|
+
type: "string"
|
|
10598
|
+
},
|
|
10599
|
+
{
|
|
10600
|
+
type: "null"
|
|
10601
|
+
}
|
|
10602
|
+
]
|
|
10603
|
+
}
|
|
10604
|
+
},
|
|
10605
|
+
required: ["name", "type"],
|
|
10606
|
+
type: "object"
|
|
10607
|
+
},
|
|
10608
|
+
type: "array"
|
|
10609
|
+
},
|
|
10610
|
+
primaryGoalId: {
|
|
10611
|
+
anyOf: [
|
|
10612
|
+
{
|
|
10613
|
+
type: "string"
|
|
10614
|
+
},
|
|
10615
|
+
{
|
|
10616
|
+
type: "null"
|
|
10617
|
+
}
|
|
10618
|
+
]
|
|
10619
|
+
},
|
|
10620
|
+
schemaVersion: {
|
|
10621
|
+
const: 1,
|
|
10622
|
+
type: "number"
|
|
10623
|
+
}
|
|
10624
|
+
},
|
|
10625
|
+
required: ["schemaVersion", "primaryGoalId", "goals"],
|
|
10626
|
+
type: "object"
|
|
10627
|
+
},
|
|
10628
|
+
"qa.json": {
|
|
10629
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10630
|
+
additionalProperties: false,
|
|
10631
|
+
properties: {
|
|
10632
|
+
latestRun: {
|
|
10633
|
+
anyOf: [
|
|
10634
|
+
{
|
|
10635
|
+
additionalProperties: false,
|
|
10636
|
+
properties: {
|
|
10637
|
+
approvedAt: {
|
|
10638
|
+
anyOf: [
|
|
10639
|
+
{
|
|
10640
|
+
type: "string"
|
|
10641
|
+
},
|
|
10642
|
+
{
|
|
10643
|
+
type: "null"
|
|
10644
|
+
}
|
|
10645
|
+
]
|
|
10646
|
+
},
|
|
10647
|
+
completedAt: {
|
|
10648
|
+
anyOf: [
|
|
10649
|
+
{
|
|
10650
|
+
type: "string"
|
|
10651
|
+
},
|
|
10652
|
+
{
|
|
10653
|
+
type: "null"
|
|
10654
|
+
}
|
|
10655
|
+
]
|
|
10656
|
+
},
|
|
10657
|
+
id: {
|
|
10658
|
+
type: "string"
|
|
10659
|
+
},
|
|
10660
|
+
source: {
|
|
10661
|
+
type: "string"
|
|
10662
|
+
},
|
|
10663
|
+
status: {
|
|
10664
|
+
type: "string"
|
|
10665
|
+
},
|
|
10666
|
+
summary: {
|
|
10667
|
+
anyOf: [
|
|
10668
|
+
{},
|
|
10669
|
+
{
|
|
10670
|
+
type: "null"
|
|
10671
|
+
}
|
|
10672
|
+
]
|
|
10673
|
+
}
|
|
10674
|
+
},
|
|
10675
|
+
required: ["id", "status", "source", "approvedAt", "completedAt", "summary"],
|
|
10676
|
+
type: "object"
|
|
10677
|
+
},
|
|
10678
|
+
{
|
|
10679
|
+
type: "null"
|
|
10680
|
+
}
|
|
10681
|
+
]
|
|
10682
|
+
},
|
|
10683
|
+
qaApprovedAt: {
|
|
10684
|
+
anyOf: [
|
|
10685
|
+
{
|
|
10686
|
+
type: "string"
|
|
10687
|
+
},
|
|
10688
|
+
{
|
|
10689
|
+
type: "null"
|
|
10690
|
+
}
|
|
10691
|
+
]
|
|
10692
|
+
},
|
|
10693
|
+
qaApprovedBy: {
|
|
10694
|
+
anyOf: [
|
|
10695
|
+
{
|
|
10696
|
+
type: "string"
|
|
10697
|
+
},
|
|
10698
|
+
{
|
|
10699
|
+
type: "null"
|
|
10700
|
+
}
|
|
10701
|
+
]
|
|
10702
|
+
},
|
|
10703
|
+
readonly: {
|
|
10704
|
+
const: true,
|
|
10705
|
+
type: "boolean"
|
|
10706
|
+
},
|
|
10707
|
+
schemaVersion: {
|
|
10708
|
+
const: 1,
|
|
10709
|
+
type: "number"
|
|
10710
|
+
}
|
|
10711
|
+
},
|
|
10712
|
+
readOnly: true,
|
|
10713
|
+
required: ["schemaVersion", "readonly", "qaApprovedAt", "qaApprovedBy", "latestRun"],
|
|
10714
|
+
type: "object"
|
|
10715
|
+
},
|
|
10716
|
+
"targeting.json": {
|
|
10717
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10718
|
+
additionalProperties: {},
|
|
10719
|
+
properties: {
|
|
10720
|
+
authorUrl: {
|
|
10721
|
+
items: {
|
|
10722
|
+
additionalProperties: false,
|
|
10723
|
+
properties: {
|
|
10724
|
+
include: {
|
|
10725
|
+
type: "boolean"
|
|
10726
|
+
},
|
|
10727
|
+
match_type: {
|
|
10728
|
+
enum: ["exact", "contains", "wildcard", "regex"],
|
|
10729
|
+
type: "string"
|
|
10730
|
+
},
|
|
10731
|
+
matchType: {
|
|
10732
|
+
enum: ["exact", "contains", "wildcard", "regex"],
|
|
10733
|
+
type: "string"
|
|
10734
|
+
},
|
|
10735
|
+
pattern: {
|
|
10736
|
+
minLength: 1,
|
|
10737
|
+
type: "string"
|
|
10738
|
+
},
|
|
10739
|
+
type: {
|
|
10740
|
+
enum: ["regex", "simple"],
|
|
10741
|
+
type: "string"
|
|
10742
|
+
}
|
|
10743
|
+
},
|
|
10744
|
+
required: ["type", "pattern"],
|
|
10745
|
+
type: "object"
|
|
10746
|
+
},
|
|
10747
|
+
type: "array"
|
|
10748
|
+
},
|
|
10749
|
+
custom: {},
|
|
10750
|
+
device: {},
|
|
10751
|
+
deviceType: {
|
|
10752
|
+
type: "string"
|
|
10753
|
+
},
|
|
10754
|
+
lifecycle: {},
|
|
10755
|
+
pageRules: {
|
|
10756
|
+
items: {},
|
|
10757
|
+
type: "array"
|
|
10758
|
+
},
|
|
10759
|
+
pages: {
|
|
10760
|
+
items: {},
|
|
10761
|
+
type: "array"
|
|
10762
|
+
},
|
|
10763
|
+
segments: {
|
|
10764
|
+
items: {},
|
|
10765
|
+
type: "array"
|
|
10766
|
+
},
|
|
10767
|
+
url: {
|
|
10768
|
+
items: {
|
|
10769
|
+
additionalProperties: false,
|
|
10770
|
+
properties: {
|
|
10771
|
+
include: {
|
|
10772
|
+
type: "boolean"
|
|
10773
|
+
},
|
|
10774
|
+
match_type: {
|
|
10775
|
+
enum: ["exact", "contains", "wildcard", "regex"],
|
|
10776
|
+
type: "string"
|
|
10777
|
+
},
|
|
10778
|
+
matchType: {
|
|
10779
|
+
enum: ["exact", "contains", "wildcard", "regex"],
|
|
10780
|
+
type: "string"
|
|
10781
|
+
},
|
|
10782
|
+
pattern: {
|
|
10783
|
+
minLength: 1,
|
|
10784
|
+
type: "string"
|
|
10785
|
+
},
|
|
10786
|
+
type: {
|
|
10787
|
+
enum: ["regex", "simple"],
|
|
10788
|
+
type: "string"
|
|
10789
|
+
}
|
|
10790
|
+
},
|
|
10791
|
+
required: ["type", "pattern"],
|
|
10792
|
+
type: "object"
|
|
10793
|
+
},
|
|
10794
|
+
type: "array"
|
|
10795
|
+
}
|
|
10796
|
+
},
|
|
10797
|
+
type: "object"
|
|
10798
|
+
},
|
|
10799
|
+
"variations/*/anti-flicker.json": {
|
|
10800
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10801
|
+
items: {
|
|
10802
|
+
type: "string"
|
|
10803
|
+
},
|
|
10804
|
+
type: "array"
|
|
10805
|
+
},
|
|
10806
|
+
"variations/*/index.css": {
|
|
10807
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10808
|
+
contentMediaType: "text/css",
|
|
10809
|
+
type: "string"
|
|
10810
|
+
},
|
|
10811
|
+
"variations/*/index.js": {
|
|
10812
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10813
|
+
contentMediaType: "text/javascript",
|
|
10814
|
+
type: "string"
|
|
10815
|
+
},
|
|
10816
|
+
"variations/*/mutations.json": {
|
|
10817
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10818
|
+
items: {
|
|
10819
|
+
additionalProperties: {},
|
|
10820
|
+
anyOf: [
|
|
10821
|
+
{
|
|
10822
|
+
required: ["selector"]
|
|
10823
|
+
},
|
|
10824
|
+
{
|
|
10825
|
+
properties: {
|
|
10826
|
+
action: {
|
|
10827
|
+
enum: [
|
|
10828
|
+
"priceTest",
|
|
10829
|
+
"shippingTest",
|
|
10830
|
+
"offerTest",
|
|
10831
|
+
"postPurchaseOffer",
|
|
10832
|
+
"checkoutBlock"
|
|
10833
|
+
]
|
|
10834
|
+
}
|
|
10835
|
+
},
|
|
10836
|
+
required: ["action"]
|
|
10837
|
+
}
|
|
10838
|
+
],
|
|
10839
|
+
properties: {
|
|
10840
|
+
action: {
|
|
10841
|
+
type: "string"
|
|
10842
|
+
},
|
|
10843
|
+
selector: {
|
|
10844
|
+
minLength: 1,
|
|
10845
|
+
type: "string"
|
|
10846
|
+
},
|
|
10847
|
+
type: {
|
|
10848
|
+
type: "string"
|
|
10849
|
+
}
|
|
10850
|
+
},
|
|
10851
|
+
type: "object"
|
|
10852
|
+
},
|
|
10853
|
+
type: "array"
|
|
10854
|
+
},
|
|
10855
|
+
"variations/*/reset.js": {
|
|
10856
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10857
|
+
contentMediaType: "text/javascript",
|
|
10858
|
+
type: "string"
|
|
10859
|
+
},
|
|
10860
|
+
"variations/*/url-blocks.json": {
|
|
10861
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10862
|
+
items: {},
|
|
10863
|
+
type: "array"
|
|
10864
|
+
},
|
|
10865
|
+
"variations/*/variation.json": {
|
|
10866
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
10867
|
+
additionalProperties: false,
|
|
10868
|
+
properties: {
|
|
10869
|
+
artifactReview: {
|
|
10870
|
+
additionalProperties: false,
|
|
10871
|
+
properties: {
|
|
10872
|
+
hash: {
|
|
10873
|
+
anyOf: [
|
|
10874
|
+
{
|
|
10875
|
+
type: "string"
|
|
10876
|
+
},
|
|
10877
|
+
{
|
|
10878
|
+
type: "null"
|
|
10879
|
+
}
|
|
10880
|
+
]
|
|
10881
|
+
},
|
|
10882
|
+
reviewedAt: {
|
|
10883
|
+
anyOf: [
|
|
10884
|
+
{
|
|
10885
|
+
type: "string"
|
|
10886
|
+
},
|
|
10887
|
+
{
|
|
10888
|
+
type: "null"
|
|
10889
|
+
}
|
|
10890
|
+
]
|
|
10891
|
+
},
|
|
10892
|
+
reviewedBy: {
|
|
10893
|
+
anyOf: [
|
|
10894
|
+
{
|
|
10895
|
+
type: "string"
|
|
10896
|
+
},
|
|
10897
|
+
{
|
|
10898
|
+
type: "null"
|
|
10899
|
+
}
|
|
10900
|
+
]
|
|
10901
|
+
},
|
|
10902
|
+
source: {
|
|
10903
|
+
anyOf: [
|
|
10904
|
+
{
|
|
10905
|
+
type: "string"
|
|
10906
|
+
},
|
|
10907
|
+
{
|
|
10908
|
+
type: "null"
|
|
10909
|
+
}
|
|
10910
|
+
]
|
|
10911
|
+
},
|
|
10912
|
+
status: {
|
|
10913
|
+
type: "string"
|
|
10914
|
+
}
|
|
10915
|
+
},
|
|
10916
|
+
required: ["status"],
|
|
10917
|
+
type: "object"
|
|
10918
|
+
},
|
|
10919
|
+
codeDeliveryMode: {
|
|
10920
|
+
enum: ["inline", "external"],
|
|
10921
|
+
type: "string"
|
|
10922
|
+
},
|
|
10923
|
+
cssArtifactId: {
|
|
10924
|
+
anyOf: [
|
|
10925
|
+
{
|
|
10926
|
+
type: "string"
|
|
10927
|
+
},
|
|
10928
|
+
{
|
|
10929
|
+
type: "null"
|
|
10930
|
+
}
|
|
10931
|
+
]
|
|
10932
|
+
},
|
|
10933
|
+
id: {
|
|
10934
|
+
anyOf: [
|
|
10935
|
+
{
|
|
10936
|
+
type: "string"
|
|
10937
|
+
},
|
|
10938
|
+
{
|
|
10939
|
+
type: "null"
|
|
10940
|
+
}
|
|
10941
|
+
]
|
|
10942
|
+
},
|
|
10943
|
+
isControl: {
|
|
10944
|
+
type: "boolean"
|
|
10945
|
+
},
|
|
10946
|
+
jsArtifactId: {
|
|
10947
|
+
anyOf: [
|
|
10948
|
+
{
|
|
10949
|
+
type: "string"
|
|
10950
|
+
},
|
|
10951
|
+
{
|
|
10952
|
+
type: "null"
|
|
10953
|
+
}
|
|
10954
|
+
]
|
|
10955
|
+
},
|
|
10956
|
+
name: {
|
|
10957
|
+
type: "string"
|
|
10958
|
+
},
|
|
10959
|
+
redirectUrl: {
|
|
10960
|
+
anyOf: [
|
|
10961
|
+
{
|
|
10962
|
+
type: "string"
|
|
10963
|
+
},
|
|
10964
|
+
{
|
|
10965
|
+
type: "null"
|
|
10966
|
+
}
|
|
10967
|
+
]
|
|
10968
|
+
},
|
|
10969
|
+
schemaVersion: {
|
|
10970
|
+
const: 1,
|
|
10971
|
+
type: "number"
|
|
10972
|
+
},
|
|
10973
|
+
slug: {
|
|
10974
|
+
type: "string"
|
|
10975
|
+
},
|
|
10976
|
+
weight: {
|
|
10977
|
+
maximum: 1,
|
|
10978
|
+
minimum: 0,
|
|
10979
|
+
type: "number"
|
|
10980
|
+
}
|
|
10981
|
+
},
|
|
10982
|
+
required: ["schemaVersion"],
|
|
10983
|
+
type: "object"
|
|
10984
|
+
}
|
|
10985
|
+
},
|
|
10986
|
+
schemaVersion: 1,
|
|
10987
|
+
source: "experiment-filesystem"
|
|
10988
|
+
};
|
|
10989
|
+
|
|
10184
10990
|
// src/commands/experiments.ts
|
|
10185
10991
|
function formatDate(iso) {
|
|
10186
10992
|
return new Date(iso).toLocaleDateString("en-US", {
|
|
@@ -10244,6 +11050,13 @@ function formatRevenue(value, currency) {
|
|
|
10244
11050
|
return String(value);
|
|
10245
11051
|
}
|
|
10246
11052
|
}
|
|
11053
|
+
function audienceLine(segmentApplied) {
|
|
11054
|
+
if (!segmentApplied || typeof segmentApplied !== "object") return null;
|
|
11055
|
+
const { requested, applied, reason: reason2 } = segmentApplied;
|
|
11056
|
+
if (!requested) return null;
|
|
11057
|
+
const label = `${requested.mode === "exclude" ? "excluding " : ""}${String(requested.dim)}=${String(requested.value)}`;
|
|
11058
|
+
return applied === true ? label : `all visitors (${label} not applied: ${typeof reason2 === "string" ? reason2 : "unknown reason"})`;
|
|
11059
|
+
}
|
|
10247
11060
|
function printExperimentResults(results2, currency) {
|
|
10248
11061
|
const summary = summarizeResults(results2);
|
|
10249
11062
|
const { experiment: experiment2, totals, decision, verdictWithheld, statisticsState, presentedOutcome } = summary;
|
|
@@ -10251,6 +11064,8 @@ function printExperimentResults(results2, currency) {
|
|
|
10251
11064
|
console.log();
|
|
10252
11065
|
console.log(source_default.bold(String(experiment2.name ?? experiment2.id ?? "Experiment results")));
|
|
10253
11066
|
console.log(` Status: ${statusBadge(String(experiment2.status ?? "unknown"))}`);
|
|
11067
|
+
const audience = audienceLine(results2.segment_applied);
|
|
11068
|
+
if (audience) console.log(` Audience: ${audience}`);
|
|
10254
11069
|
console.log(` Visitors: ${String(totals.visitors ?? 0)}`);
|
|
10255
11070
|
console.log(` Conversions: ${String(totals.primaryConversions ?? 0)}`);
|
|
10256
11071
|
console.log(` Revenue: ${formatRevenue(totals.revenue, currency)}`);
|
|
@@ -10314,18 +11129,11 @@ function printExperimentResults(results2, currency) {
|
|
|
10314
11129
|
}
|
|
10315
11130
|
console.log();
|
|
10316
11131
|
}
|
|
11132
|
+
var filesystemPaths = Object.keys(experiment_filesystem_schema_default.files);
|
|
10317
11133
|
var EXPERIMENT_FILESYSTEM_PATH_SCHEMA = {
|
|
10318
|
-
topLevel:
|
|
10319
|
-
experiment:
|
|
10320
|
-
variation:
|
|
10321
|
-
"variation.json",
|
|
10322
|
-
"mutations.json",
|
|
10323
|
-
"url-blocks.json",
|
|
10324
|
-
"index.css",
|
|
10325
|
-
"index.js",
|
|
10326
|
-
"reset.js",
|
|
10327
|
-
"anti-flicker.json"
|
|
10328
|
-
]
|
|
11134
|
+
topLevel: filesystemPaths.filter((entry) => !entry.includes("/")),
|
|
11135
|
+
experiment: filesystemPaths.filter((entry) => entry.startsWith("experiment/")).map((entry) => entry.slice("experiment/".length)),
|
|
11136
|
+
variation: filesystemPaths.filter((entry) => entry.startsWith("variations/*/")).map((entry) => entry.slice("variations/*/".length))
|
|
10329
11137
|
};
|
|
10330
11138
|
var SERVER_OWNED_EXPERIMENT_FILES = /* @__PURE__ */ new Set(["qa.json", "launch.json"]);
|
|
10331
11139
|
var escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -10777,20 +11585,31 @@ var list = new Command("list").alias("ls").description(
|
|
|
10777
11585
|
"List experiments in summary view by default; use --full for details or --fields for selected columns (archived experiments are hidden by default)"
|
|
10778
11586
|
).option(
|
|
10779
11587
|
"-s, --status <status>",
|
|
10780
|
-
"Filter by status (draft|awaiting_client_approval|changes_requested|client_approved|qa|ready_to_launch|running|paused|completed)"
|
|
11588
|
+
"Filter by status (draft|awaiting_client_approval|changes_requested|client_approved|qa|ready_to_launch|running|paused|completed) (applied server-side)"
|
|
11589
|
+
).option(
|
|
11590
|
+
"--url <absolute-url>",
|
|
11591
|
+
"Filter by effective storefront URL targeting (applied server-side)"
|
|
10781
11592
|
).option("-n, --limit <n>", "Max results", "20").option("--include-archived", "Include archived experiments").option("--full", "Return full experiment details instead of the default summary").option(
|
|
10782
11593
|
"--fields <list>",
|
|
10783
11594
|
"Comma-separated fields to return and table columns in order (JSON always keeps id)"
|
|
10784
11595
|
).action(async function action3(opts) {
|
|
10785
11596
|
const creds = requireCredentials();
|
|
10786
11597
|
const spinner = await createSpinner("Fetching experiments...");
|
|
10787
|
-
const
|
|
11598
|
+
const listDefault = () => listExperiments(creds, {
|
|
10788
11599
|
status: opts.status,
|
|
10789
11600
|
limit: parseInt(opts.limit, 10),
|
|
10790
11601
|
includeArchived: opts.includeArchived,
|
|
10791
11602
|
view: opts.full ? "full" : "summary",
|
|
10792
11603
|
fields: opts.fields
|
|
10793
11604
|
});
|
|
11605
|
+
const res = opts.url !== void 0 ? await listExperiments(creds, {
|
|
11606
|
+
status: opts.status,
|
|
11607
|
+
limit: parseInt(opts.limit, 10),
|
|
11608
|
+
includeArchived: opts.includeArchived,
|
|
11609
|
+
view: opts.full ? "full" : "summary",
|
|
11610
|
+
fields: opts.fields,
|
|
11611
|
+
url: opts.url
|
|
11612
|
+
}) : await listDefault();
|
|
10794
11613
|
if (!res.ok) {
|
|
10795
11614
|
spinner?.fail("Failed to fetch experiments");
|
|
10796
11615
|
fail(this, res.error, classifyStatus(res.status), res.errorDetails);
|
|
@@ -10928,7 +11747,13 @@ ${JSON.stringify(data.order, null, 2)}`);
|
|
|
10928
11747
|
console.log(`
|
|
10929
11748
|
Definitions: ${data.definitions_url}`);
|
|
10930
11749
|
}
|
|
10931
|
-
var results = new Command("results").description("Read experiment results and timeseries by ID or slug").argument("<id-or-slug>", EXPERIMENT_REFERENCE_DESCRIPTION).option("--currency <code>", "Currency code for revenue formatting").option("--explain", "Explain raw-event exclusions and residuals").option("--goal <id>", "Goal ID or event key for --explain").option("--order <key>", "Order label trail for --explain").option("--samples", "Show sample identifiers with --explain").action(async function action7(idOrSlug, opts) {
|
|
11750
|
+
var results = new Command("results").description("Read experiment results and timeseries by ID or slug").argument("<id-or-slug>", EXPERIMENT_REFERENCE_DESCRIPTION).option("--currency <code>", "Currency code for revenue formatting").option("--segment <dim:value>", "Include one audience segment").option("--exclude-segment <dim:value>", "Exclude one audience segment (include wins)").option("--explain", "Explain raw-event exclusions and residuals").option("--goal <id>", "Goal ID or event key for --explain").option("--order <key>", "Order label trail for --explain").option("--samples", "Show sample identifiers with --explain").action(async function action7(idOrSlug, opts) {
|
|
11751
|
+
if (opts.explain && (opts.segment !== void 0 || opts.excludeSegment !== void 0))
|
|
11752
|
+
fail(
|
|
11753
|
+
this,
|
|
11754
|
+
"--segment and --exclude-segment are only available for results, without --explain",
|
|
11755
|
+
EXIT_CODES.validation
|
|
11756
|
+
);
|
|
10932
11757
|
if (!opts.explain && (opts.goal || opts.order || opts.samples))
|
|
10933
11758
|
fail(this, "--goal, --order and --samples require --explain", EXIT_CODES.validation);
|
|
10934
11759
|
const creds = requireCredentials();
|
|
@@ -10939,7 +11764,11 @@ var results = new Command("results").description("Read experiment results and ti
|
|
|
10939
11764
|
spinner?.fail(`Experiment "${idOrSlug}" not found`);
|
|
10940
11765
|
fail(this, `Experiment "${idOrSlug}" not found.`, EXIT_CODES.validation);
|
|
10941
11766
|
}
|
|
10942
|
-
const res = opts.explain ? await getExperimentResultsExplain(creds, exp.id, opts) : await getExperimentResults(creds, exp.id, {
|
|
11767
|
+
const res = opts.explain ? await getExperimentResultsExplain(creds, exp.id, opts) : await getExperimentResults(creds, exp.id, {
|
|
11768
|
+
currency: opts.currency,
|
|
11769
|
+
segment: opts.segment,
|
|
11770
|
+
exclude_segment: opts.excludeSegment
|
|
11771
|
+
});
|
|
10943
11772
|
if (!res.ok || !res.data) {
|
|
10944
11773
|
spinner?.fail("Failed to fetch experiment results");
|
|
10945
11774
|
fail(
|
|
@@ -11213,7 +12042,7 @@ var create = new Command("create").description(
|
|
|
11213
12042
|
[]
|
|
11214
12043
|
).option(
|
|
11215
12044
|
"--goal <goal-id|new:fields>",
|
|
11216
|
-
"Goal id or new:type=...,selector=...,name=... (repeatable)",
|
|
12045
|
+
"Goal id or new:type=...,selector=...,name=... (repeatable; omitted uses the shop default main goal)",
|
|
11217
12046
|
collectCreateOption,
|
|
11218
12047
|
[]
|
|
11219
12048
|
).option(
|
|
@@ -11632,6 +12461,7 @@ var pullFilesystem = new Command("pull").description("Pull an experiment as an e
|
|
|
11632
12461
|
output(
|
|
11633
12462
|
this,
|
|
11634
12463
|
{
|
|
12464
|
+
schemaVersion: 1,
|
|
11635
12465
|
folder,
|
|
11636
12466
|
experimentId: exp.id,
|
|
11637
12467
|
files: res.data.files.map((file) => import_node_path6.default.join(folder, file.path))
|
|
@@ -12460,7 +13290,55 @@ var qaEvidence = new Command("evidence").description("Attach screenshot jobs or
|
|
|
12460
13290
|
throw error;
|
|
12461
13291
|
}
|
|
12462
13292
|
});
|
|
12463
|
-
var qa = new Command("qa").description("Manage experiment QA runs from the CLI").addCommand(qaStatus).addCommand(
|
|
13293
|
+
var qa = new Command("qa").description("Manage experiment QA runs from the CLI").addCommand(qaStatus).addCommand(
|
|
13294
|
+
new Command("events").description("List QA-tagged events for an experiment session").argument("<id-or-slug>", EXPERIMENT_REFERENCE_DESCRIPTION).option("--session <id>", "QA session id (defaults to the latest QA run)").option("--minutes <n>", "Lookback window in minutes", "60").option("--type <type>", "Event type: all, goal, or custom", "all").action(async function(target, opts) {
|
|
13295
|
+
const minutes = Number(opts.minutes);
|
|
13296
|
+
if (!Number.isInteger(minutes) || minutes < 5 || minutes > 1440)
|
|
13297
|
+
fail(this, "--minutes must be an integer between 5 and 1440", EXIT_CODES.validation);
|
|
13298
|
+
if (!["all", "goal", "custom"].includes(opts.type))
|
|
13299
|
+
fail(this, "--type must be all, goal, or custom", EXIT_CODES.validation);
|
|
13300
|
+
const creds = requireCredentials();
|
|
13301
|
+
const experiment2 = { id: (await resolveExperimentForFilesystemOrId(target)).experimentId };
|
|
13302
|
+
let session = opts.session;
|
|
13303
|
+
if (!session) {
|
|
13304
|
+
const status4 = await getExperimentQaRun(creds, experiment2.id);
|
|
13305
|
+
if (!status4.ok || !status4.data)
|
|
13306
|
+
throw new CliError(
|
|
13307
|
+
status4.error ?? "Failed to fetch QA run",
|
|
13308
|
+
classifyStatus(status4.status),
|
|
13309
|
+
status4.errorDetails
|
|
13310
|
+
);
|
|
13311
|
+
session = status4.data.run.id;
|
|
13312
|
+
}
|
|
13313
|
+
const response = await getExperimentQaEvents(creds, experiment2.id, {
|
|
13314
|
+
session,
|
|
13315
|
+
minutes,
|
|
13316
|
+
type: opts.type
|
|
13317
|
+
});
|
|
13318
|
+
if (!response.ok || !response.data)
|
|
13319
|
+
throw new CliError(
|
|
13320
|
+
response.error ?? "Failed to fetch QA events",
|
|
13321
|
+
classifyStatus(response.status),
|
|
13322
|
+
response.errorDetails
|
|
13323
|
+
);
|
|
13324
|
+
output(
|
|
13325
|
+
this,
|
|
13326
|
+
response.data,
|
|
13327
|
+
() => printTable(
|
|
13328
|
+
["TYPE", "EVENT", "VARIATION", "SESSION", "COUNT", "LAST SEEN", "LAST URL"],
|
|
13329
|
+
response.data.data.map((row) => [
|
|
13330
|
+
row.event_type === "goal" ? "goal" : "custom",
|
|
13331
|
+
row.event_name || row.goal_id,
|
|
13332
|
+
row.variation_id,
|
|
13333
|
+
row.qa_session_id,
|
|
13334
|
+
String(row.events),
|
|
13335
|
+
row.last_event_at ?? "\u2014",
|
|
13336
|
+
row.last_url ?? "\u2014"
|
|
13337
|
+
])
|
|
13338
|
+
)
|
|
13339
|
+
);
|
|
13340
|
+
})
|
|
13341
|
+
).addCommand(qaCheck).addCommand(qaNotes).addCommand(qaApprove).addCommand(qaReopen).addCommand(qaEvidence);
|
|
12464
13342
|
var SCREENSHOT_DEVICES = [
|
|
12465
13343
|
"desktop_chrome",
|
|
12466
13344
|
"iphone_15_pro",
|
|
@@ -13246,9 +14124,21 @@ var previewCommand = new Command("preview").description(
|
|
|
13246
14124
|
'Experiment is missing "store_url". Set it on the experiment or pass --store-url <url>.'
|
|
13247
14125
|
);
|
|
13248
14126
|
}
|
|
14127
|
+
const snapshot = await getExperimentFilesystem(creds, exp.id).catch(() => null);
|
|
14128
|
+
let qaRun;
|
|
14129
|
+
if (snapshot?.ok && snapshot.data) {
|
|
14130
|
+
const qaFile = snapshot.data.files.find((file) => file.path === "qa.json");
|
|
14131
|
+
if (qaFile) {
|
|
14132
|
+
try {
|
|
14133
|
+
const run3 = JSON.parse(qaFile.content)?.latestRun;
|
|
14134
|
+
if (run3 && typeof run3.id === "string" && run3.id.trim()) qaRun = run3;
|
|
14135
|
+
} catch {
|
|
14136
|
+
}
|
|
14137
|
+
}
|
|
14138
|
+
}
|
|
13249
14139
|
let previewUrl;
|
|
13250
14140
|
try {
|
|
13251
|
-
previewUrl = buildQaPreviewUrl2(storeUrl, exp.id, variation.id);
|
|
14141
|
+
previewUrl = buildQaPreviewUrl2(storeUrl, exp.id, variation.id, qaRun?.id);
|
|
13252
14142
|
} catch {
|
|
13253
14143
|
fail(
|
|
13254
14144
|
previewCommand,
|
|
@@ -13257,6 +14147,10 @@ var previewCommand = new Command("preview").description(
|
|
|
13257
14147
|
}
|
|
13258
14148
|
const signed = await signedPreviewFromReadiness(creds, exp.id, variation.id, storeUrl);
|
|
13259
14149
|
const selectedPreviewUrl = signed?.signed_preview_url ?? previewUrl.toString();
|
|
14150
|
+
if (signed?.signed_preview_url) {
|
|
14151
|
+
const signedSessionId = signed.signed_preview_qa_session_id;
|
|
14152
|
+
qaRun = signedSessionId ? qaRun?.id === signedSessionId ? qaRun : { id: signedSessionId } : void 0;
|
|
14153
|
+
}
|
|
13260
14154
|
const warning = signed?.signed_preview_url ? null : "Test images may not load on this unsigned link. Open Apex \u2192 QA for a signed link.";
|
|
13261
14155
|
if (warning) console.error(warning);
|
|
13262
14156
|
output(
|
|
@@ -13267,6 +14161,7 @@ var previewCommand = new Command("preview").description(
|
|
|
13267
14161
|
previewUrl: selectedPreviewUrl,
|
|
13268
14162
|
expiresAt: signed?.signed_preview_expires_at ?? null,
|
|
13269
14163
|
...warning ? { warning } : {},
|
|
14164
|
+
...qaRun ? { qa_run: qaRun, qa_session_id: qaRun.id } : {},
|
|
13270
14165
|
...!opts?.storeUrl && exp.preview_target ? { previewTarget: exp.preview_target } : {}
|
|
13271
14166
|
},
|
|
13272
14167
|
() => {
|
|
@@ -20146,7 +21041,8 @@ function createSchemaCommand(program3) {
|
|
|
20146
21041
|
mandatoryOptions: "An option's mandatory field is true only when the flag itself must be passed.",
|
|
20147
21042
|
requiredArguments: "An argument's required field means the positional is mandatory."
|
|
20148
21043
|
},
|
|
20149
|
-
...commandSchema(program3)
|
|
21044
|
+
...commandSchema(program3),
|
|
21045
|
+
files: experiment_filesystem_schema_default
|
|
20150
21046
|
};
|
|
20151
21047
|
output(this, schema, () => {
|
|
20152
21048
|
process.stdout.write(`${JSON.stringify(schema, null, 2)}
|
|
@@ -20787,8 +21683,15 @@ var skillsCommand = new Command("skills").description("Print or install the Apex
|
|
|
20787
21683
|
});
|
|
20788
21684
|
});
|
|
20789
21685
|
|
|
21686
|
+
// ../../ops/org-split/move-plan.mjs
|
|
21687
|
+
var uuid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
21688
|
+
function validateMoveInput(shopIds, toOrgId) {
|
|
21689
|
+
if (typeof toOrgId !== "string" || !uuid.test(toOrgId) || !Array.isArray(shopIds) || !shopIds.length || shopIds.some((id) => typeof id !== "string" || !uuid.test(id))) throw new Error("Choose valid store and destination UUIDs");
|
|
21690
|
+
return { shopIds: [...new Set(shopIds.map((id) => id.toLowerCase()))].sort(), toOrgId: toOrgId.toLowerCase() };
|
|
21691
|
+
}
|
|
21692
|
+
|
|
20790
21693
|
// src/commands/admin.ts
|
|
20791
|
-
var
|
|
21694
|
+
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;
|
|
20792
21695
|
function switchValue(value) {
|
|
20793
21696
|
if (value === "on") return true;
|
|
20794
21697
|
if (value === "off") return false;
|
|
@@ -20915,7 +21818,7 @@ var create6 = new Command("create").description("Create an internal, demo or dog
|
|
|
20915
21818
|
fail(this, "--name must be 1 to 60 characters", 3);
|
|
20916
21819
|
if (opts.reason.trim().length < 8 || opts.reason.trim().length > 500)
|
|
20917
21820
|
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
20918
|
-
if (opts.claimShop && !
|
|
21821
|
+
if (opts.claimShop && !uuid2.test(opts.claimShop)) fail(this, "--claim-shop must be a UUID", 3);
|
|
20919
21822
|
if (opts.claimShop && (opts.domain || opts.platform))
|
|
20920
21823
|
fail(this, "Use --claim-shop or --domain with --platform", 3);
|
|
20921
21824
|
if (!!opts.domain !== !!opts.platform)
|
|
@@ -20936,7 +21839,7 @@ var create6 = new Command("create").description("Create an internal, demo or dog
|
|
|
20936
21839
|
fail(this, "--owner requires a store for the invitation", 3);
|
|
20937
21840
|
if (opts.plan !== "self_managed" && (!opts.consultant || !opts.consultantTitle?.trim()))
|
|
20938
21841
|
fail(this, "Managed plans require --consultant and --consultant-title", 3);
|
|
20939
|
-
if (opts.consultant && !
|
|
21842
|
+
if (opts.consultant && !uuid2.test(opts.consultant))
|
|
20940
21843
|
fail(this, "--consultant must be a platform access UUID", 3);
|
|
20941
21844
|
if (!!opts.consultant !== !!opts.consultantTitle?.trim())
|
|
20942
21845
|
fail(this, "Provide --consultant and --consultant-title together", 3);
|
|
@@ -21001,7 +21904,7 @@ var create6 = new Command("create").description("Create an internal, demo or dog
|
|
|
21001
21904
|
});
|
|
21002
21905
|
});
|
|
21003
21906
|
var setCategory = new Command("set-category").description("Change an existing account's category with an audit reason").argument("<org-id>", "Organization UUID").requiredOption("--category <category>", "internal, demo, dogfood or customer").requiredOption("--reason <text>", "Audit reason, 8 to 500 characters").option("--confirm", "Confirm category change").option("--json", "Output JSON").action(async function(orgId, opts) {
|
|
21004
|
-
if (!
|
|
21907
|
+
if (!uuid2.test(orgId)) fail(this, "<org-id> must be a UUID", 3);
|
|
21005
21908
|
if (!["internal", "demo", "dogfood", "customer"].includes(opts.category))
|
|
21006
21909
|
fail(this, "--category must be internal, demo, dogfood or customer", 3);
|
|
21007
21910
|
const reason2 = opts.reason.trim();
|
|
@@ -21032,14 +21935,137 @@ var setCategory = new Command("set-category").description("Change an existing ac
|
|
|
21032
21935
|
printTable(["RESULT"], [[`Customer ${result.customerId} moved to ${result.category}`]]);
|
|
21033
21936
|
});
|
|
21034
21937
|
});
|
|
21035
|
-
var
|
|
21938
|
+
var setManagedBy = new Command("set-managed-by").description("Assign or clear a managing agency with an audit reason").argument("<org-id>", "Organization UUID").option("--by <org-id>", "Managing agency UUID").option("--clear", "Clear the managing agency").requiredOption("--reason <text>", "Audit reason, 8 to 500 characters").option("--confirm", "Confirm manager change").option("--json", "Output JSON").action(async function(orgId, opts) {
|
|
21939
|
+
if (!uuid2.test(orgId)) fail(this, "<org-id> must be a UUID", 3);
|
|
21940
|
+
if (!!opts.by === !!opts.clear) fail(this, "Use exactly one of --by or --clear", 3);
|
|
21941
|
+
if (opts.by && !uuid2.test(opts.by)) fail(this, "--by must be a UUID", 3);
|
|
21942
|
+
const reason2 = opts.reason.trim();
|
|
21943
|
+
if (reason2.length < 8 || reason2.length > 500)
|
|
21944
|
+
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
21945
|
+
if (!opts.confirm) {
|
|
21946
|
+
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
21947
|
+
confirmationRequired(
|
|
21948
|
+
this,
|
|
21949
|
+
"--confirm is required to change a managing agency",
|
|
21950
|
+
`apex admin customers set-managed-by ${orgId} ${opts.by ? `--by ${opts.by}` : "--clear"} --reason ${quote(reason2)} --confirm`
|
|
21951
|
+
);
|
|
21952
|
+
}
|
|
21953
|
+
const res = await setAdminCustomerManagedBy(requireUserCredentials(), orgId, {
|
|
21954
|
+
managed_by_org_id: opts.by ?? null,
|
|
21955
|
+
reason: reason2
|
|
21956
|
+
});
|
|
21957
|
+
if (!res.ok || !res.data)
|
|
21958
|
+
fail(
|
|
21959
|
+
this,
|
|
21960
|
+
res.error ?? "Failed to change managing agency",
|
|
21961
|
+
classifyStatus(res.status),
|
|
21962
|
+
res.errorDetails
|
|
21963
|
+
);
|
|
21964
|
+
output(
|
|
21965
|
+
this,
|
|
21966
|
+
res.data,
|
|
21967
|
+
() => printTable(
|
|
21968
|
+
["CUSTOMER", "MANAGING AGENCY"],
|
|
21969
|
+
[[res.data.data.customerId, res.data.data.managed_by_org_id ?? "None"]]
|
|
21970
|
+
)
|
|
21971
|
+
);
|
|
21972
|
+
});
|
|
21973
|
+
var setWorkspaceType = new Command("set-workspace-type").description("Change a workspace type with an audit reason").argument("<org-id>", "Organization UUID").requiredOption("--type <company|agency>", "Workspace type").requiredOption("--reason <text>", "Audit reason, 8 to 500 characters").option("--confirm", "Confirm workspace type change").option("--json", "Output JSON").action(async function(orgId, opts) {
|
|
21974
|
+
if (!uuid2.test(orgId)) fail(this, "<org-id> must be a UUID", 3);
|
|
21975
|
+
if (opts.type !== "company" && opts.type !== "agency")
|
|
21976
|
+
fail(this, "--type must be company or agency", 3);
|
|
21977
|
+
const reason2 = opts.reason.trim();
|
|
21978
|
+
if (reason2.length < 8 || reason2.length > 500)
|
|
21979
|
+
fail(this, "--reason must be 8 to 500 characters", 3);
|
|
21980
|
+
if (!opts.confirm) {
|
|
21981
|
+
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
21982
|
+
confirmationRequired(
|
|
21983
|
+
this,
|
|
21984
|
+
"--confirm is required to change a workspace type",
|
|
21985
|
+
`apex admin customers set-workspace-type ${orgId} --type ${opts.type} --reason ${quote(reason2)} --confirm`
|
|
21986
|
+
);
|
|
21987
|
+
}
|
|
21988
|
+
const res = await setAdminCustomerWorkspaceType(requireUserCredentials(), orgId, {
|
|
21989
|
+
workspace_type: opts.type,
|
|
21990
|
+
reason: reason2
|
|
21991
|
+
});
|
|
21992
|
+
if (!res.ok || !res.data)
|
|
21993
|
+
fail(
|
|
21994
|
+
this,
|
|
21995
|
+
res.error ?? "Failed to change workspace type",
|
|
21996
|
+
classifyStatus(res.status),
|
|
21997
|
+
res.errorDetails
|
|
21998
|
+
);
|
|
21999
|
+
output(
|
|
22000
|
+
this,
|
|
22001
|
+
res.data,
|
|
22002
|
+
() => printTable(
|
|
22003
|
+
["CUSTOMER", "WORKSPACE TYPE"],
|
|
22004
|
+
[[res.data.data.customerId, res.data.data.workspace_type]]
|
|
22005
|
+
)
|
|
22006
|
+
);
|
|
22007
|
+
});
|
|
22008
|
+
function storeMoveRequest(opts) {
|
|
22009
|
+
const { shopIds, toOrgId } = validateMoveInput(opts.shop, opts.to);
|
|
22010
|
+
const reason2 = opts.reason.trim();
|
|
22011
|
+
if (reason2.length < 8 || reason2.length > 500)
|
|
22012
|
+
throw new Error("--reason must be 8 to 500 characters");
|
|
22013
|
+
return {
|
|
22014
|
+
toOrgId,
|
|
22015
|
+
body: {
|
|
22016
|
+
shop_ids: shopIds,
|
|
22017
|
+
reason: reason2,
|
|
22018
|
+
keep_grants: !!opts.keepGrants,
|
|
22019
|
+
dry_run: !opts.confirm
|
|
22020
|
+
}
|
|
22021
|
+
};
|
|
22022
|
+
}
|
|
22023
|
+
var moveStores = new Command("move-stores").description("Preview or confirm an audited set of store moves").requiredOption("--to <org-id>", "Destination organization UUID").requiredOption(
|
|
22024
|
+
"--shop <shop-id>",
|
|
22025
|
+
"Store UUID, repeat for each store",
|
|
22026
|
+
(value, previous) => [...previous, value],
|
|
22027
|
+
[]
|
|
22028
|
+
).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) {
|
|
22029
|
+
let request2;
|
|
22030
|
+
try {
|
|
22031
|
+
request2 = storeMoveRequest(opts);
|
|
22032
|
+
} catch (error) {
|
|
22033
|
+
fail(this, error instanceof Error ? error.message : "Invalid move request", 3);
|
|
22034
|
+
}
|
|
22035
|
+
const res = await moveAdminCustomerStores(
|
|
22036
|
+
requireUserCredentials(),
|
|
22037
|
+
request2.toOrgId,
|
|
22038
|
+
request2.body
|
|
22039
|
+
);
|
|
22040
|
+
if (!res.ok || !res.data)
|
|
22041
|
+
fail(
|
|
22042
|
+
this,
|
|
22043
|
+
res.error ?? "Failed to move stores",
|
|
22044
|
+
classifyStatus(res.status),
|
|
22045
|
+
res.errorDetails
|
|
22046
|
+
);
|
|
22047
|
+
output(this, res.data, () => {
|
|
22048
|
+
printTable(
|
|
22049
|
+
["FIELD", "VALUE"],
|
|
22050
|
+
Object.entries(res.data.data).map(([key, value]) => [key, JSON.stringify(value)])
|
|
22051
|
+
);
|
|
22052
|
+
});
|
|
22053
|
+
});
|
|
22054
|
+
var customers = new Command("customers").description("Create engineering accounts and manage existing account categories").addCommand(create6).addCommand(setCategory).addCommand(setManagedBy).addCommand(setWorkspaceType).addCommand(moveStores);
|
|
21036
22055
|
var adminCommand = new Command("admin").description("Operate allowlisted platform controls").addCommand(settingsGet).addCommand(quarantine).addCommand(shops).addCommand(customers);
|
|
21037
22056
|
|
|
21038
22057
|
// src/commands/membership.ts
|
|
21039
22058
|
init_source();
|
|
21040
22059
|
async function run2(c, p, label) {
|
|
21041
22060
|
const r = await p;
|
|
21042
|
-
if (!r.ok)
|
|
22061
|
+
if (!r.ok)
|
|
22062
|
+
fail(
|
|
22063
|
+
c,
|
|
22064
|
+
r.error ?? `Failed to ${label}`,
|
|
22065
|
+
classifyStatus(r.status),
|
|
22066
|
+
r.errorDetails,
|
|
22067
|
+
apiFailureOf(r)
|
|
22068
|
+
);
|
|
21043
22069
|
output(c, r.data ?? {}, () => process.stdout.write(`${JSON.stringify(r.data, null, 2)}
|
|
21044
22070
|
`));
|
|
21045
22071
|
}
|
|
@@ -21075,7 +22101,27 @@ orgCommand.command("update").option("--name <name>").option("--slug <slug>").opt
|
|
|
21075
22101
|
);
|
|
21076
22102
|
});
|
|
21077
22103
|
orgCommand.command("members").action(async function() {
|
|
21078
|
-
await
|
|
22104
|
+
const r = await listOrgMembers(requireUserCredentials());
|
|
22105
|
+
if (!r.ok)
|
|
22106
|
+
fail(
|
|
22107
|
+
this,
|
|
22108
|
+
r.error ?? "Failed to list members",
|
|
22109
|
+
classifyStatus(r.status),
|
|
22110
|
+
r.errorDetails,
|
|
22111
|
+
apiFailureOf(r)
|
|
22112
|
+
);
|
|
22113
|
+
const rows = r.data?.data ?? [];
|
|
22114
|
+
output(this, r.data ?? {}, () => {
|
|
22115
|
+
printTable(
|
|
22116
|
+
["ID", "MEMBER", "ROLE", "SUSPENDED"],
|
|
22117
|
+
rows.map((row) => [
|
|
22118
|
+
String(row.id),
|
|
22119
|
+
String(row.email ?? row.name ?? "-"),
|
|
22120
|
+
String(row.role),
|
|
22121
|
+
String(row.suspended_at ?? "-")
|
|
22122
|
+
])
|
|
22123
|
+
);
|
|
22124
|
+
});
|
|
21079
22125
|
});
|
|
21080
22126
|
orgCommand.command("invite").argument("<email>").option("--role <role>", "Alias for --org-role").option("--org-role <role>", "Organization role", "member").addOption(
|
|
21081
22127
|
new Option(
|
|
@@ -21112,6 +22158,26 @@ orgCommand.command("set-role").argument("<memberId>").argument("<role>").option(
|
|
|
21112
22158
|
"set role"
|
|
21113
22159
|
);
|
|
21114
22160
|
});
|
|
22161
|
+
orgCommand.command("suspend-member").argument("<memberId>").option("--reason <text>").option("-f, --force").action(async function(id, o) {
|
|
22162
|
+
if (!await confirm(
|
|
22163
|
+
this,
|
|
22164
|
+
o.force,
|
|
22165
|
+
`Suspend organization member ${id}`,
|
|
22166
|
+
`apex org suspend-member ${id} --force`
|
|
22167
|
+
))
|
|
22168
|
+
return;
|
|
22169
|
+
await run2(this, suspendOrgMember(requireUserCredentials(), id, o.reason), "suspend member");
|
|
22170
|
+
});
|
|
22171
|
+
orgCommand.command("reinstate-member").argument("<memberId>").option("-f, --force").action(async function(id, o) {
|
|
22172
|
+
if (!await confirm(
|
|
22173
|
+
this,
|
|
22174
|
+
o.force,
|
|
22175
|
+
`Reinstate organization member ${id}`,
|
|
22176
|
+
`apex org reinstate-member ${id} --force`
|
|
22177
|
+
))
|
|
22178
|
+
return;
|
|
22179
|
+
await run2(this, reinstateOrgMember(requireUserCredentials(), id), "reinstate member");
|
|
22180
|
+
});
|
|
21115
22181
|
orgCommand.command("remove-member").argument("<memberId>").option("-f, --force").action(async function(id, o) {
|
|
21116
22182
|
if (!await confirm(
|
|
21117
22183
|
this,
|