@xcelera/cli 2.2.2 → 2.3.1

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 CHANGED
@@ -4,6 +4,38 @@ A CLI for running Lighthouse performance audits using xcelera.dev
4
4
 
5
5
  ## Usage
6
6
 
7
+ ### CLI Usage
8
+
9
+ ```bash
10
+ # Basic audit
11
+ xcelera audit --url https://example.com --token your-api-token
12
+ ```
13
+
14
+ ### Authenticated Pages
15
+
16
+ For pages behind login, you can pass authentication credentials:
17
+
18
+ ```bash
19
+ # With session cookie
20
+ xcelera audit --url https://myapp.com/dashboard --cookie "session=abc123"
21
+
22
+ # With bearer token header
23
+ xcelera audit --url https://api.myapp.com/admin \
24
+ --header "Authorization: Bearer eyJhbG..."
25
+
26
+ # Multiple cookies
27
+ xcelera audit --url https://myapp.com/dashboard \
28
+ --cookie "session=abc123" --cookie "csrf=xyz"
29
+
30
+ # Full auth JSON (multiple cookies and custom headers)
31
+ xcelera audit --url https://myapp.com/dashboard \
32
+ --auth '{"cookies":[{"name":"session","value":"abc123"}],"headers":{"X-Custom":"value"}}'
33
+
34
+ # Using environment variable
35
+ export XCELERA_AUTH='{"cookies":[{"name":"session","value":"abc123"}]}'
36
+ xcelera audit --url https://myapp.com/dashboard
37
+ ```
38
+
7
39
  ### GitHub Action Usage
8
40
 
9
41
  ```yaml
@@ -14,6 +46,34 @@ A CLI for running Lighthouse performance audits using xcelera.dev
14
46
  token: ${{ secrets.XCELERA_TOKEN }}
15
47
  ```
16
48
 
49
+ For authenticated pages in CI:
50
+
51
+ ```yaml
52
+ # With session cookie
53
+ - name: Lighthouse Audit (Cookie Auth)
54
+ uses: xcelera/cli@v1
55
+ with:
56
+ url: https://example.com/dashboard
57
+ token: ${{ secrets.XCELERA_TOKEN }}
58
+ cookie: "session=value"
59
+
60
+ # With bearer token header
61
+ - name: Lighthouse Audit (Bearer Auth)
62
+ uses: xcelera/cli@v1
63
+ with:
64
+ url: https://example.com/admin
65
+ token: ${{ secrets.XCELERA_TOKEN }}
66
+ header: "Authorization: Bearer eybDfd..."
67
+
68
+ # With full auth JSON (multiple cookies/headers)
69
+ - name: Lighthouse Audit (Full Auth)
70
+ uses: xcelera/cli@v1
71
+ with:
72
+ url: https://example.com/dashboard
73
+ token: ${{ secrets.XCELERA_TOKEN }}
74
+ auth: '{"cookies":[{"name":"session","value":"session_value"},{"name":"csrf","value":"csrf_value"}]}'
75
+ ```
76
+
17
77
  ## Setup
18
78
 
19
79
  ### 1. Get Your API Token
package/dist/action.js CHANGED
@@ -27303,7 +27303,7 @@ function isNetworkError(error) {
27303
27303
  return errorMessages.has(message);
27304
27304
  }
27305
27305
 
