@xcelera/cli 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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';
@@ -36573,13 +36575,18 @@ async function inferBuildContext() {
36573
36575
  };
36574
36576
  }
36575
36577
 
36576
- async function runAuditCommand(url, token) {
36578
+ async function runAuditCommand(url, token, authOptions) {
36577
36579
  const output = [];
36578
36580
  const errors = [];
36579
36581
  try {
36580
36582
  const buildContext = await inferBuildContext();
36581
36583
  output.push(...formatBuildContext(buildContext));
36582
- const response = await requestAudit(url, token, buildContext);
36584
+ const auth = parseAuthCredentials(authOptions);
36585
+ if (auth) {
36586
+ output.push('🔐 Authentication credentials detected');
36587
+ output.push('');
36588
+ }
36589
+ const response = await requestAudit(url, token, buildContext, auth);
36583
36590
  if (!response.success) {
36584
36591
  const { message, details } = response.error;
36585
36592
  errors.push('❌ Unable to schedule audit :(');
@@ -36671,13 +36678,67 @@ function formatGitHubIntegrationStatus(context) {
36671
36678
  }
36672
36679
  return { output, errors };
36673
36680
  }
36681
+ function parseAuthCredentials(options) {
36682
+ const envAuth = process.env.XCELERA_AUTH;
36683
+ if (envAuth) {
36684
+ try {
36685
+ return JSON.parse(envAuth);
36686
+ }
36687
+ catch {
36688
+ throw new Error('XCELERA_AUTH environment variable contains invalid JSON');
36689
+ }
36690
+ }
36691
+ // Check for --auth JSON option
36692
+ if (options?.authJson) {
36693
+ try {
36694
+ return JSON.parse(options.authJson);
36695
+ }
36696
+ catch {
36697
+ throw new Error('--auth option contains invalid JSON');
36698
+ }
36699
+ }
36700
+ // Build auth from --cookie and --header options
36701
+ const hasCookies = options?.cookies && options.cookies.length > 0;
36702
+ const hasHeaders = options?.headers && options.headers.length > 0;
36703
+ if (!hasCookies && !hasHeaders) {
36704
+ return undefined;
36705
+ }
36706
+ const auth = {};
36707
+ if (hasCookies && options.cookies) {
36708
+ auth.cookies = options.cookies.map(parseCookie);
36709
+ }
36710
+ if (hasHeaders && options.headers) {
36711
+ auth.headers = {};
36712
+ for (const header of options.headers) {
36713
+ const colonIndex = header.indexOf(':');
36714
+ if (colonIndex === -1) {
36715
+ throw new Error(`Invalid header format: "${header}". Expected "Name: Value"`);
36716
+ }
36717
+ const name = header.slice(0, colonIndex).trim();
36718
+ const value = header.slice(colonIndex + 1).trim();
36719
+ auth.headers[name] = value;
36720
+ }
36721
+ }
36722
+ return auth;
36723
+ }
36724
+ function parseCookie(cookie) {
36725
+ const equalsIndex = cookie.indexOf('=');
36726
+ if (equalsIndex === -1) {
36727
+ throw new Error(`Invalid cookie format: "${cookie}". Expected "name=value"`);
36728
+ }
36729
+ return {
36730
+ name: cookie.slice(0, equalsIndex),
36731
+ value: cookie.slice(equalsIndex + 1)
36732
+ };
36733
+ }
36674
36734
 
36675
36735
  /* istanbul ignore file */
36676
36736
  run();
36677
36737
  async function run() {
36678
36738
  const url = coreExports.getInput('url', { required: true });
36679
36739
  const token = coreExports.getInput('token', { required: true });
36680
- const result = await runAuditCommand(url, token);
36740
+ const authOptions = parseAuthInputs();
36741
+ const result = await runAuditCommand(url, token, authOptions);
36681
36742
  result.output.forEach((line) => coreExports.info(line));
36682
36743
  result.errors.forEach((line) => coreExports.error(line));
36683
36744
  if (result.exitCode !== 0) {
@@ -36688,4 +36749,17 @@ async function run() {
36688
36749
  coreExports.setOutput('status', 'success');
36689
36750
  }
36690
36751
  }
36752
+ function parseAuthInputs() {
36753
+ const auth = coreExports.getInput('auth');
36754
+ const cookie = coreExports.getInput('cookie');
36755
+ const header = coreExports.getInput('header');
36756
+ if (!auth && !cookie && !header) {
36757
+ return undefined;
36758
+ }
36759
+ return {
36760
+ authJson: auth || undefined,
36761
+ cookies: cookie ? [cookie] : undefined,
36762
+ headers: header ? [header] : undefined
36763
+ };
36764
+ }
36691
36765
  //# sourceMappingURL=action.js.map