@docupace/pipeline 1.0.66 → 1.0.68

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.
@@ -1,3 +1,4 @@
1
+ # bitbucket-pipelines.yml
1
2
  clone:
2
3
  depth: 2
3
4
 
@@ -6,23 +7,54 @@ pipelines:
6
7
  '**':
7
8
  - step:
8
9
  runs-on:
10
+ - self.hosted
9
11
  - linux.shell
10
- - onprem
11
12
  name: On Pull Request
12
13
  script:
14
+ - npm install -g pnpm
13
15
  - pnpm config set //registry.npmjs.org/:_authToken $DOCUPACE_NPM_TOKEN
14
16
  - pnpm install --frozen-lockfile
15
- - >
16
- npx eslint . --rule "no-unused-vars: warn" --rule "no-useless-escape: warn" --color
17
+ - 'npx eslint . --rule "no-unused-vars: warn" --rule "no-useless-escape: warn" --color'
18
+ - pnpm test
19
+ artifacts:
20
+ - coverage/**
21
+ after-script:
22
+ - echo "Pipeline completed with status $BITBUCKET_EXIT_CODE"
23
+
17
24
  custom:
18
25
  scheduled-tests:
19
26
  - step:
20
27
  runs-on:
28
+ - self.hosted
21
29
  - linux.shell
22
- - onprem
23
- name: Manual
30
+ name: Scheduled Tests
24
31
  script:
32
+ - npm install -g pnpm
25
33
  - pnpm config set //registry.npmjs.org/:_authToken $DOCUPACE_NPM_TOKEN
26
34
  - pnpm install --frozen-lockfile
27
- - >
28
- npx eslint . --rule "no-unused-vars: warn" --rule "no-useless-escape: warn" --color
35
+ - 'npx eslint . --rule "no-unused-vars: warn" --rule "no-useless-escape: warn" --color'
36
+ - pnpm test
37
+ artifacts:
38
+ - coverage/**
39
+ after-script:
40
+ - echo "Pipeline completed with status $BITBUCKET_EXIT_CODE"
41
+
42
+ branches:
43
+ main:
44
+ - step:
45
+ runs-on:
46
+ - self.hosted
47
+ - linux.shell
48
+ name: Main Branch Build
49
+ script:
50
+ - npm install -g pnpm
51
+ - pnpm config set //registry.npmjs.org/:_authToken $DOCUPACE_NPM_TOKEN
52
+ - pnpm install --frozen-lockfile
53
+ - 'npx eslint . --rule "no-unused-vars: warn" --rule "no-useless-escape: warn" --color'
54
+ - pnpm test
55
+ artifacts:
56
+ - coverage/**
57
+
58
+ definitions:
59
+ caches:
60
+ pnpm: ~/.pnpm-store
package/eslint.config.js CHANGED
@@ -4,17 +4,29 @@ import prettierConfig from 'eslint-config-prettier';
4
4
  import prettierPlugin from 'eslint-plugin-prettier';
5
5
  import importPlugin from 'eslint-plugin-import';
6
6
 
7
- /** @type {import('eslint').Linter.Config[]} */
8
7
  export default [
9
8
  {
10
9
  languageOptions: {
11
10
  globals: {
12
11
  ...globals.browser,
13
- ...globals.node, // Add Node.js globals
12
+ ...globals.node,
14
13
  },
15
14
  },
16
15
  },
16
+
17
+ // Core JS rules
17
18
  pluginJs.configs.recommended,
19
+
20
+ // Jest globals for test files only
21
+ {
22
+ files: ['**/*.test.js', '**/__tests__/**/*.js'],
23
+ languageOptions: {
24
+ globals: {
25
+ ...globals.jest,
26
+ },
27
+ },
28
+ },
29
+
18
30
  {
19
31
  plugins: {
20
32
  prettier: prettierPlugin,
@@ -29,7 +41,6 @@ export default [
29
41
  rules: {
30
42
  ...prettierConfig.rules,
31
43
  'prettier/prettier': 'error',
32
- // Import-related rules
33
44
  'import/no-unresolved': 'error',
34
45
  'import/named': 'error',
35
46
  'import/no-extraneous-dependencies': 'error',
package/jest.config.js ADDED
@@ -0,0 +1,15 @@
1
+ // jest.config.js
2
+ export default {
3
+ testEnvironment: 'node',
4
+ transform: {},
5
+ verbose: true,
6
+ collectCoverage: true,
7
+ coverageDirectory: 'coverage',
8
+ coverageReporters: ['text', 'lcov', 'json', 'html'],
9
+ collectCoverageFrom: [
10
+ 'src/**/*.{js,ts}',
11
+ '!src/**/cli.js',
12
+ '!src/**/*.test.{js,ts}',
13
+ '!**/node_modules/**',
14
+ ],
15
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docupace/pipeline",
3
- "version": "1.0.66",
3
+ "version": "1.0.68",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,7 @@
18
18
  "@changesets/cli": "^2.27.10",
19
19
  "@docupace/core-client": "^0.1.94",
20
20
  "@docupace/pipeline": "^1.0.33-alpha-2",
21
+ "@jest/globals": "^30.1.2",
21
22
  "auth0-deploy-cli": "^8.8.0",
22
23
  "axios": "^1.7.9",
23
24
  "commander": "^12.1.0",
@@ -41,9 +42,11 @@
41
42
  "eslint-import-resolver-typescript": "^4.4.4",
42
43
  "eslint-plugin-prettier": "^5.2.1",
43
44
  "globals": "^15.14.0",
45
+ "jest": "^30.1.3",
44
46
  "prettier": "^3.4.2"
45
47
  },
46
48
  "scripts": {
49
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --testPathIgnorePatterns='src/next/test\\.js'",
47
50
  "test-deploy-core": "dp-next-cli deploy-core-pipeline dev template",
48
51
  "test-deploy-from-site": "dp-next-cli deploy-from-site --from-env dev --to-env dev --from-site financialdev --to-site template --deploy-core true",
49
52
  "test-run-pipline": "dp-next-cli run-pipeline -r docupace-next-e2e -b master -p run-tests-qa",
@@ -1,13 +1,8 @@
1
1
  import axios from 'axios';
2
-
3
2
  import { createAlias } from '../next/alias.js';
4
-
5
3
  import { getAuth0AuthToken } from './configure.js';
6
-
7
4
  import { getVaultSecrets } from './vault.js';
8
-
9
5
  import { getVaultSecretsConfigs } from '../next/config.js';
10
-
11
6
  import { cloneEnvRepository, readDeployConfig } from '../next/deploy.js';
12
7
 
13
8
  export async function getCCAlias({ application, auth0Domain, auth0AuthToken }) {
@@ -35,7 +30,14 @@ export async function getCCAlias({ application, auth0Domain, auth0AuthToken }) {
35
30
  }
36
31
  }
37
32
 
38
- export async function configureAlias(site, env, username, password, realm) {
33
+ export async function configureAlias(
34
+ site,
35
+ env,
36
+ username,
37
+ password,
38
+ realm,
39
+ auth0Tenant,
40
+ ) {
39
41
  console.log(`Creating alias for site: ${site} in env: ${env}`);
40
42
  // Site Common Secrets
41
43
  const siteCommonSecretsPath =
@@ -43,7 +45,12 @@ export async function configureAlias(site, env, username, password, realm) {
43
45
  console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
44
46
  const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
45
47
 
46
- const auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
48
+ let auth0Domain;
49
+ if (auth0Tenant === '') {
50
+ auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
51
+ } else {
52
+ auth0Domain = `${auth0Tenant}.us.auth0.com`;
53
+ }
47
54
  const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
48
55
  const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
49
56
  const auth0Token = await getAuth0AuthToken(
@@ -0,0 +1,172 @@
1
+ // alias.test.js
2
+ import { jest } from '@jest/globals';
3
+
4
+ // --------- ESM-Compatible Mocks ---------
5
+ jest.unstable_mockModule('axios', () => ({
6
+ default: {
7
+ get: jest.fn(),
8
+ },
9
+ }));
10
+
11
+ jest.unstable_mockModule('../next/alias.js', () => ({
12
+ createAlias: jest.fn(),
13
+ }));
14
+
15
+ jest.unstable_mockModule('./configure.js', () => ({
16
+ getAuth0AuthToken: jest.fn(),
17
+ }));
18
+
19
+ jest.unstable_mockModule('./vault.js', () => ({
20
+ getVaultSecrets: jest.fn(),
21
+ }));
22
+
23
+ jest.unstable_mockModule('../next/config.js', () => ({
24
+ getVaultSecretsConfigs: jest.fn(),
25
+ }));
26
+
27
+ jest.unstable_mockModule('../next/deploy.js', () => ({
28
+ cloneEnvRepository: jest.fn(),
29
+ readDeployConfig: jest.fn(),
30
+ }));
31
+
32
+ // --------- Import AFTER mocks ---------
33
+ const { configureAlias, getCCAlias } = await import('./alias.js');
34
+ const axios = (await import('axios')).default;
35
+ const { createAlias } = await import('../next/alias.js');
36
+ const { getAuth0AuthToken } = await import('./configure.js');
37
+ const { getVaultSecrets } = await import('./vault.js');
38
+ const { getVaultSecretsConfigs } = await import('../next/config.js');
39
+ const { cloneEnvRepository, readDeployConfig } = await import(
40
+ '../next/deploy.js'
41
+ );
42
+
43
+ // --------- Shared Test Setup ---------
44
+ beforeAll(() => {
45
+ jest.spyOn(console, 'log').mockImplementation(() => {}); // silence logs
46
+ });
47
+
48
+ afterAll(() => {
49
+ console.log.mockRestore();
50
+ });
51
+
52
+ describe('configureAlias', () => {
53
+ const site = 'example';
54
+ const env = 'dev';
55
+ const username = 'admin';
56
+ const password = 'pass';
57
+ const realm = 'Users';
58
+ const auth0Tenant = '';
59
+
60
+ const mockSecrets = {
61
+ AUTH0_CLIENT_ID: 'client-id',
62
+ AUTH0_CLIENT_SECRET: 'client-secret',
63
+ };
64
+
65
+ const mockToken = 'mocked-auth0-token';
66
+
67
+ const mockClients = [
68
+ { name: 'docupace-graphql-client-credentials', client_id: 'client-123' },
69
+ ];
70
+
71
+ const mockConfig = {
72
+ deployConfig: {
73
+ graphqlServer: {
74
+ coreUrl: 'https://core.example.com',
75
+ },
76
+ },
77
+ };
78
+
79
+ beforeEach(() => {
80
+ jest.clearAllMocks();
81
+
82
+ getVaultSecretsConfigs.mockReturnValue({
83
+ siteCommonSecretsPath: 'vault/path/to/secrets',
84
+ });
85
+
86
+ getVaultSecrets.mockResolvedValue(mockSecrets);
87
+ getAuth0AuthToken.mockResolvedValue(mockToken);
88
+ axios.get.mockResolvedValue({ data: mockClients });
89
+ cloneEnvRepository.mockResolvedValue(undefined);
90
+ readDeployConfig.mockResolvedValue(mockConfig);
91
+ createAlias.mockResolvedValue(undefined);
92
+ });
93
+
94
+ it('should configure alias with default tenant and call all required steps', async () => {
95
+ await configureAlias(site, env, username, password, realm, auth0Tenant);
96
+
97
+ expect(getVaultSecretsConfigs).toHaveBeenCalledWith(site);
98
+ expect(getVaultSecrets).toHaveBeenCalledWith('vault/path/to/secrets');
99
+
100
+ expect(getAuth0AuthToken).toHaveBeenCalledWith(
101
+ 'docupace-dev-example.us.auth0.com',
102
+ 'client-id',
103
+ 'client-secret',
104
+ );
105
+
106
+ expect(cloneEnvRepository).toHaveBeenCalledWith(env);
107
+
108
+ expect(readDeployConfig).toHaveBeenCalledWith(
109
+ 'graphql-server',
110
+ env,
111
+ site,
112
+ 'values',
113
+ );
114
+
115
+ expect(axios.get).toHaveBeenCalledWith(
116
+ 'https://docupace-dev-example.us.auth0.com/api/v2/clients',
117
+ { headers: { authorization: `Bearer ${mockToken}` } },
118
+ );
119
+
120
+ expect(createAlias).toHaveBeenCalledWith(
121
+ 'https://core.example.com',
122
+ username,
123
+ password,
124
+ realm,
125
+ 'client-123@clients',
126
+ );
127
+ });
128
+ });
129
+
130
+ describe('getCCAlias', () => {
131
+ const application = 'docupace-graphql-client-credentials';
132
+ const auth0Domain = 'example.auth0.com';
133
+ const auth0AuthToken = 'token';
134
+
135
+ it('should return correct alias string for client', async () => {
136
+ axios.get.mockResolvedValue({
137
+ data: [{ name: application, client_id: 'abc123' }],
138
+ });
139
+
140
+ const alias = await getCCAlias({
141
+ application,
142
+ auth0Domain,
143
+ auth0AuthToken,
144
+ });
145
+ expect(alias).toBe('abc123@clients');
146
+
147
+ expect(axios.get).toHaveBeenCalledWith(
148
+ 'https://example.auth0.com/api/v2/clients',
149
+ { headers: { authorization: 'Bearer token' } },
150
+ );
151
+ });
152
+
153
+ it('should log error and return undefined if axios fails', async () => {
154
+ axios.get.mockRejectedValue(new Error('Network error'));
155
+ const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
156
+
157
+ const result = await getCCAlias({
158
+ application,
159
+ auth0Domain,
160
+ auth0AuthToken,
161
+ });
162
+ expect(result).toBeUndefined();
163
+
164
+ expect(errorSpy).toHaveBeenCalledWith(
165
+ expect.stringContaining(
166
+ 'Failed to form alias name for application: docupace-graphql-client-credentials: Network error',
167
+ ),
168
+ );
169
+
170
+ errorSpy.mockRestore();
171
+ });
172
+ });
package/src/auth0/cli.js CHANGED
@@ -57,24 +57,26 @@ program
57
57
  });
58
58
 
59
59
  program
60
- .command('configureAlias <site> <env> <username> <password> <realm>')
60
+ .command(
61
+ 'configureAlias <site> <env> <username> <password> <realm> [auth0Tenant]',
62
+ )
61
63
  .description('Configure Core Alias for the given site')
62
- .action(async (site, env, username, password, realm) => {
63
- await configureAlias(site, env, username, password, realm);
64
+ .action(async (site, env, username, password, realm, auth0Tenant = '') => {
65
+ await configureAlias(site, env, username, password, realm, auth0Tenant);
64
66
  });
65
67
 
66
68
  program
67
- .command('exportConf <site> <env>')
69
+ .command('exportConf <site> <env> [auth0Tenant]')
68
70
  .description('Export Auth0 configuration for the given site')
69
- .action(async (site, env) => {
70
- await exportConf(site, env);
71
+ .action(async (site, env, auth0Tenant = '') => {
72
+ await exportConf(site, env, auth0Tenant);
71
73
  });
72
74
 
73
75
  program
74
- .command('getAuth0Metadata <site> <env>')
76
+ .command('getAuth0Metadata <site> <env> [auth0Tenant]')
75
77
  .description('Get Auth0 metadata for the given site')
76
- .action(async (site, env) => {
77
- await getAuth0Metadata(site, env);
78
+ .action(async (site, env, auth0Tenant = '') => {
79
+ await getAuth0Metadata(site, env, auth0Tenant);
78
80
  });
79
81
 
80
82
  program.parse(process.argv);
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import axios from 'axios';
4
- import crypto from 'crypto';
4
+ import * as crypto from 'crypto';
5
5
 
6
6
  import {
7
7
  cloneEnvRepository,
@@ -11,6 +11,7 @@ import {
11
11
  } from '../next/deploy.js';
12
12
 
13
13
  import { getVaultSecrets, updateVaultSecrets } from './vault.js';
14
+
14
15
  import {
15
16
  coreSiteEnvMap,
16
17
  environmentConfig,
@@ -0,0 +1,167 @@
1
+ // @jest-environment node
2
+ import { jest } from '@jest/globals';
3
+
4
+ // ─── Mock All Required Modules ───────────────────────────────────────────────
5
+
6
+ jest.unstable_mockModule('fs-extra', () => ({
7
+ default: {
8
+ promises: {
9
+ mkdir: jest.fn(),
10
+ },
11
+ writeFile: jest.fn(),
12
+ ensureDir: jest.fn(),
13
+ },
14
+ writeFile: jest.fn(),
15
+ ensureDir: jest.fn(),
16
+ }));
17
+
18
+ jest.unstable_mockModule('axios', () => ({
19
+ default: {
20
+ post: jest.fn(),
21
+ get: jest.fn(),
22
+ },
23
+ }));
24
+
25
+ jest.unstable_mockModule('crypto', () => ({
26
+ randomBytes: () => ({
27
+ toString: () => 'mockBase64==',
28
+ }),
29
+ }));
30
+
31
+ jest.unstable_mockModule('../next/deploy.js', () => ({
32
+ cloneRepository: jest.fn(),
33
+ cloneEnvRepository: jest.fn(),
34
+ pushDeployConfig: jest.fn(),
35
+ readDeployConfig: jest.fn(),
36
+ }));
37
+
38
+ jest.unstable_mockModule('./vault.js', () => ({
39
+ getVaultSecrets: jest.fn(),
40
+ updateVaultSecrets: jest.fn(),
41
+ }));
42
+
43
+ jest.unstable_mockModule('../next/config.js', () => ({
44
+ coreSiteEnvMap: { dev: 'dev-env' },
45
+ environmentConfig: {
46
+ dev: {
47
+ newUrl: (site) => `dev.${site}.com`,
48
+ oldUrl: (site) => `legacy.${site}.com`,
49
+ ccUrl: (site) => `cc.${site}.com`,
50
+ docupaceHost: () => 'docupace.com',
51
+ },
52
+ },
53
+ getVaultSecretsConfigs: jest.fn(),
54
+ }));
55
+
56
+ // ─── Global References ───────────────────────────────────────────────────────
57
+
58
+ let fs, axios, deploy, vault, config;
59
+ let getAuth0AuthToken, cleanAndWritePropertiesFile, updateCoreSiteConfig;
60
+
61
+ const originalProcessExit = process.exit;
62
+
63
+ beforeAll(async () => {
64
+ // Mock process.exit to prevent killing the test runner
65
+ process.exit = jest.fn();
66
+
67
+ // Suppress noisy error output
68
+ jest.spyOn(console, 'error').mockImplementation(() => {});
69
+ jest.spyOn(console, 'log').mockImplementation(() => {});
70
+
71
+ // Import after mocks
72
+ ({ default: fs } = await import('fs-extra'));
73
+ ({ default: axios } = await import('axios'));
74
+ deploy = await import('../next/deploy.js');
75
+ vault = await import('./vault.js');
76
+ config = await import('../next/config.js');
77
+
78
+ const mod = await import('./configure.js');
79
+ ({ getAuth0AuthToken, cleanAndWritePropertiesFile, updateCoreSiteConfig } =
80
+ mod);
81
+ });
82
+
83
+ afterAll(() => {
84
+ // Restore
85
+ process.exit = originalProcessExit;
86
+ console.error.mockRestore();
87
+ console.log.mockRestore();
88
+ });
89
+
90
+ // ─── Tests ───────────────────────────────────────────────────────────────────
91
+
92
+ describe('Deployment Automation Module (ESM)', () => {
93
+ describe('getAuth0AuthToken', () => {
94
+ it('should return access token on success', async () => {
95
+ axios.post.mockResolvedValue({ data: { access_token: 'mock-token' } });
96
+ const token = await getAuth0AuthToken('auth.domain', 'cid', 'secret');
97
+ expect(token).toBe('mock-token');
98
+ });
99
+
100
+ it('should return undefined on failure', async () => {
101
+ axios.post.mockRejectedValue({ message: 'fail' });
102
+ const token = await getAuth0AuthToken('auth.domain', 'cid', 'secret');
103
+ expect(token).toBeUndefined();
104
+ expect(console.error).toHaveBeenCalledWith(
105
+ 'Error fetching Auth0 token:',
106
+ 'fail',
107
+ );
108
+ });
109
+ });
110
+
111
+ describe('cleanAndWritePropertiesFile', () => {
112
+ it('writes cleaned file content', async () => {
113
+ fs.writeFile.mockResolvedValue();
114
+ await cleanAndWritePropertiesFile('/tmp/test.properties', 'a=1\n\nb=2\n');
115
+ expect(fs.writeFile).toHaveBeenCalledWith(
116
+ '/tmp/test.properties',
117
+ 'a=1\nb=2',
118
+ 'utf8',
119
+ );
120
+ });
121
+
122
+ it('calls process.exit on write error', async () => {
123
+ fs.writeFile.mockRejectedValue(new Error('disk full'));
124
+ await cleanAndWritePropertiesFile('/bad/path', 'x=y');
125
+ expect(process.exit).toHaveBeenCalledWith(1);
126
+ });
127
+ });
128
+
129
+ describe('updateCoreSiteConfig', () => {
130
+ it('updates config when S3 is enabled', async () => {
131
+ config.getVaultSecretsConfigs.mockReturnValue({
132
+ awsSecretsPath: 'aws/path',
133
+ });
134
+
135
+ deploy.cloneRepository.mockResolvedValue('/repo/path');
136
+
137
+ vault.getVaultSecrets.mockResolvedValue({
138
+ AWS_ACCESS_KEY_ID: 'abc',
139
+ AWS_SECRET_ACCESS_KEY: 'def',
140
+ AWS_REGION: 'us-west-2',
141
+ });
142
+
143
+ fs.ensureDir.mockResolvedValue();
144
+ fs.writeFile.mockResolvedValue();
145
+ deploy.pushDeployConfig.mockResolvedValue();
146
+
147
+ await updateCoreSiteConfig('mysite', 'dev', true, false);
148
+
149
+ expect(fs.ensureDir).toHaveBeenCalledWith('/repo/path/MYSITE');
150
+ expect(fs.writeFile).toHaveBeenCalled();
151
+ expect(deploy.pushDeployConfig).toHaveBeenCalled();
152
+ });
153
+
154
+ it('calls process.exit if cloneRepository fails', async () => {
155
+ config.getVaultSecretsConfigs.mockReturnValue({
156
+ awsSecretsPath: 'aws/path',
157
+ });
158
+
159
+ deploy.cloneRepository.mockRejectedValue(new Error('bad clone'));
160
+
161
+ await updateCoreSiteConfig('mysite', 'dev', true, false);
162
+
163
+ expect(process.exit).toHaveBeenCalledWith(1);
164
+ expect(console.error).toHaveBeenCalledWith('Error:', 'bad clone');
165
+ });
166
+ });
167
+ });
@@ -2,7 +2,7 @@ import { getVaultSecrets } from './vault.js';
2
2
  import { getVaultSecretsConfigs } from '../next/config.js';
3
3
  import { dump } from 'auth0-deploy-cli';
4
4
 
5
- export async function exportConf(site, env) {
5
+ export async function exportConf(site, env, auth0Tenant) {
6
6
  try {
7
7
  console.log(
8
8
  `Exporting Auth0 configuration for site: ${site} and env: ${env}`,
@@ -13,7 +13,12 @@ export async function exportConf(site, env) {
13
13
  console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
14
14
  const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
15
15
 
16
- const auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
16
+ let auth0Domain;
17
+ if (auth0Tenant === '') {
18
+ auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
19
+ } else {
20
+ auth0Domain = `${auth0Tenant}.us.auth0.com`;
21
+ }
17
22
  const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
18
23
  const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
19
24