@madgex/fert 6.0.1 → 6.0.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/bin/cli.js +19 -14
- package/bin/commands/_service-command-bootstrap.js +12 -14
- package/bin/commands/build-tasks/build-external-assets.js +5 -5
- package/bin/commands/build-tasks/build-tokens.js +7 -7
- package/bin/commands/build-tasks/bundle-entry.js +13 -10
- package/bin/commands/build.js +19 -23
- package/bin/commands/configs.js +18 -22
- package/bin/commands/dev-server.js +17 -14
- package/bin/commands/init.js +13 -14
- package/bin/commands/publish-tasks/asset-store-uploader.js +12 -12
- package/bin/commands/publish-tasks/get-aws-parameter.js +4 -6
- package/bin/commands/publish.js +12 -12
- package/bin/utils/configs.js +39 -47
- package/bin/utils/cpid-lookup.js +12 -12
- package/bin/utils/cpid-matches-git-remote.js +7 -7
- package/bin/utils/getSchemaMeta.js +2 -4
- package/bin/utils/index.js +53 -54
- package/bin/utils/logging.js +4 -3
- package/bin/utils/lookup-cf-distribution-ids.js +15 -15
- package/bin/utils/persistent-cache-with-ttl.js +18 -18
- package/bin/utils/resolve-external-assets.js +3 -9
- package/bin/utils/slug.js +2 -2
- package/constants.js +50 -54
- package/eslint.config.js +19 -0
- package/package.json +10 -10
- package/server/extensions/error-logging.js +1 -1
- package/server/index.js +5 -101
- package/server/plugins/hapi-vite.js +8 -5
- package/server/routes/public.js +4 -2
- package/server/routes/views.js +5 -7
- package/server/server.js +104 -0
- package/server/view-manager.js +5 -5
- package/vite.config.js +4 -4
package/bin/utils/configs.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
4
|
+
import { glob } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import * as Hoek from '@hapi/hoek';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { log } from '../utils/logging.js';
|
|
9
|
+
import { CONFIG_DIR } from '../../constants.js';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Validates the local configuration files against the provided schema.
|
|
@@ -16,7 +19,7 @@ const { CONFIG_DIR } = require('../../constants');
|
|
|
16
19
|
* @returns {Promise<void>} - Returns a promise that resolves if all configurations are valid.
|
|
17
20
|
* @throws {Error} - Throws an error if any configuration is invalid.
|
|
18
21
|
*/
|
|
19
|
-
|
|
22
|
+
export async function validateLocalConfigs({ workingDir, clientPropertyId, throwable = true }) {
|
|
20
23
|
Hoek.assert(clientPropertyId, 'clientPropertyId is required');
|
|
21
24
|
Hoek.assert(workingDir, 'workingDir is required');
|
|
22
25
|
|
|
@@ -30,7 +33,7 @@ const validateLocalConfigs = async ({ workingDir, clientPropertyId, throwable =
|
|
|
30
33
|
const api = await getConfigAPI({
|
|
31
34
|
clientPropertyId,
|
|
32
35
|
});
|
|
33
|
-
const localConfigs = loadLocalConfigs(workingDir);
|
|
36
|
+
const localConfigs = await loadLocalConfigs(workingDir);
|
|
34
37
|
|
|
35
38
|
const validationPromises = Object.keys(localConfigs).map(async (configName) => {
|
|
36
39
|
try {
|
|
@@ -67,9 +70,9 @@ const validateLocalConfigs = async ({ workingDir, clientPropertyId, throwable =
|
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
await Promise.all(validationPromises);
|
|
70
|
-
}
|
|
73
|
+
}
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
export async function getConfigAPI({ clientPropertyId, environment = 'production' } = {}) {
|
|
73
76
|
const { ConfigAPI } = await import('@madgex/config-api-sdk');
|
|
74
77
|
|
|
75
78
|
const api = new ConfigAPI({
|
|
@@ -80,7 +83,7 @@ const getConfigAPI = async ({ clientPropertyId, environment = 'production' } = {
|
|
|
80
83
|
await api.loadSchemas();
|
|
81
84
|
|
|
82
85
|
return api;
|
|
83
|
-
}
|
|
86
|
+
}
|
|
84
87
|
|
|
85
88
|
/**
|
|
86
89
|
* loading all configs from a directory (usually root /configs folder)
|
|
@@ -88,35 +91,31 @@ const getConfigAPI = async ({ clientPropertyId, environment = 'production' } = {
|
|
|
88
91
|
* @param {string} workingDir
|
|
89
92
|
* @returns {Promise<Object>} - Object map of configs loaded from files {filename:configJSON,...}
|
|
90
93
|
*/
|
|
91
|
-
|
|
94
|
+
export async function loadLocalConfigs(workingDir) {
|
|
92
95
|
const dir = path.join(workingDir, CONFIG_DIR);
|
|
93
96
|
const configs = {};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
data: require(filePath),
|
|
111
|
-
};
|
|
112
|
-
} catch (err) {
|
|
113
|
-
log.error(`Error loading config (${filePath}): ${err.message}`);
|
|
114
|
-
}
|
|
97
|
+
|
|
98
|
+
const configFilePaths = await Array.fromAsync(glob(`*.json`, { cwd: dir }));
|
|
99
|
+
|
|
100
|
+
for (const file of configFilePaths) {
|
|
101
|
+
const filePath = path.join(dir, file);
|
|
102
|
+
|
|
103
|
+
if (fs.statSync(filePath).isFile()) {
|
|
104
|
+
const fileName = path.basename(file, path.extname(file));
|
|
105
|
+
const { default: data } = await import(pathToFileURL(filePath), { with: { type: 'json' } });
|
|
106
|
+
try {
|
|
107
|
+
configs[fileName] = {
|
|
108
|
+
path: filePath,
|
|
109
|
+
data,
|
|
110
|
+
};
|
|
111
|
+
} catch (err) {
|
|
112
|
+
log.error(`Error loading config (${filePath}): ${err.message}`);
|
|
115
113
|
}
|
|
116
|
-
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
117
116
|
|
|
118
117
|
return configs;
|
|
119
|
-
}
|
|
118
|
+
}
|
|
120
119
|
|
|
121
120
|
/**
|
|
122
121
|
* Handles the removal and setting of project configs in the Configuration API.
|
|
@@ -128,7 +127,7 @@ const loadLocalConfigs = (workingDir) => {
|
|
|
128
127
|
*
|
|
129
128
|
* @returns {Promise<boolean>} - Returns a promise that resolves to true if the update is successful.
|
|
130
129
|
*/
|
|
131
|
-
|
|
130
|
+
export async function updateProjectConfigs({ clientPropertyId, workingDir, environment = 'production' } = {}) {
|
|
132
131
|
Hoek.assert(clientPropertyId, 'clientPropertyId is required');
|
|
133
132
|
Hoek.assert(workingDir, 'workingDir is required');
|
|
134
133
|
|
|
@@ -146,7 +145,7 @@ const updateProjectConfigs = async ({ clientPropertyId, workingDir, environment
|
|
|
146
145
|
|
|
147
146
|
log.info('Updating configs…');
|
|
148
147
|
|
|
149
|
-
const localConfigs = loadLocalConfigs(workingDir);
|
|
148
|
+
const localConfigs = await loadLocalConfigs(workingDir);
|
|
150
149
|
const { toRemove, toSet } = collateConfigs(api, localConfigs);
|
|
151
150
|
|
|
152
151
|
// Will throw on first failure
|
|
@@ -161,9 +160,9 @@ const updateProjectConfigs = async ({ clientPropertyId, workingDir, environment
|
|
|
161
160
|
log.error('Failed to apply project configs', error);
|
|
162
161
|
throw error;
|
|
163
162
|
}
|
|
164
|
-
}
|
|
163
|
+
}
|
|
165
164
|
|
|
166
|
-
|
|
165
|
+
export function collateConfigs(api, localConfigs) {
|
|
167
166
|
const toRemove = {};
|
|
168
167
|
const toSet = {};
|
|
169
168
|
|
|
@@ -193,7 +192,7 @@ const collateConfigs = (api, localConfigs) => {
|
|
|
193
192
|
});
|
|
194
193
|
|
|
195
194
|
return { toRemove, toSet };
|
|
196
|
-
}
|
|
195
|
+
}
|
|
197
196
|
|
|
198
197
|
const getUnsetKeysWithDefaults = (defaults = {}, config = {}) => {
|
|
199
198
|
Hoek.assert(typeof defaults === 'object' && defaults !== null, 'defaults must be an object');
|
|
@@ -239,10 +238,3 @@ const setConfigs = async (api, toSet) => {
|
|
|
239
238
|
|
|
240
239
|
return Promise.all(operations);
|
|
241
240
|
};
|
|
242
|
-
|
|
243
|
-
module.exports = {
|
|
244
|
-
getConfigAPI,
|
|
245
|
-
validateLocalConfigs,
|
|
246
|
-
updateProjectConfigs,
|
|
247
|
-
collateConfigs,
|
|
248
|
-
};
|
package/bin/utils/cpid-lookup.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { log } from '../utils/logging.js';
|
|
4
|
+
import { PROPERTY_ID_API, ONE_WEEK } from '../../constants.js';
|
|
5
|
+
import { PersistentCacheWithTtl } from './persistent-cache-with-ttl.js';
|
|
6
6
|
|
|
7
|
-
const cache = new
|
|
7
|
+
const cache = new PersistentCacheWithTtl('cpid-cache', {
|
|
8
8
|
ttl: ONE_WEEK,
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export async function doCpidLookup(clientPropertyId) {
|
|
12
12
|
const API_URL = new URL(clientPropertyId, PROPERTY_ID_API).toString();
|
|
13
13
|
|
|
14
14
|
const results = await axios
|
|
@@ -34,15 +34,15 @@ exports.doCpidLookup = async (clientPropertyId) => {
|
|
|
34
34
|
rootClientPropertyId: parentCpid ?? clientPropertyId,
|
|
35
35
|
isAffiliate: !!parentCpid,
|
|
36
36
|
};
|
|
37
|
-
}
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
export async function cpidLookup(clientPropertyId, options = {}) {
|
|
40
40
|
if (options.purgeCache) {
|
|
41
41
|
cache.purgeCacheFile();
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (!options.cache) {
|
|
45
|
-
return
|
|
45
|
+
return doCpidLookup(clientPropertyId);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const value = cache.get(clientPropertyId);
|
|
@@ -51,9 +51,9 @@ exports.cpidLookup = async (clientPropertyId, options = {}) => {
|
|
|
51
51
|
return value;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const result = await
|
|
54
|
+
const result = await doCpidLookup(clientPropertyId);
|
|
55
55
|
|
|
56
56
|
cache.set(clientPropertyId, result);
|
|
57
57
|
|
|
58
58
|
return result;
|
|
59
|
-
}
|
|
59
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import simpleGit from 'simple-git';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as Hoek from '@hapi/hoek';
|
|
4
|
+
import dedent from 'dedent';
|
|
5
|
+
import * as utils from './index.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Validates client property ID found in the fert config against the git url and the package name.
|
|
@@ -18,7 +18,7 @@ const utils = require('./index.js');
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
export async function cpIdMatchesGitRemote(fertConfig) {
|
|
22
22
|
const fertConfigDir = await utils.findFertConfigDir();
|
|
23
23
|
|
|
24
24
|
// Validate that the fert config directory is a git repository
|
|
@@ -56,4 +56,4 @@ exports.cpIdMatchesGitRemote = async (fertConfig) => {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return false;
|
|
59
|
-
}
|
|
59
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export function getSchemaMeta(schema, key = null) {
|
|
2
2
|
if (!schema || typeof schema.describe !== 'function') {
|
|
3
3
|
throw new Error('Schema is required');
|
|
4
4
|
}
|
|
@@ -16,6 +16,4 @@ const getSchemaMeta = function getSchemaMeta(schema, key = null) {
|
|
|
16
16
|
} catch (error) {
|
|
17
17
|
throw new Error('Invalid Joi schema', { cause: error });
|
|
18
18
|
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = { getSchemaMeta };
|
|
19
|
+
}
|
package/bin/utils/index.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
3
4
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
import { glob } from 'node:fs/promises';
|
|
6
|
+
import { findUp } from 'find-up-simple';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import uuidValidator from 'uuid-validate';
|
|
9
|
+
import * as Hoek from '@hapi/hoek';
|
|
10
|
+
import simpleGit from 'simple-git';
|
|
11
|
+
import { cpidLookup } from './cpid-lookup.js';
|
|
12
|
+
import { cpIdMatchesGitRemote } from './cpid-matches-git-remote.js';
|
|
13
|
+
import { resolveExternalAssets } from './resolve-external-assets.js';
|
|
14
|
+
import { log } from './logging.js';
|
|
15
|
+
import { CONFIG_API, VERSION, FERT_CONFIG_FILENAME, FERT_SERVICE_CONFIG_FILENAME } from '../../constants.js';
|
|
16
|
+
|
|
17
|
+
export function printBanner() {
|
|
17
18
|
console.log(`\n${chalk.green.bold('Fert')} v${VERSION}`);
|
|
18
|
-
}
|
|
19
|
+
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
export async function getConfig(cpid, configNames = []) {
|
|
21
22
|
Hoek.assert(Array.isArray(configNames), 'configNames must be an array');
|
|
22
23
|
|
|
23
24
|
const result = {};
|
|
@@ -31,15 +32,15 @@ exports.getConfig = async (cpid, configNames = []) => {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
return result;
|
|
34
|
-
}
|
|
35
|
+
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
export async function resolveConfig(options = {}) {
|
|
37
38
|
Hoek.assert(options.serviceName, 'serviceName is required');
|
|
38
39
|
|
|
39
|
-
const rootDir = await
|
|
40
|
+
const rootDir = await findFertConfigDir();
|
|
40
41
|
const git = simpleGit({ baseDir: rootDir });
|
|
41
42
|
|
|
42
|
-
const serviceConfigs = await
|
|
43
|
+
const serviceConfigs = await loadServiceConfigFiles();
|
|
43
44
|
|
|
44
45
|
// workingDir based on service folder
|
|
45
46
|
const { dir: workingDir, serviceConfig } = serviceConfigs.find(
|
|
@@ -55,12 +56,12 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
55
56
|
scripts: [],
|
|
56
57
|
},
|
|
57
58
|
};
|
|
58
|
-
|
|
59
|
+
const configFromFile = await loadConfigFromFile({ dir: rootDir });
|
|
59
60
|
const fertConfig = Hoek.applyToDefaults(
|
|
60
61
|
defaults,
|
|
61
62
|
// merge fert config with service config
|
|
62
63
|
{
|
|
63
|
-
...
|
|
64
|
+
...configFromFile,
|
|
64
65
|
...serviceConfig,
|
|
65
66
|
},
|
|
66
67
|
);
|
|
@@ -88,7 +89,7 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
88
89
|
|
|
89
90
|
fertConfig.externalAssets = resolveExternalAssets(fertConfig.externalAssets);
|
|
90
91
|
|
|
91
|
-
fertConfig.config = await
|
|
92
|
+
fertConfig.config = await getConfig(fertConfig.clientPropertyId, [
|
|
92
93
|
'JobseekerSiteWebSitePath',
|
|
93
94
|
// 'SiteName',
|
|
94
95
|
]);
|
|
@@ -102,7 +103,7 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
102
103
|
},
|
|
103
104
|
client,
|
|
104
105
|
};
|
|
105
|
-
}
|
|
106
|
+
}
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
109
|
* Find the root fert config in this project. This is required to
|
|
@@ -110,45 +111,43 @@ exports.resolveConfig = async (options = {}) => {
|
|
|
110
111
|
*
|
|
111
112
|
* @returns {string} closest fert config directory in this folder, or above
|
|
112
113
|
*/
|
|
113
|
-
|
|
114
|
-
const { findUp } = await import('find-up-simple');
|
|
114
|
+
export async function findFertConfigDir() {
|
|
115
115
|
const fertConfigPath = await findUp(FERT_CONFIG_FILENAME);
|
|
116
116
|
if (!fertConfigPath) throw new Error(`couldn't find ${FERT_CONFIG_FILENAME}`);
|
|
117
117
|
return path.resolve(path.dirname(fertConfigPath));
|
|
118
|
-
}
|
|
118
|
+
}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
121
|
* find and load all service config files, return config and location
|
|
122
122
|
* @param {string} root directory path
|
|
123
123
|
* @returns
|
|
124
124
|
*/
|
|
125
|
-
|
|
126
|
-
const rootDir = await
|
|
125
|
+
export async function loadServiceConfigFiles() {
|
|
126
|
+
const rootDir = await findFertConfigDir();
|
|
127
127
|
|
|
128
128
|
const serviceConfigs = [];
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
const serviceConfigPaths = await Array.fromAsync(
|
|
130
|
+
glob(`**/${FERT_SERVICE_CONFIG_FILENAME}`, {
|
|
131
|
+
cwd: path.resolve(rootDir),
|
|
132
|
+
exclude: (item) => ['node_modules', 'dist'].includes(item),
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
for await (const filePath of serviceConfigPaths) {
|
|
133
137
|
const dir = path.resolve(rootDir, path.dirname(filePath));
|
|
134
|
-
const serviceConfig = await
|
|
138
|
+
const serviceConfig = await loadConfigFromFile({
|
|
135
139
|
dir,
|
|
136
140
|
filename: FERT_SERVICE_CONFIG_FILENAME,
|
|
137
141
|
});
|
|
138
142
|
serviceConfigs.push({ dir, serviceConfig });
|
|
139
143
|
}
|
|
140
144
|
return serviceConfigs;
|
|
141
|
-
}
|
|
145
|
+
}
|
|
142
146
|
|
|
143
|
-
|
|
147
|
+
export async function loadConfigFromFile({ dir = process.cwd(), filename = FERT_CONFIG_FILENAME, silent = false }) {
|
|
144
148
|
const configPath = path.resolve(dir, filename);
|
|
145
149
|
try {
|
|
146
|
-
|
|
147
|
-
if (require.cache[configPath]) {
|
|
148
|
-
delete require.cache[configPath];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const fertConfig = require(configPath);
|
|
150
|
+
const { default: fertConfig } = await import(pathToFileURL(configPath));
|
|
152
151
|
|
|
153
152
|
return fertConfig;
|
|
154
153
|
} catch (err) {
|
|
@@ -160,33 +159,33 @@ exports.loadConfigFromFile = ({ dir = process.cwd(), filename = FERT_CONFIG_FILE
|
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
return null;
|
|
163
|
-
}
|
|
162
|
+
}
|
|
164
163
|
|
|
165
|
-
|
|
164
|
+
export function ensureTrailingSlash(str) {
|
|
166
165
|
const lastChar = str.at(-1);
|
|
167
166
|
|
|
168
167
|
return lastChar === '/' ? str : `${str}/`;
|
|
169
|
-
}
|
|
168
|
+
}
|
|
170
169
|
|
|
171
|
-
|
|
170
|
+
export async function exists(_path) {
|
|
172
171
|
try {
|
|
173
172
|
fs.access(_path);
|
|
174
173
|
return true;
|
|
175
174
|
} catch {
|
|
176
175
|
return false;
|
|
177
176
|
}
|
|
178
|
-
}
|
|
177
|
+
}
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
export function isEmptyDir(_path) {
|
|
181
180
|
const files = fs.readdirSync(_path);
|
|
182
181
|
return files.length === 0 || (files.length === 1 && files[0] === '.git');
|
|
183
|
-
}
|
|
182
|
+
}
|
|
184
183
|
|
|
185
|
-
|
|
184
|
+
export function formatTargetDir(targetDir) {
|
|
186
185
|
return targetDir?.trim().replace(/\/+$/g, '');
|
|
187
|
-
}
|
|
186
|
+
}
|
|
188
187
|
|
|
189
|
-
|
|
188
|
+
export function emptyDir(dir) {
|
|
190
189
|
if (!fs.existsSync(dir)) {
|
|
191
190
|
return;
|
|
192
191
|
}
|
|
@@ -196,4 +195,4 @@ exports.emptyDir = function emptyDir(dir) {
|
|
|
196
195
|
}
|
|
197
196
|
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true });
|
|
198
197
|
}
|
|
199
|
-
}
|
|
198
|
+
}
|
package/bin/utils/logging.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { CloudFrontClient, ListDistributionsCommand } from '@aws-sdk/client-cloudfront';
|
|
2
|
+
import { PersistentCacheWithTtl } from './persistent-cache-with-ttl.js';
|
|
3
|
+
import assert from 'node:assert';
|
|
4
|
+
import { ONE_WEEK, AWS_REGION } from '../../constants.js';
|
|
5
|
+
import { log } from '../utils/logging.js';
|
|
6
6
|
|
|
7
|
-
const cache = new
|
|
7
|
+
const cache = new PersistentCacheWithTtl('cf-distribution-cache', {
|
|
8
8
|
ttl: ONE_WEEK,
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export async function doGetAllCloudFrontDistributions() {
|
|
12
12
|
const cloudfront = new CloudFrontClient({ region: AWS_REGION });
|
|
13
13
|
const distributions = [];
|
|
14
14
|
|
|
@@ -25,9 +25,9 @@ exports.doGetAllCloudFrontDistributions = async () => {
|
|
|
25
25
|
} while (isTruncated);
|
|
26
26
|
|
|
27
27
|
return distributions;
|
|
28
|
-
}
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
export async function getAllCloudFrontDistributions(options = {}) {
|
|
31
31
|
assert(options.target, 'Target required');
|
|
32
32
|
const CACHE_KEY = `cf-distributions:${options.target}`;
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ exports.getAllCloudFrontDistributions = async (options = {}) => {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
if (!options.cache) {
|
|
39
|
-
return
|
|
39
|
+
return doGetAllCloudFrontDistributions();
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const value = cache.get(CACHE_KEY);
|
|
@@ -47,24 +47,24 @@ exports.getAllCloudFrontDistributions = async (options = {}) => {
|
|
|
47
47
|
|
|
48
48
|
log.info('\nRefreshing CloudFront Distributions cache…');
|
|
49
49
|
|
|
50
|
-
const result = await
|
|
50
|
+
const result = await doGetAllCloudFrontDistributions();
|
|
51
51
|
|
|
52
52
|
cache.set(CACHE_KEY, result);
|
|
53
53
|
|
|
54
54
|
log.success('Completed refreshing CF distribution cache.\n');
|
|
55
55
|
|
|
56
56
|
return result;
|
|
57
|
-
}
|
|
57
|
+
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Find all CloudFront distribution Ids that are associated with the supplied domain.
|
|
61
61
|
* @param {string} domain Search all CloudFront Distributions for those that match domain name.
|
|
62
62
|
* @returns {Promise<Array.<{id:string, aliases:[string]}>>} An array of objects.
|
|
63
63
|
*/
|
|
64
|
-
|
|
64
|
+
export async function getCloudFrontDistributionsForDomain(domain, options) {
|
|
65
65
|
assert(domain && typeof domain === 'string', 'Domain name required');
|
|
66
66
|
|
|
67
|
-
const distributions = await
|
|
67
|
+
const distributions = await getAllCloudFrontDistributions(options);
|
|
68
68
|
|
|
69
69
|
return distributions.reduce((accum, val) => {
|
|
70
70
|
const { Id, Aliases } = val;
|
|
@@ -76,4 +76,4 @@ exports.getCloudFrontDistributionsForDomain = async (domain, options) => {
|
|
|
76
76
|
|
|
77
77
|
return accum;
|
|
78
78
|
}, []);
|
|
79
|
-
}
|
|
79
|
+
}
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { FlatCache } from 'flat-cache';
|
|
4
|
+
import { TMP_DIR, VERSION } from '../../constants.js';
|
|
5
|
+
import { slug } from './slug.js';
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
export class PersistentCacheWithTtl {
|
|
8
8
|
constructor(name, options = { ttl: 0 }) {
|
|
9
9
|
assert(name, 'Cache name required');
|
|
10
|
-
|
|
11
10
|
this.name = name;
|
|
12
|
-
this.cacheDir = path.resolve(`${TMP_DIR}/fert-${slug(VERSION)}`);
|
|
13
|
-
this.cache = this._loadCache();
|
|
14
|
-
|
|
15
11
|
this.options = options;
|
|
12
|
+
|
|
13
|
+
this.createCache();
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
createCache() {
|
|
17
|
+
this.cache = new FlatCache({
|
|
18
|
+
name: this.name,
|
|
19
|
+
cacheDir: path.resolve(`${TMP_DIR}/fert-${slug(VERSION)}`),
|
|
20
|
+
});
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
set(key, value) {
|
|
23
|
-
this.cache.
|
|
24
|
+
this.cache.set(key, {
|
|
24
25
|
value,
|
|
25
26
|
expire: new Date().getTime() + this.options.ttl,
|
|
26
27
|
});
|
|
@@ -29,10 +30,10 @@ class persistentCacheWithTtl {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
get(key) {
|
|
32
|
-
let cachedBlob = this.cache.
|
|
33
|
+
let cachedBlob = this.cache.get(key);
|
|
33
34
|
|
|
34
35
|
if (cachedBlob && new Date().getTime() > cachedBlob.expire) {
|
|
35
|
-
this.cache.
|
|
36
|
+
this.cache.delete(key);
|
|
36
37
|
cachedBlob = null;
|
|
37
38
|
|
|
38
39
|
this.cache.save(true);
|
|
@@ -42,8 +43,7 @@ class persistentCacheWithTtl {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
purgeCacheFile() {
|
|
45
|
-
|
|
46
|
-
this.
|
|
46
|
+
this.cache.destroy();
|
|
47
|
+
this.createCache();
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
|
-
exports.persistentCacheWithTtl = persistentCacheWithTtl;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class LinkAsset {
|
|
1
|
+
export class LinkAsset {
|
|
2
2
|
constructor(arg) {
|
|
3
3
|
this.rel = 'stylesheet';
|
|
4
4
|
this.type = 'text/css';
|
|
@@ -18,7 +18,7 @@ class LinkAsset {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
class ScriptAsset {
|
|
21
|
+
export class ScriptAsset {
|
|
22
22
|
constructor(arg) {
|
|
23
23
|
this.async = true;
|
|
24
24
|
if (typeof arg === 'string') {
|
|
@@ -48,7 +48,7 @@ class ScriptAsset {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function resolveExternalAssets(assets = {}) {
|
|
51
|
+
export function resolveExternalAssets(assets = {}) {
|
|
52
52
|
const result = {
|
|
53
53
|
links: [],
|
|
54
54
|
scripts: [],
|
|
@@ -72,9 +72,3 @@ function resolveExternalAssets(assets = {}) {
|
|
|
72
72
|
|
|
73
73
|
return result;
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
module.exports = {
|
|
77
|
-
LinkAsset,
|
|
78
|
-
ScriptAsset,
|
|
79
|
-
resolveExternalAssets,
|
|
80
|
-
};
|
package/bin/utils/slug.js
CHANGED