27306
- async function requestAudit(url, token, context) {
27306
+ async function requestAudit(url, token, context, auth) {
27307
27307
  const apiUrl = `${getApiBaseUrl()}/api/v1/audit`;
27308
27308
  try {
27309
27309
  const response = await fetch(apiUrl, {
@@ -27314,7 +27314,8 @@ async function requestAudit(url, token, context) {
27314
27314
  },
27315
27315
  body: JSON.stringify({
27316
27316
  url,
27317
- context
27317
+ context,
27318
+ ...(auth && { auth })
27318
27319
  })
27319
27320
  });
27320
27321
  if (!response.ok) {
@@ -27346,6 +27347,7 @@ async function requestAudit(url, token, context) {
27346
27347
  throw error;
27347
27348
  }
27348
27349
  }
27350
+ /* istanbul ignore next */
27349
27351
  function getApiBaseUrl() {
27350
27352
  if (process.env.NODE_ENV === 'development') {
27351
27353
  return 'http://localhost:3000';
@@ -36509,7 +36511,7 @@ var simpleGit = gitInstanceFactory;
36509
36511
 
36510
36512
  async function inferGitContext() {
36511
36513
  if (!(await isGitRepository())) {
36512
- throw new Error('No git repository detected.');
36514
+ return undefined;
36513
36515
  }
36514
36516
  const remoteUrl = await getRemoteUrl();
36515
36517
  const parsed = parseGithubUrl(remoteUrl);
@@ -36559,27 +36561,30 @@ async function getCommit(hash = 'HEAD') {
36559
36561
 
36560
36562
  async function inferBuildContext() {
36561
36563
  const ciEnv = envCi();
36562
- const gitContext = {
36563
- ...(await inferGitContext()),
36564
- branch: ('prBranch' in ciEnv && ciEnv.prBranch ? ciEnv.prBranch : ciEnv.branch) ??
36565
- undefined
36566
- };
36564
+ const gitContext = await inferGitContext();
36565
+ const branch = ('prBranch' in ciEnv && ciEnv.prBranch ? ciEnv.prBranch : ciEnv.branch) ??
36566
+ undefined;
36567
36567
  return {
36568
36568
  service: ciEnv.isCi ? ciEnv.service : 'unknown',
36569
36569
  prNumber: 'pr' in ciEnv ? ciEnv.pr : undefined,
36570
36570
  buildNumber: 'build' in ciEnv ? ciEnv.build : undefined,
36571
36571
  buildUrl: 'buildUrl' in ciEnv ? ciEnv.buildUrl : undefined,
36572
- git: gitContext
36572
+ git: gitContext ? { ...gitContext, branch } : undefined
36573
36573
  };
36574
36574
  }
36575
36575
 
36576
- async function runAuditCommand(url, token) {
36576
+ async function runAuditCommand(url, token, authOptions) {
36577
36577
  const output = [];
36578
36578
  const errors = [];
36579
36579
  try {
36580
36580
  const buildContext = await inferBuildContext();
36581
36581
  output.push(...formatBuildContext(buildContext));
36582
- const response = await requestAudit(url, token, buildContext);
36582
+ const auth = parseAuthCredentials(authOptions);
36583
+ if (auth) {
36584
+ output.push('🔐 Authentication credentials detected');
36585
+ output.push('');
36586
+ }
36587
+ const response = await requestAudit(url, token, buildContext, auth);
36583
36588
  if (!response.success) {
36584
36589
  const { message, details } = response.error;
36585
36590
  errors.push('❌ Unable to schedule audit :(');
@@ -36671,13 +36676,67 @@ function formatGitHubIntegrationStatus(context) {
36671
36676
  }
36672
36677
  return { output, errors };
36673
36678
  }
36679
+ function parseAuthCredentials(options) {
36680
+ const envAuth = process.env.XCELERA_AUTH;
36681
+ if (envAuth) {
36682
+ try {
36683
+ return JSON.parse(envAuth);
36684
+ }
36685
+ catch {
36686
+ throw new Error('XCELERA_AUTH environment variable contains invalid JSON');
36687
+ }
36688
+ }
36689
+ // Check for --auth JSON option
36690
+ if (options?.authJson) {
36691
+ try {
36692
+ return JSON.parse(options.authJson);
36693
+ }
36694
+ catch {
36695
+ throw new Error('--auth option contains invalid JSON');
36696
+ }
36697
+ }
36698
+ // Build auth from --cookie and --header options
36699
+ const hasCookies = options?.cookies && options.cookies.length > 0;
36700
+ const hasHeaders = options?.headers && options.headers.length > 0;
36701
+ if (!hasCookies && !hasHeaders) {
36702
+ return undefined;
36703
+ }
36704
+ const auth = {};
36705
+ if (hasCookies && options.cookies) {
36706
+ auth.cookies = options.cookies.map(parseCookie);
36707
+ }
36708
+ if (hasHeaders && options.headers) {
36709
+ auth.headers = {};
36710
+ for (const header of options.headers) {
36711
+ const colonIndex = header.indexOf(':');
36712
+ if (colonIndex === -1) {
36713
+ throw new Error(`Invalid header format: "${header}". Expected "Name: Value"`);
36714
+ }
36715
+ const name = header.slice(0, colonIndex).trim();
36716
+ const value = header.slice(colonIndex + 1).trim();
36717
+ auth.headers[name] = value;
36718
+ }
36719
+ }
36720
+ return auth;
36721
+ }
36722
+ function parseCookie(cookie) {
36723
+ const equalsIndex = cookie.indexOf('=');
36724
+ if (equalsIndex === -1) {
36725
+ throw new Error(`Invalid cookie format: "${cookie}". Expected "name=value"`);
36726
+ }
36727
+ return {
36728
+ name: cookie.slice(0, equalsIndex),
36729
+ value: cookie.slice(equalsIndex + 1)
36730
+ };
36731
+ }
36674
36732
 
36675
36733
  /* istanbul ignore file */
36676
36734
  run();
36677
36735
  async function run() {
36678
36736
  const url = coreExports.getInput('url', { required: true });
36679
36737
  const token = coreExports.getInput('token', { required: true });
36680
- const result = await runAuditCommand(url, token);
36738
+ const authOptions = parseAuthInputs();
36739
+ const result = await runAuditCommand(url, token, authOptions);
36681
36740
  result.output.forEach((line) => coreExports.info(line));
36682
36741
  result.errors.forEach((line) => coreExports.error(line));
36683
36742
  if (result.exitCode !== 0) {
@@ -36688,4 +36747,17 @@ async function run() {
36688
36747
  coreExports.setOutput('status', 'success');
36689
36748
  }
36690
36749
  }
36750
+ function parseAuthInputs() {
36751
+ const auth = coreExports.getInput('auth');
36752
+ const cookie = coreExports.getInput('cookie');
36753
+ const header = coreExports.getInput('header');
36754
+ if (!auth && !cookie && !header) {
36755
+ return undefined;
36756
+ }
36757
+ return {
36758
+ authJson: auth || undefined,
36759
+ cookies: cookie ? [cookie] : undefined,
36760
+ headers: header ? [header] : undefined
36761
+ };
36762
+ }
36691
36763
  //# sourceMappingURL=action.js.map