@drip-apex/apex-cli 0.12.0 → 0.13.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/AGENTS.md +4 -1
- package/README.md +62 -2
- package/dist/cli.js +254 -167
- package/package.json +1 -1
- package/skills/apex-cli/SKILL.md +3 -1
package/AGENTS.md
CHANGED
|
@@ -18,7 +18,10 @@ Use `apex` as the canonical command name. `drip` is a compatibility alias.
|
|
|
18
18
|
- Launch is dashboard-only. The API and CLI do not start traffic.
|
|
19
19
|
- Prefer `--json`; piped stdout defaults to JSON automatically.
|
|
20
20
|
- JSON output is a stable contract: top level is `{ ok, version, command, data | error }`.
|
|
21
|
-
- Diagnostics, prompts, progress,
|
|
21
|
+
- With `--json`, stdout is exactly one JSON document. Diagnostics, prompts, progress,
|
|
22
|
+
and update notices go to stderr.
|
|
23
|
+
- For single-request commands `data` is the API response body as returned (lists at
|
|
24
|
+
`.data.data[]`). API failures carry the API error body in `error.api`.
|
|
22
25
|
- Do not parse human tables. Use `apex schema --json` first if you need flags.
|
|
23
26
|
- Keep command names exact. Do not infer or guess names from the CLI's
|
|
24
27
|
"did you mean" hints — those are stderr diagnostics for humans; machine
|
package/README.md
CHANGED
|
@@ -100,6 +100,42 @@ Summary timestamps include `created_at` and `archived_at`; experiments have no `
|
|
|
100
100
|
`--include-archived` to include them; archived rows display their archive date
|
|
101
101
|
when the API provides `archived_at`.
|
|
102
102
|
|
|
103
|
+
## JSON output contract
|
|
104
|
+
|
|
105
|
+
With `--json`, or whenever stdout is piped, stdout carries exactly one JSON
|
|
106
|
+
document and nothing else. Spinners, progress, prompts, warnings, human text and
|
|
107
|
+
child-process output go to stderr, so `apex ... --json | jq` always parses.
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{ "ok": true, "version": "0.13.0", "command": "apex flags get", "data": {}, "context": {} }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- `data` is the API response body exactly as the API returned it for every command
|
|
114
|
+
backed by one API request. Lists keep the API's `{ "data": [...], "pagination": {...} }`
|
|
115
|
+
shape, so rows are at `.data.data[]`; single resources are at `.data` directly.
|
|
116
|
+
- `apex experiments get` adds one CLI-derived key, `dashboard_url`, beside the
|
|
117
|
+
experiment fields.
|
|
118
|
+
- Commands that combine several requests or local files (`experiments create`,
|
|
119
|
+
`pull`, `plan`, `apply`, `qa approve`, `triggers`, `project-code`, `harness`,
|
|
120
|
+
`workspace`, `doctor`, `whoami`, `push`, `analytics urls`, `flags status`,
|
|
121
|
+
`goals test`) print a documented CLI-composed `data` object.
|
|
122
|
+
- Failures print `{ "ok": false, "version", "command", "error", "context" }`.
|
|
123
|
+
`error.code` is the CLI exit code, `error.details` carries retry hints and
|
|
124
|
+
server details, and `error.api` is `{ "status", "body" }` with the API error
|
|
125
|
+
envelope verbatim whenever an API response caused the failure.
|
|
126
|
+
- `deprecated` appears on the envelope only when a deprecated flag was used.
|
|
127
|
+
|
|
128
|
+
**Breaking in 0.13.0.** Earlier releases re-nested or renamed API bodies. Update
|
|
129
|
+
scripts: `.data.experiments[]` becomes `.data.data[]`; `experiments get`
|
|
130
|
+
`.data.experiment.id` becomes `.data.id`; `.data.flag`, `.data.goal`,
|
|
131
|
+
`.data.funnel`, `.data.signal`, `.data.backlog_item`, `.data.personalization`,
|
|
132
|
+
`.data.exclusion_group`, `.data.asset`, `.data.landing_page`, `.data.webhook`,
|
|
133
|
+
`.data.targeting` and `.data.verification` wrappers are gone (read the fields at
|
|
134
|
+
`.data`); `experiments results` reads at `.data` instead of `.data.results`,
|
|
135
|
+
`funnels run` at `.data` instead of `.data.run`, and `brand` at `.data.data`
|
|
136
|
+
instead of `.data.brandContext`; lifecycle and delete commands return the API's
|
|
137
|
+
body instead of a CLI summary.
|
|
138
|
+
|
|
103
139
|
## Command index
|
|
104
140
|
|
|
105
141
|
Use `apex schema --json` to emit the complete machine-readable command surface,
|
|
@@ -352,5 +388,29 @@ config-fetch p50/p95 (milliseconds), and inline/cache/network/none counts.
|
|
|
352
388
|
JSON output includes the API body in the standard envelope and assignment-ready
|
|
353
389
|
percentiles. Fewer than five measured samples have null percentiles. Natural
|
|
354
390
|
loads are shop-wide non-QA loads without forced IDs; a QA-session bucket can
|
|
355
|
-
overlap forced loads. Analytics failures return errors.
|
|
356
|
-
|
|
391
|
+
overlap forced loads. Analytics failures return errors. The API position is
|
|
392
|
+
`runtime_inline_no_change`.
|
|
393
|
+
|
|
394
|
+
The runtime remains unchanged. Natural runtime decides within tens of milliseconds
|
|
395
|
+
of SDK start when config ships inline with the snippet (measured p50 12 ms /
|
|
396
|
+
p95 54 ms on a large storefront). QA previews, screenshot-mode previews and
|
|
397
|
+
cookie-forced sessions take the QA config lane and fetch fresh config over the
|
|
398
|
+
network (measured p50 1.3 s / p95 7 s); they are not representative of launch
|
|
399
|
+
behaviour. URL-forced sessions without a `qa` parameter keep the inline or cached
|
|
400
|
+
config, so these measurements do not describe them. No config preload or
|
|
401
|
+
anti-flicker hold is planned.
|
|
402
|
+
|
|
403
|
+
### Connection troubleshooting
|
|
404
|
+
|
|
405
|
+
Connection errors retain the underlying failure. JSON output exposes
|
|
406
|
+
`error.details.reason` and, when available, `error.details.code`; the numeric
|
|
407
|
+
`error.code` remains the CLI exit code.
|
|
408
|
+
|
|
409
|
+
| Reason | Meaning and usual fix |
|
|
410
|
+
| --- | --- |
|
|
411
|
+
| `dns` | The host could not be resolved. Check `APEX_BASE_URL` (or `DRIP_BASE_URL`), DNS, and whether your sandbox permits network access. |
|
|
412
|
+
| `refused` | The host rejected the connection. Check the base URL, port, and whether the server is running. |
|
|
413
|
+
| `reset` | The connection was interrupted. Check network stability and proxy settings before retrying. |
|
|
414
|
+
| `tls` | Certificate or TLS validation failed. Check expired certificates and your corporate TLS proxy's trusted CA configuration. |
|
|
415
|
+
| `timeout` | The request was aborted or exceeded its deadline. Check server availability and network access. |
|
|
416
|
+
| `unknown` | Another network failure occurred. Use the included cause message to diagnose network or sandbox restrictions. |
|
package/dist/cli.js
CHANGED
|
@@ -7112,7 +7112,7 @@ var import_node_os3 = __toESM(require("node:os"));
|
|
|
7112
7112
|
// package.json
|
|
7113
7113
|
var package_default = {
|
|
7114
7114
|
name: "@drip-apex/apex-cli",
|
|
7115
|
-
version: "0.
|
|
7115
|
+
version: "0.13.0",
|
|
7116
7116
|
license: "MIT",
|
|
7117
7117
|
description: "Apex CLI for managing experiments, approved roadmap ideas, and draft workspaces.",
|
|
7118
7118
|
private: false,
|
|
@@ -7172,16 +7172,42 @@ var EXIT_CODES = {
|
|
|
7172
7172
|
confirmationRequired: 4,
|
|
7173
7173
|
conflict: 5
|
|
7174
7174
|
};
|
|
7175
|
+
var MAX_RECORDED_API_FAILURES = 32;
|
|
7176
|
+
var recentApiFailures = [];
|
|
7177
|
+
function recordApiResponse(response) {
|
|
7178
|
+
if (response.ok) return;
|
|
7179
|
+
recentApiFailures.push({
|
|
7180
|
+
status: response.status,
|
|
7181
|
+
body: response.data ?? null,
|
|
7182
|
+
message: response.error,
|
|
7183
|
+
details: response.errorDetails
|
|
7184
|
+
});
|
|
7185
|
+
if (recentApiFailures.length > MAX_RECORDED_API_FAILURES) recentApiFailures.shift();
|
|
7186
|
+
}
|
|
7187
|
+
function matchApiFailure(message, details) {
|
|
7188
|
+
const byDetails = details !== void 0 ? recentApiFailures.find((entry) => entry.details === details) : void 0;
|
|
7189
|
+
if (byDetails) return { status: byDetails.status, body: byDetails.body };
|
|
7190
|
+
const byMessage = recentApiFailures.filter(
|
|
7191
|
+
(entry) => Boolean(entry.message) && message.includes(entry.message)
|
|
7192
|
+
);
|
|
7193
|
+
if (byMessage.length !== 1) return void 0;
|
|
7194
|
+
return { status: byMessage[0].status, body: byMessage[0].body };
|
|
7195
|
+
}
|
|
7175
7196
|
var CliError = class extends Error {
|
|
7176
7197
|
exitCode;
|
|
7177
7198
|
details;
|
|
7178
|
-
|
|
7199
|
+
api;
|
|
7200
|
+
constructor(message, exitCode = EXIT_CODES.general, details, api) {
|
|
7179
7201
|
super(message);
|
|
7180
7202
|
this.name = "CliError";
|
|
7181
7203
|
this.exitCode = exitCode;
|
|
7182
7204
|
this.details = details;
|
|
7205
|
+
this.api = api ?? matchApiFailure(message, details);
|
|
7183
7206
|
}
|
|
7184
7207
|
};
|
|
7208
|
+
function apiFailureOf(response) {
|
|
7209
|
+
return response.ok ? void 0 : { status: response.status, body: response.data ?? null };
|
|
7210
|
+
}
|
|
7185
7211
|
var initialEnvironmentApiKey = process.env.APEX_API_KEY || process.env.DRIP_API_KEY;
|
|
7186
7212
|
var envelopeContext = {
|
|
7187
7213
|
org_id: null,
|
|
@@ -7196,6 +7222,7 @@ var commandName = "apex";
|
|
|
7196
7222
|
var wroteEnvelope = false;
|
|
7197
7223
|
var stdoutLines = [];
|
|
7198
7224
|
var originalConsoleLog = null;
|
|
7225
|
+
var rawStdoutWrite = null;
|
|
7199
7226
|
var deprecationMarker = null;
|
|
7200
7227
|
var interceptedCommands = /* @__PURE__ */ new WeakMap();
|
|
7201
7228
|
function interceptCliError(err, command) {
|
|
@@ -7222,18 +7249,52 @@ function formatConsoleArgs(args) {
|
|
|
7222
7249
|
return JSON.stringify(arg);
|
|
7223
7250
|
}).join(" ");
|
|
7224
7251
|
}
|
|
7252
|
+
function installJsonStdoutGuard() {
|
|
7253
|
+
if (rawStdoutWrite) return;
|
|
7254
|
+
const stdout = process.stdout;
|
|
7255
|
+
const original = stdout.write.bind(stdout);
|
|
7256
|
+
rawStdoutWrite = (text) => original(text);
|
|
7257
|
+
stdout.write = ((chunk, ...args) => process.stderr.write(
|
|
7258
|
+
chunk,
|
|
7259
|
+
...args
|
|
7260
|
+
));
|
|
7261
|
+
}
|
|
7262
|
+
function isJsonMode() {
|
|
7263
|
+
return jsonMode;
|
|
7264
|
+
}
|
|
7225
7265
|
function configureRuntime(command) {
|
|
7226
7266
|
commandName = commandPath(command) || commandName;
|
|
7227
7267
|
jsonMode = shouldUseJson(command);
|
|
7228
|
-
if (!jsonMode
|
|
7268
|
+
if (!jsonMode) return;
|
|
7269
|
+
installJsonStdoutGuard();
|
|
7270
|
+
if (originalConsoleLog) return;
|
|
7229
7271
|
originalConsoleLog = console.log;
|
|
7230
7272
|
console.log = (...args) => {
|
|
7231
7273
|
stdoutLines.push(formatConsoleArgs(args));
|
|
7232
7274
|
};
|
|
7233
7275
|
}
|
|
7276
|
+
function writeJsonDocument(envelope) {
|
|
7277
|
+
const text = `${JSON.stringify(envelope, null, 2)}
|
|
7278
|
+
`;
|
|
7279
|
+
if (wroteEnvelope) {
|
|
7280
|
+
process.stderr.write(text);
|
|
7281
|
+
return;
|
|
7282
|
+
}
|
|
7283
|
+
wroteEnvelope = true;
|
|
7284
|
+
const pendingHumanLines = stdoutLines;
|
|
7285
|
+
stdoutLines = [];
|
|
7286
|
+
restoreConsoleLog();
|
|
7287
|
+
if (pendingHumanLines.length > 0) process.stderr.write(`${pendingHumanLines.join("\n")}
|
|
7288
|
+
`);
|
|
7289
|
+
if (rawStdoutWrite) rawStdoutWrite(text);
|
|
7290
|
+
else process.stdout.write(text);
|
|
7291
|
+
}
|
|
7234
7292
|
function flushFallbackEnvelope() {
|
|
7235
|
-
if (!jsonMode || wroteEnvelope
|
|
7236
|
-
|
|
7293
|
+
if (!jsonMode || wroteEnvelope) return;
|
|
7294
|
+
if (process.exitCode !== void 0 && process.exitCode !== 0) return;
|
|
7295
|
+
const output2 = stdoutLines.join("\n");
|
|
7296
|
+
stdoutLines = [];
|
|
7297
|
+
writeEnvelope(output2 ? { output: output2 } : null);
|
|
7237
7298
|
}
|
|
7238
7299
|
function restoreConsoleLog() {
|
|
7239
7300
|
if (!originalConsoleLog) return;
|
|
@@ -7252,10 +7313,7 @@ function writeEnvelope(data, command = commandName) {
|
|
|
7252
7313
|
context: envelopeContext,
|
|
7253
7314
|
...deprecationMarker ? { deprecated: deprecationMarker } : {}
|
|
7254
7315
|
};
|
|
7255
|
-
|
|
7256
|
-
restoreConsoleLog();
|
|
7257
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
|
|
7258
|
-
`);
|
|
7316
|
+
writeJsonDocument(envelope);
|
|
7259
7317
|
}
|
|
7260
7318
|
function writeErrorEnvelope(error, command = commandName) {
|
|
7261
7319
|
const envelope = {
|
|
@@ -7265,14 +7323,12 @@ function writeErrorEnvelope(error, command = commandName) {
|
|
|
7265
7323
|
error: {
|
|
7266
7324
|
message: error.message,
|
|
7267
7325
|
code: error.exitCode,
|
|
7268
|
-
...error.details ? { details: error.details } : {}
|
|
7326
|
+
...error.details ? { details: error.details } : {},
|
|
7327
|
+
...error.api ? { api: error.api } : {}
|
|
7269
7328
|
},
|
|
7270
7329
|
context: envelopeContext
|
|
7271
7330
|
};
|
|
7272
|
-
|
|
7273
|
-
restoreConsoleLog();
|
|
7274
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
|
|
7275
|
-
`);
|
|
7331
|
+
writeJsonDocument(envelope);
|
|
7276
7332
|
}
|
|
7277
7333
|
function output(command, data, human) {
|
|
7278
7334
|
if (shouldUseJson(command)) {
|
|
@@ -7291,8 +7347,8 @@ function commandPath(command) {
|
|
|
7291
7347
|
}
|
|
7292
7348
|
return names.join(" ");
|
|
7293
7349
|
}
|
|
7294
|
-
function fail(command, message, exitCode = EXIT_CODES.general, details) {
|
|
7295
|
-
throw new CliError(message, exitCode, details);
|
|
7350
|
+
function fail(command, message, exitCode = EXIT_CODES.general, details, api) {
|
|
7351
|
+
throw new CliError(message, exitCode, details, api);
|
|
7296
7352
|
}
|
|
7297
7353
|
function classifyStatus(status2) {
|
|
7298
7354
|
if (status2 === 401 || status2 === 403) return EXIT_CODES.auth;
|
|
@@ -7666,11 +7722,20 @@ function createHttpClient(creds, options) {
|
|
|
7666
7722
|
try {
|
|
7667
7723
|
response = await fetch(`${creds.baseUrl}${path24}`, { method, headers, body: form ? body5 : body5 ? JSON.stringify(body5) : void 0, signal: AbortSignal.timeout(timeoutMs) });
|
|
7668
7724
|
} catch (error) {
|
|
7669
|
-
|
|
7725
|
+
const outer = error && typeof error === "object" ? error : void 0;
|
|
7726
|
+
const nested = outer?.cause && typeof outer.cause === "object" ? outer.cause : void 0;
|
|
7727
|
+
return options.onNetworkError({
|
|
7728
|
+
baseUrl: creds.baseUrl,
|
|
7729
|
+
timeoutMs,
|
|
7730
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
7731
|
+
code: typeof nested?.code === "string" ? nested.code : typeof outer?.code === "string" ? outer.code : void 0,
|
|
7732
|
+
name: typeof outer?.name === "string" ? outer.name : void 0,
|
|
7733
|
+
causeMessage: typeof nested?.message === "string" ? nested.message : void 0
|
|
7734
|
+
});
|
|
7670
7735
|
}
|
|
7671
7736
|
inspectVersion(response.headers);
|
|
7672
7737
|
const json = await response.json().catch(() => null);
|
|
7673
|
-
if (!response.ok) return { ok: false, status: response.status, data:
|
|
7738
|
+
if (!response.ok) return { ok: false, status: response.status, data: json, error: extractErrorMessage(json, response.status), errorDetails: extractErrorDetails(json), requestId: response.headers.get("x-request-id"), rateLimit: { limit: response.headers.get("x-ratelimit-limit"), remaining: response.headers.get("x-ratelimit-remaining"), reset: response.headers.get("x-ratelimit-reset") } };
|
|
7674
7739
|
return { ok: true, status: response.status, data: json };
|
|
7675
7740
|
}
|
|
7676
7741
|
return { request: (method, path24, body5, timeoutMs) => request2(method, path24, body5, timeoutMs), requestForm: (method, path24, body5) => request2(method, path24, body5, void 0, true) };
|
|
@@ -7739,10 +7804,42 @@ function sharedClient(creds) {
|
|
|
7739
7804
|
transport: testTransport,
|
|
7740
7805
|
testTransportVersion: () => testTransport ? process.env[["APEX", "CLI", "MOCK", "API", "VERSION"].join("_")] : void 0,
|
|
7741
7806
|
onNetworkError: (info) => {
|
|
7807
|
+
let url;
|
|
7808
|
+
try {
|
|
7809
|
+
url = new URL(info.baseUrl);
|
|
7810
|
+
} catch {
|
|
7811
|
+
}
|
|
7812
|
+
const host = url?.hostname ?? info.baseUrl;
|
|
7813
|
+
const code = info.code;
|
|
7814
|
+
let reason = "unknown";
|
|
7815
|
+
let message = info.causeMessage ?? info.cause;
|
|
7816
|
+
if (info.name === "TimeoutError" || info.name === "AbortError" || code === "UND_ERR_CONNECT_TIMEOUT") {
|
|
7817
|
+
reason = "timeout";
|
|
7818
|
+
message = `server did not respond within ${info.timeoutMs / 1e3}s`;
|
|
7819
|
+
} else if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
|
|
7820
|
+
reason = "dns";
|
|
7821
|
+
message = `could not resolve host ${host}`;
|
|
7822
|
+
} else if (code === "ECONNREFUSED") {
|
|
7823
|
+
reason = "refused";
|
|
7824
|
+
message = `connection refused by ${host}:${url?.port || (url?.protocol === "https:" ? "443" : "80")}`;
|
|
7825
|
+
} else if (code === "ECONNRESET" || code === "EPIPE") {
|
|
7826
|
+
reason = "reset";
|
|
7827
|
+
message = `connection reset by ${host}`;
|
|
7828
|
+
} else if (code?.startsWith("CERT_") || code?.startsWith("ERR_TLS_") || [
|
|
7829
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
7830
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
7831
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
7832
|
+
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
7833
|
+
"UNABLE_TO_GET_ISSUER_CERT",
|
|
7834
|
+
"HOSTNAME_MISMATCH"
|
|
7835
|
+
].includes(code ?? "")) {
|
|
7836
|
+
reason = "tls";
|
|
7837
|
+
message = `TLS error (${code})`;
|
|
7838
|
+
}
|
|
7742
7839
|
throw new CliError(
|
|
7743
|
-
`Could not reach ${info.baseUrl}: check APEX_BASE_URL (or DRIP_BASE_URL) / network;
|
|
7840
|
+
`Could not reach ${info.baseUrl}: check APEX_BASE_URL (or DRIP_BASE_URL) / network; ${message}.`,
|
|
7744
7841
|
EXIT_CODES.general,
|
|
7745
|
-
{
|
|
7842
|
+
{ reason, code, name: info.name, baseUrl: info.baseUrl, timeoutMs: info.timeoutMs }
|
|
7746
7843
|
);
|
|
7747
7844
|
}
|
|
7748
7845
|
});
|
|
@@ -7751,10 +7848,14 @@ function sharedClient(creds) {
|
|
|
7751
7848
|
return client;
|
|
7752
7849
|
}
|
|
7753
7850
|
async function request(creds, method, path24, body5, requestTimeoutMs) {
|
|
7754
|
-
|
|
7851
|
+
const response = await sharedClient(creds).request(method, path24, body5, requestTimeoutMs);
|
|
7852
|
+
recordApiResponse(response);
|
|
7853
|
+
return response;
|
|
7755
7854
|
}
|
|
7756
7855
|
async function requestForm(creds, method, path24, body5) {
|
|
7757
|
-
|
|
7856
|
+
const response = await sharedClient(creds).requestForm(method, path24, body5);
|
|
7857
|
+
recordApiResponse(response);
|
|
7858
|
+
return response;
|
|
7758
7859
|
}
|
|
7759
7860
|
function listExperiments(creds, opts) {
|
|
7760
7861
|
const params = new URLSearchParams();
|
|
@@ -9800,7 +9901,8 @@ async function resolveExperiment(idOrSlug) {
|
|
|
9800
9901
|
throw new CliError(
|
|
9801
9902
|
res2.status === 404 && isTestKeyReference(idOrSlug) ? `Experiment "${idOrSlug}" not found in selected shop ${creds.resolvedContext?.shopId ?? "(API key shop)"}. Test keys resolve within the selected shop; use --shop <shop-id> to change it.` : res2.error ?? `Experiment "${idOrSlug}" not found`,
|
|
9802
9903
|
classifyStatus(res2.status),
|
|
9803
|
-
res2.errorDetails
|
|
9904
|
+
res2.errorDetails,
|
|
9905
|
+
apiFailureOf(res2)
|
|
9804
9906
|
);
|
|
9805
9907
|
}
|
|
9806
9908
|
const slug = idOrSlug.startsWith("slug:") ? idOrSlug.slice(5) : idOrSlug;
|
|
@@ -9809,7 +9911,8 @@ async function resolveExperiment(idOrSlug) {
|
|
|
9809
9911
|
throw new CliError(
|
|
9810
9912
|
res.error ?? `Experiment "${idOrSlug}" not found`,
|
|
9811
9913
|
classifyStatus(res.status),
|
|
9812
|
-
res.errorDetails
|
|
9914
|
+
res.errorDetails,
|
|
9915
|
+
apiFailureOf(res)
|
|
9813
9916
|
);
|
|
9814
9917
|
}
|
|
9815
9918
|
var list = new Command("list").alias("ls").description(
|
|
@@ -9836,7 +9939,7 @@ var list = new Command("list").alias("ls").description(
|
|
|
9836
9939
|
}
|
|
9837
9940
|
spinner?.stop();
|
|
9838
9941
|
const experiments = res.data.data;
|
|
9839
|
-
output(this,
|
|
9942
|
+
output(this, res.data, () => {
|
|
9840
9943
|
if (experiments.length === 0) {
|
|
9841
9944
|
console.log(source_default.dim("No experiments found."));
|
|
9842
9945
|
return;
|
|
@@ -9888,11 +9991,7 @@ var get = new Command("get").description(
|
|
|
9888
9991
|
exp.shop_id ?? creds.resolvedContext?.shopId,
|
|
9889
9992
|
exp.id
|
|
9890
9993
|
);
|
|
9891
|
-
output(
|
|
9892
|
-
this,
|
|
9893
|
-
{ experiment: exp, dashboard_url: dashboardUrl },
|
|
9894
|
-
() => printExperiment(exp, dashboardUrl)
|
|
9895
|
-
);
|
|
9994
|
+
output(this, { ...exp, dashboard_url: dashboardUrl }, () => printExperiment(exp, dashboardUrl));
|
|
9896
9995
|
});
|
|
9897
9996
|
var attachIdea = new Command("attach-idea").description("Attach an experiment to an idea").argument("<experiment>", EXPERIMENT_REFERENCE_DESCRIPTION).requiredOption("--idea <key>", "Idea UUID or Apex backlog key").option("--follow-up", "Attach as a follow-up test").action(async function action5(experimentRef, opts) {
|
|
9898
9997
|
const experiment = await resolveExperiment(experimentRef);
|
|
@@ -9949,7 +10048,7 @@ var results = new Command("results").description("Read experiment results and ti
|
|
|
9949
10048
|
spinner?.stop();
|
|
9950
10049
|
output(
|
|
9951
10050
|
this,
|
|
9952
|
-
|
|
10051
|
+
res.data,
|
|
9953
10052
|
() => printExperimentResults(res.data, opts.currency)
|
|
9954
10053
|
);
|
|
9955
10054
|
} catch (error) {
|
|
@@ -10535,7 +10634,7 @@ var pause = new Command("pause").description("Pause a running experiment").argum
|
|
|
10535
10634
|
res.errorDetails
|
|
10536
10635
|
);
|
|
10537
10636
|
}
|
|
10538
|
-
output(this,
|
|
10637
|
+
output(this, res.data, () => {
|
|
10539
10638
|
spinner.succeed(`Experiment "${exp.name}" is now ${statusBadge("paused")}`);
|
|
10540
10639
|
});
|
|
10541
10640
|
});
|
|
@@ -10557,7 +10656,7 @@ var complete = new Command("complete").description("Complete/stop an experiment"
|
|
|
10557
10656
|
res.errorDetails
|
|
10558
10657
|
);
|
|
10559
10658
|
}
|
|
10560
|
-
output(this,
|
|
10659
|
+
output(this, res.data, () => {
|
|
10561
10660
|
spinner.succeed(`Experiment "${exp.name}" is now ${statusBadge("completed")}`);
|
|
10562
10661
|
});
|
|
10563
10662
|
});
|
|
@@ -10585,7 +10684,7 @@ var del = new Command("delete").alias("rm").description("Delete an experiment").
|
|
|
10585
10684
|
});
|
|
10586
10685
|
rl.close();
|
|
10587
10686
|
if (answer.toLowerCase() !== "y") {
|
|
10588
|
-
console.log("Aborted.");
|
|
10687
|
+
output(this, { aborted: true }, () => console.log("Aborted."));
|
|
10589
10688
|
return;
|
|
10590
10689
|
}
|
|
10591
10690
|
}
|
|
@@ -10600,11 +10699,7 @@ var del = new Command("delete").alias("rm").description("Delete an experiment").
|
|
|
10600
10699
|
res.errorDetails
|
|
10601
10700
|
);
|
|
10602
10701
|
}
|
|
10603
|
-
output(
|
|
10604
|
-
this,
|
|
10605
|
-
{ experiment: { id: exp.id, name: exp.name }, deleted: true },
|
|
10606
|
-
() => spinner.succeed(`Experiment "${exp.name}" deleted.`)
|
|
10607
|
-
);
|
|
10702
|
+
output(this, res.data, () => spinner.succeed(`Experiment "${exp.name}" deleted.`));
|
|
10608
10703
|
});
|
|
10609
10704
|
var pullFilesystem = new Command("pull").description("Pull an experiment as an editable filesystem").argument("<id-or-slug>", EXPERIMENT_REFERENCE_DESCRIPTION).option("--out <path>", "Target folder").action(async function action13(idOrSlug, opts) {
|
|
10610
10705
|
const creds = requireCredentials();
|
|
@@ -10773,7 +10868,7 @@ var applyFilesystem = new Command("apply").option("--sync", "Refresh local autho
|
|
|
10773
10868
|
);
|
|
10774
10869
|
}
|
|
10775
10870
|
if (!ok) {
|
|
10776
|
-
console.log("Aborted.");
|
|
10871
|
+
output(this, { aborted: true }, () => console.log("Aborted."));
|
|
10777
10872
|
return;
|
|
10778
10873
|
}
|
|
10779
10874
|
}
|
|
@@ -10879,7 +10974,7 @@ var qaStatus = new Command("status").description(
|
|
|
10879
10974
|
resolved.folder,
|
|
10880
10975
|
resolved.experimentId
|
|
10881
10976
|
);
|
|
10882
|
-
output(this,
|
|
10977
|
+
output(this, res.data, () => printQaRun(res.data.run));
|
|
10883
10978
|
} catch (error) {
|
|
10884
10979
|
spinner.fail("Failed to fetch QA run");
|
|
10885
10980
|
throw error;
|
|
@@ -10921,7 +11016,7 @@ var qaCheck = new Command("check").description("Update one QA checklist item wit
|
|
|
10921
11016
|
resolved.folder,
|
|
10922
11017
|
resolved.experimentId
|
|
10923
11018
|
);
|
|
10924
|
-
const data = opts.summary ? qaSummary(run3, run3.checklist.find((item) => item.id === opts.item) ?? null) :
|
|
11019
|
+
const data = opts.summary ? qaSummary(run3, run3.checklist.find((item) => item.id === opts.item) ?? null) : res.data;
|
|
10925
11020
|
output(this, data, () => {
|
|
10926
11021
|
spinner.succeed("Updated QA checklist");
|
|
10927
11022
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
@@ -10970,7 +11065,7 @@ var qaNotes = new Command("notes").description("Update QA run notes or acceptanc
|
|
|
10970
11065
|
const data = opts.summary ? qaSummary(run3, {
|
|
10971
11066
|
notes: run3.notes,
|
|
10972
11067
|
acceptanceCriteriaSummary: run3.acceptanceCriteriaSummary
|
|
10973
|
-
}) :
|
|
11068
|
+
}) : res.data;
|
|
10974
11069
|
output(this, data, () => {
|
|
10975
11070
|
spinner.succeed("Updated QA notes");
|
|
10976
11071
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
@@ -11051,11 +11146,7 @@ var qaReopen = new Command("reopen").description("Reopen QA and clear scheduled
|
|
|
11051
11146
|
resolved.folder,
|
|
11052
11147
|
resolved.experimentId
|
|
11053
11148
|
);
|
|
11054
|
-
output(
|
|
11055
|
-
this,
|
|
11056
|
-
{ experimentId: resolved.experimentId, qaStatus: "open" },
|
|
11057
|
-
() => spinner.succeed(`QA reopened for ${resolved.label}`)
|
|
11058
|
-
);
|
|
11149
|
+
output(this, res.data, () => spinner.succeed(`QA reopened for ${resolved.label}`));
|
|
11059
11150
|
} catch (error) {
|
|
11060
11151
|
spinner.fail("Failed to reopen QA");
|
|
11061
11152
|
throw error;
|
|
@@ -11162,7 +11253,7 @@ var qaEvidence = new Command("evidence").description("Attach screenshot jobs or
|
|
|
11162
11253
|
const data = opts.summary ? qaSummary(
|
|
11163
11254
|
run3,
|
|
11164
11255
|
run3.evidenceRecords.filter((record2) => !previousIds.has(record2.id))
|
|
11165
|
-
) :
|
|
11256
|
+
) : response.data;
|
|
11166
11257
|
output(this, data, () => {
|
|
11167
11258
|
if (opts.summary) process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
11168
11259
|
`);
|
|
@@ -12016,7 +12107,10 @@ function cleanupResetJs(experiment) {
|
|
|
12016
12107
|
function runAbHarness(args, cwd) {
|
|
12017
12108
|
const bin = process.env.AB_HARNESS_BIN || "ab-harness";
|
|
12018
12109
|
return new Promise((resolve2, reject) => {
|
|
12019
|
-
const child = (0, import_node_child_process6.spawn)(bin, args, {
|
|
12110
|
+
const child = (0, import_node_child_process6.spawn)(bin, args, {
|
|
12111
|
+
cwd,
|
|
12112
|
+
stdio: isJsonMode() ? ["inherit", 2, "inherit"] : "inherit"
|
|
12113
|
+
});
|
|
12020
12114
|
child.on("error", reject);
|
|
12021
12115
|
child.on("exit", (code) => {
|
|
12022
12116
|
if (code === 0) resolve2();
|
|
@@ -13025,29 +13119,36 @@ function printManifestPlan(manifest) {
|
|
|
13025
13119
|
var trackingCommand = new Command("tracking").description(
|
|
13026
13120
|
"Create Apex-first tracking ingestion manifests and QA handoffs"
|
|
13027
13121
|
);
|
|
13028
|
-
trackingCommand.command("inspect").description("Create a local tracking manifest from funnel URLs").argument("<urls...>", "Landing, storefront, checkout, or confirmation URLs").option("--shop-id <id>", "Apex shop ID for snippet generation").option("--endpoint <url>", "Apex Worker endpoint", "https://events.drip-apex.com").option("--out <path>", "Manifest output path", defaultManifestPath()).action((urls, opts)
|
|
13122
|
+
trackingCommand.command("inspect").description("Create a local tracking manifest from funnel URLs").argument("<urls...>", "Landing, storefront, checkout, or confirmation URLs").option("--shop-id <id>", "Apex shop ID for snippet generation").option("--endpoint <url>", "Apex Worker endpoint", "https://events.drip-apex.com").option("--out <path>", "Manifest output path", defaultManifestPath()).action(function(urls, opts) {
|
|
13029
13123
|
const manifest = buildManifest(urls, opts);
|
|
13030
13124
|
const outPath = manifestPath(opts.out);
|
|
13031
13125
|
writeManifest(outPath, manifest);
|
|
13032
|
-
|
|
13033
|
-
if (manifest.recommendedCookieDomain) {
|
|
13034
|
-
console.log(`Recommended cookie domain: ${source_default.cyan(manifest.recommendedCookieDomain)}`);
|
|
13035
|
-
}
|
|
13036
|
-
if (manifest.snippet.html) {
|
|
13037
|
-
console.log(`Head snippet: ${source_default.cyan(manifest.snippet.html)}`);
|
|
13038
|
-
} else {
|
|
13126
|
+
if (!manifest.snippet.html)
|
|
13039
13127
|
printWarning("No shop ID provided, so the manifest has no install snippet.");
|
|
13040
|
-
}
|
|
13128
|
+
output(this, { path: outPath, manifest }, () => {
|
|
13129
|
+
printSuccess(`Wrote ${outPath}`);
|
|
13130
|
+
if (manifest.recommendedCookieDomain) {
|
|
13131
|
+
console.log(`Recommended cookie domain: ${source_default.cyan(manifest.recommendedCookieDomain)}`);
|
|
13132
|
+
}
|
|
13133
|
+
if (manifest.snippet.html) {
|
|
13134
|
+
console.log(`Head snippet: ${source_default.cyan(manifest.snippet.html)}`);
|
|
13135
|
+
}
|
|
13136
|
+
});
|
|
13041
13137
|
});
|
|
13042
|
-
trackingCommand.command("plan").description("Print the implementation plan from a tracking manifest").argument("[manifest]", "Tracking manifest path", defaultManifestPath()).action((input)
|
|
13043
|
-
|
|
13138
|
+
trackingCommand.command("plan").description("Print the implementation plan from a tracking manifest").argument("[manifest]", "Tracking manifest path", defaultManifestPath()).action(function(input) {
|
|
13139
|
+
const filePath = manifestPath(input);
|
|
13140
|
+
const manifest = readManifest(filePath);
|
|
13141
|
+
output(this, { path: filePath, manifest }, () => printManifestPlan(manifest));
|
|
13044
13142
|
});
|
|
13045
|
-
trackingCommand.command("qa").description("Print the QA checklist for a tracking manifest").argument("[manifest]", "Tracking manifest path", defaultManifestPath()).action((input)
|
|
13046
|
-
const
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
console.log(
|
|
13143
|
+
trackingCommand.command("qa").description("Print the QA checklist for a tracking manifest").argument("[manifest]", "Tracking manifest path", defaultManifestPath()).action(function(input) {
|
|
13144
|
+
const filePath = manifestPath(input);
|
|
13145
|
+
const manifest = readManifest(filePath);
|
|
13146
|
+
output(this, { path: filePath, checks: manifest.qa.checks }, () => {
|
|
13147
|
+
console.log(source_default.bold("Apex tracking QA"));
|
|
13148
|
+
console.log();
|
|
13149
|
+
manifest.qa.checks.forEach((check, index) => {
|
|
13150
|
+
console.log(`${index + 1}. ${check}`);
|
|
13151
|
+
});
|
|
13051
13152
|
});
|
|
13052
13153
|
});
|
|
13053
13154
|
trackingCommand.command("verify").description("Verify live tracking events for the current shop").option("--minutes <n>", "Lookback window in minutes", "120").option("--limit <n>", "Recent events to include", "20").option("--experiment <id>", "Filter to one experiment ID").option("--event-type <type>", "Filter to one event type; repeat with comma-separated values").action(async function action33(opts) {
|
|
@@ -13066,7 +13167,7 @@ trackingCommand.command("verify").description("Verify live tracking events for t
|
|
|
13066
13167
|
res.errorDetails
|
|
13067
13168
|
);
|
|
13068
13169
|
}
|
|
13069
|
-
output(this,
|
|
13170
|
+
output(this, res.data, () => {
|
|
13070
13171
|
const totals = res.data.totals;
|
|
13071
13172
|
console.log(source_default.bold("Apex tracking verification"));
|
|
13072
13173
|
console.log();
|
|
@@ -13153,8 +13254,9 @@ trackingCommand.command("latency").description("Measure forced-preview versus na
|
|
|
13153
13254
|
].join("/")
|
|
13154
13255
|
])
|
|
13155
13256
|
);
|
|
13257
|
+
console.log("Times in ms. Fewer than 5 measured samples: -.");
|
|
13156
13258
|
console.log(
|
|
13157
|
-
"
|
|
13259
|
+
"Position: runtime unchanged (inline config decides within tens of ms; forced previews fetch config over the network and are not representative)"
|
|
13158
13260
|
);
|
|
13159
13261
|
});
|
|
13160
13262
|
});
|
|
@@ -13370,7 +13472,7 @@ var list2 = new Command("list").alias("ls").description("List goals").option("-n
|
|
|
13370
13472
|
if (!res.ok || !res.data) {
|
|
13371
13473
|
fail(this, res.error ?? "Failed to list goals", classifyStatus(res.status), res.errorDetails);
|
|
13372
13474
|
}
|
|
13373
|
-
output(this,
|
|
13475
|
+
output(this, res.data, () => {
|
|
13374
13476
|
if (res.data.data.length === 0) {
|
|
13375
13477
|
console.log(source_default.dim("No goals found."));
|
|
13376
13478
|
return;
|
|
@@ -13412,7 +13514,7 @@ var create2 = new Command("create").description("Create a goal").requiredOption(
|
|
|
13412
13514
|
res.errorDetails
|
|
13413
13515
|
);
|
|
13414
13516
|
}
|
|
13415
|
-
output(this,
|
|
13517
|
+
output(this, res.data, () => printGoal(res.data));
|
|
13416
13518
|
});
|
|
13417
13519
|
var update2 = new Command("update").description("Update a goal").argument("<id>", "Goal ID").option("--name <name>", "Goal name").option("--type <type>", "click|pageview|custom|revenue").option("--measurement <measurement>", "conversion|value").option(
|
|
13418
13520
|
"--value-property <property>",
|
|
@@ -13444,7 +13546,7 @@ var update2 = new Command("update").description("Update a goal").argument("<id>"
|
|
|
13444
13546
|
res.errorDetails
|
|
13445
13547
|
);
|
|
13446
13548
|
}
|
|
13447
|
-
output(this,
|
|
13549
|
+
output(this, res.data, () => printGoal(res.data));
|
|
13448
13550
|
});
|
|
13449
13551
|
var test = new Command("test").description("Dry run a goal URL pattern against traffic").option(
|
|
13450
13552
|
"--pattern <regex>",
|
|
@@ -13541,9 +13643,8 @@ var suggest = new Command("suggest").description("Suggest goals and funnels from
|
|
|
13541
13643
|
classifyStatus(res.status),
|
|
13542
13644
|
res.errorDetails
|
|
13543
13645
|
);
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
for (const goal of res.data.goals) {
|
|
13646
|
+
if (!shouldUseJson(this)) printSuggestions(res.data);
|
|
13647
|
+
for (const goal of opts.create ? res.data.goals : []) {
|
|
13547
13648
|
console.error(`Would create ${goal.type} goal: ${goal.name}`);
|
|
13548
13649
|
if (!opts.yes) {
|
|
13549
13650
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
@@ -13578,6 +13679,7 @@ var suggest = new Command("suggest").description("Suggest goals and funnels from
|
|
|
13578
13679
|
created.errorDetails
|
|
13579
13680
|
);
|
|
13580
13681
|
}
|
|
13682
|
+
output(this, res.data, () => void 0);
|
|
13581
13683
|
});
|
|
13582
13684
|
var goalsCommand = new Command("goals").description("Manage conversion and revenue goals").addCommand(list2).addCommand(create2).addCommand(update2).addCommand(test).addCommand(suggest).addHelpText(
|
|
13583
13685
|
"after",
|
|
@@ -13632,7 +13734,7 @@ var list3 = new Command("list").alias("ls").description("List funnels").action(a
|
|
|
13632
13734
|
);
|
|
13633
13735
|
output(
|
|
13634
13736
|
this,
|
|
13635
|
-
|
|
13737
|
+
res.data,
|
|
13636
13738
|
() => printTable(
|
|
13637
13739
|
["NAME", "ID", "STEPS"],
|
|
13638
13740
|
res.data.data.map((f) => [f.name.slice(0, 36), f.id, String(f.steps.length)]),
|
|
@@ -13652,7 +13754,7 @@ var create3 = new Command("create").description("Create a funnel").requiredOptio
|
|
|
13652
13754
|
classifyStatus(res.status),
|
|
13653
13755
|
res.errorDetails
|
|
13654
13756
|
);
|
|
13655
|
-
output(this,
|
|
13757
|
+
output(this, res.data, () => printFunnel(res.data));
|
|
13656
13758
|
});
|
|
13657
13759
|
var update3 = new Command("update").description("Replace a funnel's steps").argument("<id>", "Funnel ID").requiredOption("--steps-file <file>", "JSON array of { label, pattern }").action(async function action41(id, opts) {
|
|
13658
13760
|
const res = await updateFunnel(requireCredentials(), id, {
|
|
@@ -13665,7 +13767,7 @@ var update3 = new Command("update").description("Replace a funnel's steps").argu
|
|
|
13665
13767
|
classifyStatus(res.status),
|
|
13666
13768
|
res.errorDetails
|
|
13667
13769
|
);
|
|
13668
|
-
output(this,
|
|
13770
|
+
output(this, res.data, () => printFunnel(res.data));
|
|
13669
13771
|
});
|
|
13670
13772
|
var del2 = new Command("delete").description("Delete a funnel").argument("<id>", "Funnel ID").action(async function action42(id) {
|
|
13671
13773
|
const res = await deleteFunnel(requireCredentials(), id);
|
|
@@ -13676,7 +13778,7 @@ var del2 = new Command("delete").description("Delete a funnel").argument("<id>",
|
|
|
13676
13778
|
classifyStatus(res.status),
|
|
13677
13779
|
res.errorDetails
|
|
13678
13780
|
);
|
|
13679
|
-
output(this,
|
|
13781
|
+
output(this, res.data ?? null, () => console.log(`Deleted funnel ${id}`));
|
|
13680
13782
|
});
|
|
13681
13783
|
var run = new Command("run").description("Run funnel analysis").argument("<id>", "Funnel ID").option("--days <n>", "Analysis window", "30").action(async function action43(id, opts) {
|
|
13682
13784
|
if (!/^[1-9]\d*$/.test(opts.days))
|
|
@@ -13689,7 +13791,7 @@ var run = new Command("run").description("Run funnel analysis").argument("<id>",
|
|
|
13689
13791
|
fail(this, res.error ?? "Failed to run funnel", classifyStatus(res.status), res.errorDetails);
|
|
13690
13792
|
output(
|
|
13691
13793
|
this,
|
|
13692
|
-
|
|
13794
|
+
res.data,
|
|
13693
13795
|
() => printTable(
|
|
13694
13796
|
["STEP", "LABEL", "VISITORS", "DROP-OFF"],
|
|
13695
13797
|
res.data.steps.map((s) => [
|
|
@@ -13764,8 +13866,8 @@ async function load2(command) {
|
|
|
13764
13866
|
return result.data;
|
|
13765
13867
|
}
|
|
13766
13868
|
var list4 = new Command("list").alias("ls").description("List runtime environments and mapped domains").action(async function action45() {
|
|
13767
|
-
const
|
|
13768
|
-
output(this,
|
|
13869
|
+
const body5 = await load2(this);
|
|
13870
|
+
output(this, body5, () => printEnvironments(body5.environments.items));
|
|
13769
13871
|
});
|
|
13770
13872
|
var setDomain = new Command("set-domain").description("Map a domain to a runtime environment").argument("<domain>", "Domain to map").requiredOption("--environment <env>", "Environment key").action(async function action46(domain, opts) {
|
|
13771
13873
|
const normalizedDomain = normalizeEnvironmentDomain(domain);
|
|
@@ -13808,11 +13910,7 @@ var setDomain = new Command("set-domain").description("Map a domain to a runtime
|
|
|
13808
13910
|
);
|
|
13809
13911
|
}
|
|
13810
13912
|
warnOnPrecompileError(this, result.data.precompile);
|
|
13811
|
-
output(
|
|
13812
|
-
this,
|
|
13813
|
-
{ environments: result.data.environments, precompile: result.data.precompile },
|
|
13814
|
-
() => printEnvironments(result.data.environments.items)
|
|
13815
|
-
);
|
|
13913
|
+
output(this, result.data, () => printEnvironments(result.data.environments.items));
|
|
13816
13914
|
});
|
|
13817
13915
|
var removeDomain = new Command("remove-domain").description("Remove a domain mapping").argument("<domain>", "Domain to remove").action(async function action47(domain) {
|
|
13818
13916
|
const normalizedDomain = normalizeEnvironmentDomain(domain);
|
|
@@ -13843,11 +13941,7 @@ var removeDomain = new Command("remove-domain").description("Remove a domain map
|
|
|
13843
13941
|
);
|
|
13844
13942
|
}
|
|
13845
13943
|
warnOnPrecompileError(this, result.data.precompile);
|
|
13846
|
-
output(
|
|
13847
|
-
this,
|
|
13848
|
-
{ environments: result.data.environments, precompile: result.data.precompile },
|
|
13849
|
-
() => printEnvironments(result.data.environments.items)
|
|
13850
|
-
);
|
|
13944
|
+
output(this, result.data, () => printEnvironments(result.data.environments.items));
|
|
13851
13945
|
});
|
|
13852
13946
|
var environmentsCommand = new Command("environments").description("Manage runtime environments and domain mappings").addCommand(list4).addCommand(setDomain).addCommand(removeDomain);
|
|
13853
13947
|
|
|
@@ -15724,7 +15818,9 @@ async function runDoctor(options = {}) {
|
|
|
15724
15818
|
null,
|
|
15725
15819
|
res.error ?? `Failed to load ${label}`,
|
|
15726
15820
|
classifyStatus(res.status),
|
|
15727
|
-
res.errorDetails
|
|
15821
|
+
res.errorDetails,
|
|
15822
|
+
// Parallel reads: name this response's envelope explicitly.
|
|
15823
|
+
apiFailureOf(res)
|
|
15728
15824
|
);
|
|
15729
15825
|
}
|
|
15730
15826
|
for (const [label, res] of [
|
|
@@ -16085,7 +16181,7 @@ function analyticsSubcommand(name, description, defaultDays) {
|
|
|
16085
16181
|
classifyStatus(result.status),
|
|
16086
16182
|
result.errorDetails
|
|
16087
16183
|
);
|
|
16088
|
-
output(this,
|
|
16184
|
+
output(this, result.data, () => printAnalytics(result.data.data));
|
|
16089
16185
|
});
|
|
16090
16186
|
}
|
|
16091
16187
|
function urlsCommand() {
|
|
@@ -16922,7 +17018,7 @@ var list6 = new Command("list").alias("ls").description("List flags").option("-n
|
|
|
16922
17018
|
fail(this, r.error ?? "Failed to list", classifyStatus(r.status), r.errorDetails);
|
|
16923
17019
|
output(
|
|
16924
17020
|
this,
|
|
16925
|
-
|
|
17021
|
+
r.data,
|
|
16926
17022
|
() => printTable(
|
|
16927
17023
|
["KEY/NAME", "STATE", "UPDATED"],
|
|
16928
17024
|
r.data.data.map((x) => [x.key || x.name, x.status, x.updated_at ?? "-"]),
|
|
@@ -16934,7 +17030,7 @@ var get5 = new Command("get").description("Get a flag").argument("<id>").action(
|
|
|
16934
17030
|
const r = await getManagedDelivery(requireCredentials(), kind, id);
|
|
16935
17031
|
if (!r.ok || !r.data)
|
|
16936
17032
|
fail(this, r.error ?? "Failed to get", classifyStatus(r.status), r.errorDetails);
|
|
16937
|
-
output(this,
|
|
17033
|
+
output(this, r.data, () => detail(r.data));
|
|
16938
17034
|
});
|
|
16939
17035
|
var status = new Command("status").description("Check whether a flag publication is live at the edge").argument("<id>").action(async function(id) {
|
|
16940
17036
|
const r = await getFlagStatus(requireCredentials(), id);
|
|
@@ -16995,7 +17091,7 @@ function write(name) {
|
|
|
16995
17091
|
const r = name === "create" ? await createManagedDelivery(requireCredentials(), kind, b) : await updateManagedDelivery(requireCredentials(), kind, id, b);
|
|
16996
17092
|
if (!r.ok || !r.data)
|
|
16997
17093
|
fail(this, r.error ?? `Failed to ${name}`, classifyStatus(r.status), r.errorDetails);
|
|
16998
|
-
output(this,
|
|
17094
|
+
output(this, r.data, () => detail(r.data));
|
|
16999
17095
|
});
|
|
17000
17096
|
return c;
|
|
17001
17097
|
}
|
|
@@ -17004,7 +17100,7 @@ function lifecycle(action74) {
|
|
|
17004
17100
|
const r = await transitionManagedDelivery(requireCredentials(), kind, id, action74);
|
|
17005
17101
|
if (!r.ok || !r.data)
|
|
17006
17102
|
fail(this, r.error ?? `Failed to ${action74}`, classifyStatus(r.status), r.errorDetails);
|
|
17007
|
-
output(this,
|
|
17103
|
+
output(this, r.data, () => detail(r.data));
|
|
17008
17104
|
});
|
|
17009
17105
|
}
|
|
17010
17106
|
var flagsCommand = new Command("flags").description("Manage flags").addCommand(list6).addCommand(get5).addCommand(status).addCommand(write("create")).addCommand(write("update")).addCommand(lifecycle("activate")).addCommand(lifecycle("pause")).addCommand(lifecycle("archive")).addHelpText(
|
|
@@ -17121,7 +17217,7 @@ var list7 = new Command("list").alias("ls").description("List backlog items iden
|
|
|
17121
17217
|
fail(this, r.error ?? "Failed to list", classifyStatus(r.status), r.errorDetails);
|
|
17122
17218
|
output(
|
|
17123
17219
|
this,
|
|
17124
|
-
|
|
17220
|
+
r.data,
|
|
17125
17221
|
() => printTable(
|
|
17126
17222
|
["ID", "NAME", "STATE"],
|
|
17127
17223
|
r.data.data.map((x) => [
|
|
@@ -17138,7 +17234,7 @@ var get6 = new Command("get").description("Get a backlog item identified as apex
|
|
|
17138
17234
|
if (!r.ok || !r.data)
|
|
17139
17235
|
fail(this, r.error ?? "Failed to get", classifyStatus(r.status), r.errorDetails);
|
|
17140
17236
|
const labels = await fieldLabels(this, r.data);
|
|
17141
|
-
output(this,
|
|
17237
|
+
output(this, r.data, () => detail2(r.data, labels));
|
|
17142
17238
|
});
|
|
17143
17239
|
function write2(action74) {
|
|
17144
17240
|
const c = new Command(action74).description(
|
|
@@ -17165,7 +17261,7 @@ function write2(action74) {
|
|
|
17165
17261
|
if (!r.ok || !r.data)
|
|
17166
17262
|
fail(this, r.error ?? `Failed to ${action74}`, classifyStatus(r.status), r.errorDetails);
|
|
17167
17263
|
const labels = await fieldLabels(this, r.data);
|
|
17168
|
-
output(this,
|
|
17264
|
+
output(this, r.data, () => detail2(r.data, labels));
|
|
17169
17265
|
});
|
|
17170
17266
|
return c;
|
|
17171
17267
|
}
|
|
@@ -17178,13 +17274,13 @@ var archive = new Command("archive").description("Archive a backlog item with a
|
|
|
17178
17274
|
const r = await archiveBacklogInsight(requireCredentials(), id, opts.reason.trim());
|
|
17179
17275
|
if (!r.ok || !r.data)
|
|
17180
17276
|
fail(this, r.error ?? "Failed to archive", classifyStatus(r.status), r.errorDetails);
|
|
17181
|
-
output(this,
|
|
17277
|
+
output(this, r.data, () => console.log(`Archived ${id}`));
|
|
17182
17278
|
});
|
|
17183
17279
|
var restore = new Command("restore").description("Restore an archived backlog item").argument("<id>", "backlog item ID").action(async function(id) {
|
|
17184
17280
|
const r = await restoreBacklogInsight(requireCredentials(), id);
|
|
17185
17281
|
if (!r.ok || !r.data)
|
|
17186
17282
|
fail(this, r.error ?? "Failed to restore", classifyStatus(r.status), r.errorDetails);
|
|
17187
|
-
output(this,
|
|
17283
|
+
output(this, r.data, () => console.log(`Restored ${id}`));
|
|
17188
17284
|
});
|
|
17189
17285
|
var remove2 = new Command("delete").description("Delete a backlog item").argument("<id>", "backlog item ID").option("-f, --force", "Skip confirmation").action(async function(id, opts) {
|
|
17190
17286
|
if (!opts.force) {
|
|
@@ -17201,14 +17297,14 @@ var remove2 = new Command("delete").description("Delete a backlog item").argumen
|
|
|
17201
17297
|
);
|
|
17202
17298
|
rl.close();
|
|
17203
17299
|
if (answer.toLowerCase() !== "y") {
|
|
17204
|
-
console.log("Aborted.");
|
|
17300
|
+
output(this, { aborted: true }, () => console.log("Aborted."));
|
|
17205
17301
|
return;
|
|
17206
17302
|
}
|
|
17207
17303
|
}
|
|
17208
17304
|
const r = await deleteInsight(requireCredentials(), kind2, id);
|
|
17209
17305
|
if (!r.ok || !r.data)
|
|
17210
17306
|
fail(this, r.error ?? "Failed to delete", classifyStatus(r.status), r.errorDetails);
|
|
17211
|
-
output(this,
|
|
17307
|
+
output(this, r.data, () => console.log(`Deleted ${id}`));
|
|
17212
17308
|
});
|
|
17213
17309
|
function fieldDetail(field) {
|
|
17214
17310
|
console.log();
|
|
@@ -17235,7 +17331,7 @@ var fieldsList = new Command("list").alias("ls").description("List the shop's id
|
|
|
17235
17331
|
fail(this, r.error ?? "Failed to list fields", classifyStatus(r.status), r.errorDetails);
|
|
17236
17332
|
output(
|
|
17237
17333
|
this,
|
|
17238
|
-
|
|
17334
|
+
r.data,
|
|
17239
17335
|
() => printTable(
|
|
17240
17336
|
["KEY", "LABEL", "TYPE", "REQUIRED", "CLIENT"],
|
|
17241
17337
|
r.data.data.map((field) => [
|
|
@@ -17270,7 +17366,7 @@ var fieldsCreate = new Command("create").description("Add an idea field").requir
|
|
|
17270
17366
|
});
|
|
17271
17367
|
if (!r.ok || !r.data)
|
|
17272
17368
|
fail(this, r.error ?? "Failed to create field", classifyStatus(r.status), r.errorDetails);
|
|
17273
|
-
output(this,
|
|
17369
|
+
output(this, r.data, () => fieldDetail(r.data));
|
|
17274
17370
|
});
|
|
17275
17371
|
var fieldsUpdate = new Command("update").description("Update an idea field").argument("<id>", "field ID").option("--label <text>", "What the field is called").option(
|
|
17276
17372
|
"--option <value>",
|
|
@@ -17293,13 +17389,13 @@ var fieldsUpdate = new Command("update").description("Update an idea field").arg
|
|
|
17293
17389
|
const r = await updateBacklogField(requireCredentials(), id, body5);
|
|
17294
17390
|
if (!r.ok || !r.data)
|
|
17295
17391
|
fail(this, r.error ?? "Failed to update field", classifyStatus(r.status), r.errorDetails);
|
|
17296
|
-
output(this,
|
|
17392
|
+
output(this, r.data, () => fieldDetail(r.data));
|
|
17297
17393
|
});
|
|
17298
17394
|
var fieldsArchive = new Command("archive").description("Archive an idea field; values already on ideas are kept").argument("<id>", "field ID").action(async function(id) {
|
|
17299
17395
|
const r = await archiveBacklogField(requireCredentials(), id);
|
|
17300
17396
|
if (!r.ok || !r.data)
|
|
17301
17397
|
fail(this, r.error ?? "Failed to archive field", classifyStatus(r.status), r.errorDetails);
|
|
17302
|
-
output(this,
|
|
17398
|
+
output(this, r.data, () => fieldDetail(r.data));
|
|
17303
17399
|
});
|
|
17304
17400
|
var fields2 = new Command("fields").description("Manage the shop's own idea fields").addCommand(fieldsList).addCommand(fieldsCreate).addCommand(fieldsUpdate).addCommand(fieldsArchive);
|
|
17305
17401
|
var backlogCommand = new Command("backlog").description("Manage backlog").addCommand(list7).addCommand(get6).addCommand(write2("create")).addCommand(write2("update")).addCommand(archive).addCommand(restore).addCommand(remove2).addCommand(fields2);
|
|
@@ -17346,7 +17442,7 @@ var list8 = new Command("list").alias("ls").description("List signals").option("
|
|
|
17346
17442
|
fail(this, r.error ?? "Failed to list", classifyStatus(r.status), r.errorDetails);
|
|
17347
17443
|
output(
|
|
17348
17444
|
this,
|
|
17349
|
-
|
|
17445
|
+
r.data,
|
|
17350
17446
|
() => printTable(
|
|
17351
17447
|
["ID", "NAME", "STATE"],
|
|
17352
17448
|
r.data.data.map((x) => [
|
|
@@ -17362,7 +17458,7 @@ var get7 = new Command("get").description("Get a signal").argument("<id>", "sign
|
|
|
17362
17458
|
const r = await getInsight(requireCredentials(), kind3, id);
|
|
17363
17459
|
if (!r.ok || !r.data)
|
|
17364
17460
|
fail(this, r.error ?? "Failed to get", classifyStatus(r.status), r.errorDetails);
|
|
17365
|
-
output(this,
|
|
17461
|
+
output(this, r.data, () => detail3(r.data));
|
|
17366
17462
|
});
|
|
17367
17463
|
function write3(action74) {
|
|
17368
17464
|
const c = new Command(action74).description(
|
|
@@ -17382,7 +17478,7 @@ function write3(action74) {
|
|
|
17382
17478
|
const r = action74 === "create" ? await createInsight(requireCredentials(), kind3, body5) : await updateInsight(requireCredentials(), kind3, id, body5);
|
|
17383
17479
|
if (!r.ok || !r.data)
|
|
17384
17480
|
fail(this, r.error ?? `Failed to ${action74}`, classifyStatus(r.status), r.errorDetails);
|
|
17385
|
-
output(this,
|
|
17481
|
+
output(this, r.data, () => detail3(r.data));
|
|
17386
17482
|
});
|
|
17387
17483
|
return c;
|
|
17388
17484
|
}
|
|
@@ -17390,7 +17486,7 @@ var remove3 = new Command("delete").alias("archive").description("Delete or arch
|
|
|
17390
17486
|
const r = await deleteInsight(requireCredentials(), kind3, id);
|
|
17391
17487
|
if (!r.ok || !r.data)
|
|
17392
17488
|
fail(this, r.error ?? "Failed to delete", classifyStatus(r.status), r.errorDetails);
|
|
17393
|
-
output(this,
|
|
17489
|
+
output(this, r.data, () => console.log(`Deleted ${id}`));
|
|
17394
17490
|
});
|
|
17395
17491
|
var signalsCommand = new Command("signals").description("Manage signals").addCommand(list8).addCommand(get7).addCommand(write3("create")).addCommand(write3("update")).addCommand(remove3);
|
|
17396
17492
|
|
|
@@ -17439,7 +17535,7 @@ var list9 = new Command("list").alias("ls").description("List personalizations")
|
|
|
17439
17535
|
fail(this, r.error ?? "Failed to list", classifyStatus(r.status), r.errorDetails);
|
|
17440
17536
|
output(
|
|
17441
17537
|
this,
|
|
17442
|
-
|
|
17538
|
+
r.data,
|
|
17443
17539
|
() => printTable(
|
|
17444
17540
|
["KEY/NAME", "STATE", "UPDATED"],
|
|
17445
17541
|
r.data.data.map((x) => [x.key || x.name, x.status, x.updated_at ?? "-"]),
|
|
@@ -17451,7 +17547,7 @@ var get8 = new Command("get").description("Get a personalization").argument("<id
|
|
|
17451
17547
|
const r = await getManagedDelivery(requireCredentials(), kind4, id);
|
|
17452
17548
|
if (!r.ok || !r.data)
|
|
17453
17549
|
fail(this, r.error ?? "Failed to get", classifyStatus(r.status), r.errorDetails);
|
|
17454
|
-
output(this,
|
|
17550
|
+
output(this, r.data, () => detail4(r.data));
|
|
17455
17551
|
});
|
|
17456
17552
|
function write4(name) {
|
|
17457
17553
|
const c = new Command(name).description(
|
|
@@ -17469,7 +17565,7 @@ function write4(name) {
|
|
|
17469
17565
|
const r = name === "create" ? await createManagedDelivery(requireCredentials(), kind4, b) : await updateManagedDelivery(requireCredentials(), kind4, id, b);
|
|
17470
17566
|
if (!r.ok || !r.data)
|
|
17471
17567
|
fail(this, r.error ?? `Failed to ${name}`, classifyStatus(r.status), r.errorDetails);
|
|
17472
|
-
output(this,
|
|
17568
|
+
output(this, r.data, () => detail4(r.data));
|
|
17473
17569
|
});
|
|
17474
17570
|
return c;
|
|
17475
17571
|
}
|
|
@@ -17478,7 +17574,7 @@ function lifecycle2(action74) {
|
|
|
17478
17574
|
const r = await transitionManagedDelivery(requireCredentials(), kind4, id, action74);
|
|
17479
17575
|
if (!r.ok || !r.data)
|
|
17480
17576
|
fail(this, r.error ?? `Failed to ${action74}`, classifyStatus(r.status), r.errorDetails);
|
|
17481
|
-
output(this,
|
|
17577
|
+
output(this, r.data, () => detail4(r.data));
|
|
17482
17578
|
});
|
|
17483
17579
|
}
|
|
17484
17580
|
var personalizationsCommand = new Command("personalizations").description("Manage personalizations").addCommand(list9).addCommand(get8).addCommand(write4("create")).addCommand(write4("update")).addCommand(lifecycle2("activate")).addCommand(lifecycle2("pause")).addCommand(lifecycle2("archive"));
|
|
@@ -17528,7 +17624,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17528
17624
|
const page = response.data;
|
|
17529
17625
|
output(
|
|
17530
17626
|
this,
|
|
17531
|
-
|
|
17627
|
+
page,
|
|
17532
17628
|
() => printTable(
|
|
17533
17629
|
["NAME", "ID", "UPDATED"],
|
|
17534
17630
|
page.data.map((item) => [
|
|
@@ -17554,7 +17650,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17554
17650
|
);
|
|
17555
17651
|
output(
|
|
17556
17652
|
this,
|
|
17557
|
-
|
|
17653
|
+
response.data,
|
|
17558
17654
|
() => console.log(source_default.bold(response.data.name ?? id))
|
|
17559
17655
|
);
|
|
17560
17656
|
})
|
|
@@ -17585,13 +17681,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17585
17681
|
classifyStatus(response.status),
|
|
17586
17682
|
response.errorDetails
|
|
17587
17683
|
);
|
|
17588
|
-
output(
|
|
17589
|
-
this,
|
|
17590
|
-
{
|
|
17591
|
-
[kind5 === "exclusion-groups" ? "exclusion_group" : singular3]: response.data
|
|
17592
|
-
},
|
|
17593
|
-
() => console.log(source_default.green(`${action74}d ${singular3}`))
|
|
17594
|
-
);
|
|
17684
|
+
output(this, response.data, () => console.log(source_default.green(`${action74}d ${singular3}`)));
|
|
17595
17685
|
});
|
|
17596
17686
|
root.addCommand(command);
|
|
17597
17687
|
}
|
|
@@ -17616,7 +17706,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17616
17706
|
});
|
|
17617
17707
|
rl.close();
|
|
17618
17708
|
if (answer.toLowerCase() !== "y") {
|
|
17619
|
-
console.log("Aborted.");
|
|
17709
|
+
output(this, { aborted: true }, () => console.log("Aborted."));
|
|
17620
17710
|
return;
|
|
17621
17711
|
}
|
|
17622
17712
|
}
|
|
@@ -17628,7 +17718,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17628
17718
|
classifyStatus(response.status),
|
|
17629
17719
|
response.errorDetails
|
|
17630
17720
|
);
|
|
17631
|
-
output(this,
|
|
17721
|
+
output(this, response.data ?? null, () => console.log(source_default.green(`Deleted ${singular3}`)));
|
|
17632
17722
|
})
|
|
17633
17723
|
);
|
|
17634
17724
|
if (kind5 === "exclusion-groups")
|
|
@@ -17648,11 +17738,7 @@ function targetingResourceCommand(kind5) {
|
|
|
17648
17738
|
classifyStatus(response.status),
|
|
17649
17739
|
response.errorDetails
|
|
17650
17740
|
);
|
|
17651
|
-
output(
|
|
17652
|
-
this,
|
|
17653
|
-
{ exclusion_group: response.data },
|
|
17654
|
-
() => console.log(source_default.green("Replaced members"))
|
|
17655
|
-
);
|
|
17741
|
+
output(this, response.data, () => console.log(source_default.green("Replaced members")));
|
|
17656
17742
|
})
|
|
17657
17743
|
);
|
|
17658
17744
|
return root;
|
|
@@ -17668,7 +17754,9 @@ var brandCommand = new Command("brand").description("Print the shop brand contex
|
|
|
17668
17754
|
const creds = requireCredentials();
|
|
17669
17755
|
const res = await getBrandContext(creds);
|
|
17670
17756
|
if (res.status === 404) {
|
|
17671
|
-
|
|
17757
|
+
if (shouldUseJson(this)) process.stderr.write(`${NO_PROFILE_MESSAGE}
|
|
17758
|
+
`);
|
|
17759
|
+
output(this, { data: null }, () => {
|
|
17672
17760
|
console.log(source_default.dim(NO_PROFILE_MESSAGE));
|
|
17673
17761
|
});
|
|
17674
17762
|
return;
|
|
@@ -17682,7 +17770,7 @@ var brandCommand = new Command("brand").description("Print the shop brand contex
|
|
|
17682
17770
|
);
|
|
17683
17771
|
}
|
|
17684
17772
|
const brandContext = res.data.data;
|
|
17685
|
-
output(this,
|
|
17773
|
+
output(this, res.data, () => {
|
|
17686
17774
|
if (!brandContext.hasProfile) {
|
|
17687
17775
|
console.log(source_default.dim(NO_PROFILE_MESSAGE));
|
|
17688
17776
|
return;
|
|
@@ -17708,7 +17796,7 @@ var test2 = new Command("test").description("Evaluate experiment URL targeting f
|
|
|
17708
17796
|
res.errorDetails
|
|
17709
17797
|
);
|
|
17710
17798
|
}
|
|
17711
|
-
output(this,
|
|
17799
|
+
output(this, res.data, () => {
|
|
17712
17800
|
console.log(source_default.bold("Apex targeting test"));
|
|
17713
17801
|
console.log();
|
|
17714
17802
|
console.log(`URL: ${source_default.cyan(res.data.url)}`);
|
|
@@ -17782,7 +17870,7 @@ var create4 = new Command("create").description("Create an Apex SOS ticket").opt
|
|
|
17782
17870
|
"--type <type>",
|
|
17783
17871
|
"full_handover|design|development|qa|config|bug|help (internal types require a DRIP account)",
|
|
17784
17872
|
"qa"
|
|
17785
|
-
).option("--loom <url>", "Loom URL with reproduction or QA context").option("--experiment <id>", "Experiment ID").option("--sub-class <text>", "SOS sub-classification").option("--description <text-or-@file>", "Description text or @path").argument("[description]", "Description text").action(async function action64(descriptionArg, opts) {
|
|
17873
|
+
).option("--loom <url>", "Loom URL with reproduction or QA context").option("--experiment <id>", "Experiment ID").option("--backlog-item <id>", "Backlog item ID (internal SOS only)").option("--sub-class <text>", "SOS sub-classification").option("--description <text-or-@file>", "Description text or @path").argument("[description]", "Description text").action(async function action64(descriptionArg, opts) {
|
|
17786
17874
|
if (!SOS_TYPES.has(opts.type)) {
|
|
17787
17875
|
fail(
|
|
17788
17876
|
this,
|
|
@@ -17790,12 +17878,16 @@ var create4 = new Command("create").description("Create an Apex SOS ticket").opt
|
|
|
17790
17878
|
3
|
|
17791
17879
|
);
|
|
17792
17880
|
}
|
|
17881
|
+
if (opts.experiment && opts.backlogItem) {
|
|
17882
|
+
fail(this, "Provide only one of --experiment or --backlog-item", 3);
|
|
17883
|
+
}
|
|
17793
17884
|
const creds = requireCredentials();
|
|
17794
17885
|
const description = readText(opts.description) ?? descriptionArg ?? `Apex CLI ${opts.type} SOS request${opts.loom ? ` with Loom evidence: ${opts.loom}` : "."}`;
|
|
17795
17886
|
const res = await createSos(creds, {
|
|
17796
17887
|
type: opts.type,
|
|
17797
17888
|
description,
|
|
17798
17889
|
experiment_id: opts.experiment ?? null,
|
|
17890
|
+
backlog_item_id: opts.backlogItem ?? null,
|
|
17799
17891
|
sub_class: opts.subClass ?? null,
|
|
17800
17892
|
loom_url: opts.loom ?? null
|
|
17801
17893
|
});
|
|
@@ -17820,7 +17912,7 @@ var mine = new Command("mine").description("List SOS tickets created by this API
|
|
|
17820
17912
|
res.errorDetails
|
|
17821
17913
|
);
|
|
17822
17914
|
}
|
|
17823
|
-
output(this,
|
|
17915
|
+
output(this, res.data, () => {
|
|
17824
17916
|
if (res.data.tickets.length === 0) {
|
|
17825
17917
|
console.log(source_default.dim("No SOS tickets found for this API key."));
|
|
17826
17918
|
return;
|
|
@@ -17921,7 +18013,7 @@ var list12 = new Command("list").alias("ls").description("List organization shop
|
|
|
17921
18013
|
fail(this, r.error ?? "Failed to list shops", classifyStatus(r.status), r.errorDetails);
|
|
17922
18014
|
output(
|
|
17923
18015
|
this,
|
|
17924
|
-
|
|
18016
|
+
r.data,
|
|
17925
18017
|
() => printTable(
|
|
17926
18018
|
["ID", "NAME", "DOMAIN", "TIER"],
|
|
17927
18019
|
r.data.data.map((s) => [s.id, s.name ?? "-", s.domain ?? "-", s.tier ?? "-"]),
|
|
@@ -18699,7 +18791,7 @@ var discoverCommand = new Command("discover").description("Read back the trackin
|
|
|
18699
18791
|
created.errorDetails
|
|
18700
18792
|
);
|
|
18701
18793
|
}
|
|
18702
|
-
output(this,
|
|
18794
|
+
output(this, created.data, () => {
|
|
18703
18795
|
process.stdout.write(`Created dimension ${created.data.id}.
|
|
18704
18796
|
`);
|
|
18705
18797
|
process.stdout.write("Next: open Audience > Attributes in the Apex dashboard.\n");
|
|
@@ -18851,7 +18943,10 @@ async function confirmArchive(command, shopId, force) {
|
|
|
18851
18943
|
return true;
|
|
18852
18944
|
}
|
|
18853
18945
|
var archive2 = new Command("archive").description("Archive a shop and disable Apex delivery").argument("<shopId>", "Shop ID").option("-f, --force", "Skip confirmation").action(async function(shopId, opts) {
|
|
18854
|
-
if (!await confirmArchive(this, shopId, opts.force))
|
|
18946
|
+
if (!await confirmArchive(this, shopId, opts.force)) {
|
|
18947
|
+
output(this, { aborted: true }, () => void 0);
|
|
18948
|
+
return;
|
|
18949
|
+
}
|
|
18855
18950
|
const res = await archiveAdminShop(requireUserCredentials(), shopId);
|
|
18856
18951
|
if (!res.ok || !res.data)
|
|
18857
18952
|
fail(
|
|
@@ -19095,7 +19190,9 @@ var create6 = new Command("create").requiredOption("--name <name>").requiredOpti
|
|
|
19095
19190
|
classifyApiError(res.status, res.errorDetails),
|
|
19096
19191
|
res.errorDetails
|
|
19097
19192
|
);
|
|
19098
|
-
|
|
19193
|
+
if (shouldUseJson(this))
|
|
19194
|
+
process.stderr.write("Warning: this secret will not be shown again.\n");
|
|
19195
|
+
output(this, res.data, () => {
|
|
19099
19196
|
console.error("Warning: this secret will not be shown again.");
|
|
19100
19197
|
console.log(res.data.data.key);
|
|
19101
19198
|
});
|
|
@@ -19392,21 +19489,18 @@ var create7 = new Command("create").description(`Create a webhook. Prints the si
|
|
|
19392
19489
|
await createWebhook(requireCredentials(), { url: opts.url, events }),
|
|
19393
19490
|
"Failed to create webhook"
|
|
19394
19491
|
);
|
|
19395
|
-
|
|
19396
|
-
|
|
19397
|
-
|
|
19398
|
-
|
|
19399
|
-
|
|
19400
|
-
|
|
19401
|
-
|
|
19402
|
-
}
|
|
19403
|
-
(
|
|
19404
|
-
|
|
19405
|
-
|
|
19406
|
-
|
|
19407
|
-
console.log(`Signature verification: ${SIGNATURE_DOC}`);
|
|
19408
|
-
}
|
|
19409
|
-
);
|
|
19492
|
+
if (shouldUseJson(this))
|
|
19493
|
+
process.stderr.write(
|
|
19494
|
+
`Store this signing secret now. Apex will not show it again.
|
|
19495
|
+
Signature verification: ${SIGNATURE_DOC}
|
|
19496
|
+
`
|
|
19497
|
+
);
|
|
19498
|
+
output(this, result, () => {
|
|
19499
|
+
console.log(source_default.green(`Created webhook ${result.id}`));
|
|
19500
|
+
console.log(source_default.yellow("Store this signing secret now. Apex will not show it again."));
|
|
19501
|
+
console.log(result.secret);
|
|
19502
|
+
console.log(`Signature verification: ${SIGNATURE_DOC}`);
|
|
19503
|
+
});
|
|
19410
19504
|
});
|
|
19411
19505
|
var remove4 = new Command("delete").alias("rm").description("Delete a webhook").argument("<id>", "Webhook id").action(async function action70(id) {
|
|
19412
19506
|
requireShopSecretKey(this);
|
|
@@ -19465,7 +19559,7 @@ var update5 = new Command("update").description("Update a webhook URL, events, o
|
|
|
19465
19559
|
await updateWebhook(requireCredentials(), id, body5),
|
|
19466
19560
|
"Failed to update webhook"
|
|
19467
19561
|
);
|
|
19468
|
-
output(this,
|
|
19562
|
+
output(this, result, () => printWebhooks([result]));
|
|
19469
19563
|
});
|
|
19470
19564
|
var test3 = new Command("test").description("Send a signed test event to a webhook").argument("<id>", "Webhook id").action(async function action73(id) {
|
|
19471
19565
|
requireShopSecretKey(this);
|
|
@@ -19660,10 +19754,7 @@ function readFamily(family, label) {
|
|
|
19660
19754
|
fail(this, r.error ?? `Failed to list ${label}`, classifyStatus(r.status), r.errorDetails);
|
|
19661
19755
|
output(
|
|
19662
19756
|
this,
|
|
19663
|
-
|
|
19664
|
-
[family.replace("-", "_")]: r.data.data,
|
|
19665
|
-
pagination: r.data.pagination
|
|
19666
|
-
},
|
|
19757
|
+
r.data,
|
|
19667
19758
|
() => printTable(
|
|
19668
19759
|
["ID", "NAME", "STATUS"],
|
|
19669
19760
|
r.data.data.map((x) => [x.id, x.name ?? "-", x.status ?? "-"]),
|
|
@@ -19675,11 +19766,7 @@ function readFamily(family, label) {
|
|
|
19675
19766
|
const r = await getConfigResource(requireCredentials(), family, id);
|
|
19676
19767
|
if (!r.ok || !r.data)
|
|
19677
19768
|
fail(this, r.error ?? "Failed to get resource", classifyStatus(r.status), r.errorDetails);
|
|
19678
|
-
output(
|
|
19679
|
-
this,
|
|
19680
|
-
{ [family === "assets" ? "asset" : "landing_page"]: r.data },
|
|
19681
|
-
() => show(r.data)
|
|
19682
|
-
);
|
|
19769
|
+
output(this, r.data, () => show(r.data));
|
|
19683
19770
|
});
|
|
19684
19771
|
return { list: list15, get: get10 };
|
|
19685
19772
|
}
|
package/package.json
CHANGED
package/skills/apex-cli/SKILL.md
CHANGED
|
@@ -11,7 +11,9 @@ Start by asking the installed CLI for its live contract:
|
|
|
11
11
|
apex schema --json
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Prefer JSON output. When stdout is piped, Apex emits JSON by default.
|
|
14
|
+
Prefer JSON output. When stdout is piped, Apex emits JSON by default. Stdout then
|
|
15
|
+
carries exactly one JSON document; `data` is the API response body as returned
|
|
16
|
+
(lists at `.data.data[]`), and API failures carry the API error body in `error.api`.
|
|
15
17
|
|
|
16
18
|
## Zero-Experiment Shop Bootstrap
|
|
17
19
|
|