@supercheck/cli 0.1.1-beta.1 → 0.1.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -6
- package/dist/bin/supercheck.js +40 -65
- package/dist/bin/supercheck.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -76,9 +76,11 @@ supercheck upgrade
|
|
|
76
76
|
supercheck test run --local --all --type custom
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
For remote execution with persisted run history, trigger a job:
|
|
80
80
|
```bash
|
|
81
|
-
supercheck
|
|
81
|
+
supercheck job run --id <job-id>
|
|
82
|
+
# or (CI/CD trigger key flow)
|
|
83
|
+
supercheck job trigger <job-id> --wait
|
|
82
84
|
```
|
|
83
85
|
|
|
84
86
|
## Command Reference
|
|
@@ -102,29 +104,55 @@ supercheck upgrade
|
|
|
102
104
|
| `supercheck validate` | Validate local test scripts (same rules as Playground) |
|
|
103
105
|
| `supercheck destroy --force` | Remove all managed resources from the cloud |
|
|
104
106
|
| `supercheck config validate` | Validate your `supercheck.config.ts` |
|
|
107
|
+
| `supercheck config print` | Print resolved `supercheck.config.ts` |
|
|
108
|
+
|
|
109
|
+
> Note: In the current API, status pages are readable/deletable from CLI sync flows, but create/update endpoints are not available.
|
|
105
110
|
|
|
106
111
|
### Jobs & Runs
|
|
107
112
|
|
|
108
113
|
| Command | Description |
|
|
109
114
|
|---|---|
|
|
110
115
|
| `supercheck job list` | List all jobs |
|
|
116
|
+
| `supercheck job get <id>` | Get job details |
|
|
111
117
|
| `supercheck job create --name <name> --tests <test-id...>` | Create a new job with tests |
|
|
112
|
-
| `supercheck job
|
|
118
|
+
| `supercheck job update <id> --name ...` | Update job fields |
|
|
119
|
+
| `supercheck job delete <id>` | Delete a job |
|
|
120
|
+
| `supercheck job keys <jobId>` | List trigger keys for a job |
|
|
121
|
+
| `supercheck job keys create <jobId> --name <name>` | Create a trigger key |
|
|
122
|
+
| `supercheck job keys delete <jobId> <keyId>` | Revoke a trigger key |
|
|
123
|
+
| `supercheck job run --id <job-id>` | Run a job immediately |
|
|
113
124
|
| `supercheck job run --local` | Run a job locally using local test files |
|
|
114
125
|
| `supercheck job trigger <id> --wait` | Trigger a job and wait for completion (CI/CD) |
|
|
115
126
|
| `supercheck run list` | List recent execution runs |
|
|
127
|
+
| `supercheck run get <id>` | Get run details |
|
|
128
|
+
| `supercheck run status <id>` | Get run status |
|
|
129
|
+
| `supercheck run permissions <id>` | Get run permissions |
|
|
116
130
|
| `supercheck run stream <id>` | Stream live console output |
|
|
131
|
+
| `supercheck run cancel <id>` | Cancel a running execution |
|
|
117
132
|
|
|
118
133
|
### Tests & Monitors
|
|
119
134
|
|
|
120
135
|
| Command | Description |
|
|
121
136
|
|---|---|
|
|
122
137
|
| `supercheck test list` | List all tests |
|
|
138
|
+
| `supercheck test get <id>` | Get test details |
|
|
123
139
|
| `supercheck test create` | Create a new test (browser, performance, api, database, custom) |
|
|
140
|
+
| `supercheck test update <id>` | Update a test |
|
|
141
|
+
| `supercheck test delete <id>` | Delete a test |
|
|
124
142
|
| `supercheck test validate` | Validate local test scripts (same rules as Playground) |
|
|
125
|
-
| `supercheck test run` | Run tests locally
|
|
143
|
+
| `supercheck test run` | Run tests locally |
|
|
144
|
+
| `supercheck test tags <id>` | List tags for a test |
|
|
145
|
+
| `supercheck test status <id>` | Stream live status events for a test |
|
|
126
146
|
| `supercheck monitor list` | List all monitors |
|
|
127
|
-
| `supercheck monitor
|
|
147
|
+
| `supercheck monitor get <id>` | Get monitor details |
|
|
148
|
+
| `supercheck monitor results <id>` | Get monitor check results |
|
|
149
|
+
| `supercheck monitor stats <id>` | Get monitor statistics |
|
|
150
|
+
| `supercheck monitor status <id>` | Get current monitor status |
|
|
151
|
+
| `supercheck monitor create ...` | Create a monitor |
|
|
152
|
+
| `supercheck monitor update <id> ...` | Update a monitor |
|
|
153
|
+
| `supercheck monitor delete <id>` | Delete a monitor |
|
|
154
|
+
|
|
155
|
+
`supercheck test run` is local-only. `--cloud`, `--id`, and `--location` are deprecated for direct test execution.
|
|
128
156
|
|
|
129
157
|
### Variables, Tags & Notifications
|
|
130
158
|
|
|
@@ -132,7 +160,7 @@ supercheck upgrade
|
|
|
132
160
|
|---|---|
|
|
133
161
|
| `supercheck var list / get / set / delete` | Manage project variables |
|
|
134
162
|
| `supercheck tag list / create / delete` | Manage tags |
|
|
135
|
-
| `supercheck notification list / delete` | Manage notification providers |
|
|
163
|
+
| `supercheck notification list / get / create / update / delete / test` | Manage notification providers |
|
|
136
164
|
| `supercheck alert history` | View alert history |
|
|
137
165
|
| `supercheck audit` | View audit logs (admin) |
|
|
138
166
|
|
|
@@ -142,6 +170,7 @@ supercheck upgrade
|
|
|
142
170
|
|---|---|
|
|
143
171
|
| `supercheck health` | Check API health |
|
|
144
172
|
| `supercheck locations` | List available execution locations |
|
|
173
|
+
| `supercheck doctor` | Validate local CLI dependencies and config |
|
|
145
174
|
| `supercheck upgrade` | Upgrade the CLI to the latest release |
|
|
146
175
|
|
|
147
176
|
## Configuration
|
package/dist/bin/supercheck.js
CHANGED
|
@@ -216,7 +216,7 @@ function requireTriggerKey() {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
// src/version.ts
|
|
219
|
-
var CLI_VERSION = true ? "0.1.1-beta.
|
|
219
|
+
var CLI_VERSION = true ? "0.1.1-beta.2" : "0.0.0-dev";
|
|
220
220
|
|
|
221
221
|
// src/utils/proxy.ts
|
|
222
222
|
import { ProxyAgent } from "undici";
|
|
@@ -312,40 +312,6 @@ var ApiClient = class {
|
|
|
312
312
|
}
|
|
313
313
|
return url.toString();
|
|
314
314
|
}
|
|
315
|
-
getProxyEnv(url) {
|
|
316
|
-
if (this.proxy) return this.proxy;
|
|
317
|
-
const noProxyRaw = process.env.NO_PROXY ?? process.env.no_proxy;
|
|
318
|
-
if (noProxyRaw && this.isNoProxyMatch(url, noProxyRaw)) {
|
|
319
|
-
return null;
|
|
320
|
-
}
|
|
321
|
-
if (url.protocol === "https:") {
|
|
322
|
-
return process.env.HTTPS_PROXY ?? process.env.https_proxy ?? process.env.HTTP_PROXY ?? process.env.http_proxy ?? null;
|
|
323
|
-
}
|
|
324
|
-
if (url.protocol === "http:") {
|
|
325
|
-
return process.env.HTTP_PROXY ?? process.env.http_proxy ?? null;
|
|
326
|
-
}
|
|
327
|
-
return null;
|
|
328
|
-
}
|
|
329
|
-
isNoProxyMatch(url, noProxyRaw) {
|
|
330
|
-
const hostname = url.hostname;
|
|
331
|
-
const port = url.port || (url.protocol === "https:" ? "443" : "80");
|
|
332
|
-
const entries = noProxyRaw.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
333
|
-
if (entries.includes("*")) return true;
|
|
334
|
-
for (const entry of entries) {
|
|
335
|
-
const [hostPart, portPart] = entry.split(":");
|
|
336
|
-
const host = hostPart.trim();
|
|
337
|
-
const entryPort = portPart?.trim();
|
|
338
|
-
if (!host) continue;
|
|
339
|
-
if (entryPort && entryPort !== port) continue;
|
|
340
|
-
if (host.startsWith(".")) {
|
|
341
|
-
if (hostname.endsWith(host)) return true;
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
if (hostname === host) return true;
|
|
345
|
-
if (hostname.endsWith(`.${host}`)) return true;
|
|
346
|
-
}
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
315
|
/**
|
|
350
316
|
* Execute an HTTP request with retries, timeout, and rate limit handling.
|
|
351
317
|
*/
|
|
@@ -360,7 +326,7 @@ var ApiClient = class {
|
|
|
360
326
|
try {
|
|
361
327
|
const controller = new AbortController();
|
|
362
328
|
timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
363
|
-
const proxy = this.getProxyEnv(parsedUrl);
|
|
329
|
+
const proxy = this.proxy || getProxyEnv(parsedUrl);
|
|
364
330
|
const fetchOptions = {
|
|
365
331
|
method,
|
|
366
332
|
headers,
|
|
@@ -1690,6 +1656,11 @@ function isNodeInstalled() {
|
|
|
1690
1656
|
}
|
|
1691
1657
|
async function installPlaywrightBrowsers(cwd, browser = "chromium") {
|
|
1692
1658
|
try {
|
|
1659
|
+
const allowedBrowsers = ["chromium", "firefox", "webkit", "chrome", "msedge"];
|
|
1660
|
+
if (!allowedBrowsers.includes(browser)) {
|
|
1661
|
+
logger.error(`Invalid browser: ${browser}. Allowed: ${allowedBrowsers.join(", ")}`);
|
|
1662
|
+
return false;
|
|
1663
|
+
}
|
|
1693
1664
|
logger.info(`Installing Playwright ${browser} browser...`);
|
|
1694
1665
|
execSync(`npx playwright install ${browser}`, {
|
|
1695
1666
|
cwd,
|
|
@@ -2128,9 +2099,11 @@ async function validateScripts(client, inputs) {
|
|
|
2128
2099
|
import { spawn } from "child_process";
|
|
2129
2100
|
function runCommand(command, args, cwd) {
|
|
2130
2101
|
return new Promise((resolve10, reject) => {
|
|
2131
|
-
const
|
|
2102
|
+
const executable = process.platform === "win32" && command === "npx" ? "npx.cmd" : command;
|
|
2103
|
+
const child = spawn(executable, args, {
|
|
2132
2104
|
stdio: "inherit",
|
|
2133
|
-
shell:
|
|
2105
|
+
shell: false,
|
|
2106
|
+
// ✓ SECURE: Prevents command injection
|
|
2134
2107
|
cwd
|
|
2135
2108
|
});
|
|
2136
2109
|
child.on("error", (err) => reject(err));
|
|
@@ -2435,7 +2408,7 @@ jobCommand.command("run").description("Run a job immediately").requiredOption("-
|
|
|
2435
2408
|
"Running job",
|
|
2436
2409
|
() => client.post(
|
|
2437
2410
|
"/api/jobs/run",
|
|
2438
|
-
{ jobId: options.id, tests: payloadTests, trigger: "
|
|
2411
|
+
{ jobId: options.id, tests: payloadTests, trigger: "remote" }
|
|
2439
2412
|
)
|
|
2440
2413
|
);
|
|
2441
2414
|
logger.success(`Job started. Run ID: ${data.runId}`);
|
|
@@ -2870,24 +2843,15 @@ testCommand.command("delete <id>").description("Delete a test").option("--force"
|
|
|
2870
2843
|
);
|
|
2871
2844
|
logger.success(`Test ${id} deleted`);
|
|
2872
2845
|
});
|
|
2873
|
-
testCommand.command("run").description("Run tests locally
|
|
2846
|
+
testCommand.command("run").description("Run tests locally").option("--local", "Run locally").option("--cloud", "DEPRECATED: Cloud test execution is no longer supported from CLI").option("--file <path>", "Local test file path").option("--all", "Run all local tests").option("--type <type>", "Local test type filter (browser, performance, api, database, custom)").option("--id <id>", "DEPRECATED: Test ID (cloud execution removed)").option("--location <location>", "Execution location (k6 cloud only)").action(async (options) => {
|
|
2874
2847
|
if (options.local && options.cloud) {
|
|
2875
2848
|
throw new CLIError("--local and --cloud are mutually exclusive.", 3 /* ConfigError */);
|
|
2876
2849
|
}
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
}
|
|
2882
|
-
const client2 = createAuthenticatedClient();
|
|
2883
|
-
const body = {};
|
|
2884
|
-
if (options.location) body.location = options.location;
|
|
2885
|
-
const { data } = await withSpinner(
|
|
2886
|
-
"Executing test",
|
|
2887
|
-
() => client2.post(`/api/tests/${options.id}/execute`, body)
|
|
2850
|
+
if (options.cloud || options.id || options.location) {
|
|
2851
|
+
throw new CLIError(
|
|
2852
|
+
"Cloud execution for single tests has been removed from CLI because results are not persisted as job runs. Use `supercheck test run --local ...` for local validation or create/trigger a job (`supercheck job run` / `supercheck job trigger`) for remote executions with run history.",
|
|
2853
|
+
3 /* ConfigError */
|
|
2888
2854
|
);
|
|
2889
|
-
outputDetail(data);
|
|
2890
|
-
return;
|
|
2891
2855
|
}
|
|
2892
2856
|
if (!options.file && !options.all) {
|
|
2893
2857
|
throw new CLIError("Local runs require --file <path> or --all.", 3 /* ConfigError */);
|
|
@@ -2935,15 +2899,11 @@ testCommand.command("run").description("Run tests locally or in the cloud").opti
|
|
|
2935
2899
|
await runK6Tests(k6Tests, cwd);
|
|
2936
2900
|
}
|
|
2937
2901
|
});
|
|
2938
|
-
testCommand.command("execute <id>").description("
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
const { data } = await withSpinner(
|
|
2943
|
-
"Executing test",
|
|
2944
|
-
() => client.post(`/api/tests/${id}/execute`, body)
|
|
2902
|
+
testCommand.command("execute <id>").description("DEPRECATED: test execute has been removed").action(async () => {
|
|
2903
|
+
throw new CLIError(
|
|
2904
|
+
"The `test execute` command has been removed. Use `supercheck test run --local ...` for local validation or create/trigger a job (`supercheck job run` / `supercheck job trigger`) for remote executions with run history.",
|
|
2905
|
+
3 /* ConfigError */
|
|
2945
2906
|
);
|
|
2946
|
-
outputDetail(data);
|
|
2947
2907
|
});
|
|
2948
2908
|
testCommand.command("tags <id>").description("Get test tags").action(async (id) => {
|
|
2949
2909
|
const client = createAuthenticatedClient();
|
|
@@ -3539,7 +3499,8 @@ async function applyChange(client, change, opts) {
|
|
|
3539
3499
|
const endpoint = getApiEndpoint(change.type);
|
|
3540
3500
|
switch (change.action) {
|
|
3541
3501
|
case "create": {
|
|
3542
|
-
const
|
|
3502
|
+
const rawBody = { ...change.local.definition };
|
|
3503
|
+
delete rawBody.id;
|
|
3543
3504
|
const body = prepareBodyForApi(change.type, rawBody);
|
|
3544
3505
|
const response = await client.post(endpoint, body);
|
|
3545
3506
|
if (change.type === "test") {
|
|
@@ -3562,7 +3523,8 @@ async function applyChange(client, change, opts) {
|
|
|
3562
3523
|
}
|
|
3563
3524
|
case "update": {
|
|
3564
3525
|
const id = change.id ?? change.remote.id;
|
|
3565
|
-
const
|
|
3526
|
+
const rawBody = { ...change.local.definition };
|
|
3527
|
+
delete rawBody.id;
|
|
3566
3528
|
const body = prepareBodyForApi(change.type, rawBody);
|
|
3567
3529
|
await client.put(`${endpoint}/${id}`, body);
|
|
3568
3530
|
return { success: true };
|
|
@@ -3601,6 +3563,15 @@ var deployCommand = new Command12("deploy").description("Push local config resou
|
|
|
3601
3563
|
changes = changes.filter((c) => c.action !== "delete");
|
|
3602
3564
|
}
|
|
3603
3565
|
const actionable = changes.filter((c) => c.action !== "no-change");
|
|
3566
|
+
const unsupportedStatusPageMutations = actionable.filter(
|
|
3567
|
+
(c) => c.type === "statusPage" && (c.action === "create" || c.action === "update")
|
|
3568
|
+
);
|
|
3569
|
+
if (unsupportedStatusPageMutations.length > 0) {
|
|
3570
|
+
throw new CLIError(
|
|
3571
|
+
"Status page create/update is not supported by the current API. Remove statusPages create/update changes from config (or apply them in the dashboard) and run deploy again.",
|
|
3572
|
+
3 /* ConfigError */
|
|
3573
|
+
);
|
|
3574
|
+
}
|
|
3604
3575
|
if (actionable.length === 0) {
|
|
3605
3576
|
logger.success("No changes to deploy. Everything is in sync.");
|
|
3606
3577
|
return;
|
|
@@ -3885,7 +3856,11 @@ function decodeScript(script) {
|
|
|
3885
3856
|
if (reEncoded !== trimmed) {
|
|
3886
3857
|
return script;
|
|
3887
3858
|
}
|
|
3888
|
-
|
|
3859
|
+
const isTextLike = decoded.length > 0 && Array.from(decoded).every((char) => {
|
|
3860
|
+
const code = char.codePointAt(0) ?? 0;
|
|
3861
|
+
return code === 9 || code === 10 || code === 13 || code >= 32;
|
|
3862
|
+
});
|
|
3863
|
+
if (isTextLike) {
|
|
3889
3864
|
return decoded;
|
|
3890
3865
|
}
|
|
3891
3866
|
} catch {
|
|
@@ -4228,7 +4203,7 @@ function generateConfigContent(opts) {
|
|
|
4228
4203
|
parts.push(" *");
|
|
4229
4204
|
parts.push(" * supercheck test list List all tests");
|
|
4230
4205
|
parts.push(" * supercheck test validate Validate a local test script");
|
|
4231
|
-
parts.push(" * supercheck test
|
|
4206
|
+
parts.push(" * supercheck test run --local Run local test scripts");
|
|
4232
4207
|
parts.push(" *");
|
|
4233
4208
|
parts.push(" * supercheck monitor list List all monitors");
|
|
4234
4209
|
parts.push(" * supercheck job list List all jobs");
|