edge-functions 2.7.0-stage.1 → 2.7.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/CHANGELOG.md +15 -1
- package/README.md +1 -1
- package/lib/build/dispatcher/dispatcher.js +9 -4
- package/lib/commands/dev.commands.js +2 -2
- package/lib/env/server.env.js +47 -6
- package/lib/main.js +53 -3
- package/lib/notations/namespaces.js +23 -1
- package/lib/utils/feedback/feedback.utils.js +30 -3
- package/lib/utils/generateManifest/generateManifest.utils.js +77 -50
- package/lib/utils/generateManifest/generateManifest.utils.test.js +111 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## [2.7.0
|
|
1
|
+
## [2.7.0](https://github.com/aziontech/vulcan/compare/v2.6.2...v2.7.0) (2024-05-07)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Features
|
|
@@ -7,6 +7,20 @@
|
|
|
7
7
|
* eject azion.config.js file ([#314](https://github.com/aziontech/vulcan/issues/314)) ([5b6494b](https://github.com/aziontech/vulcan/commit/5b6494b19b506b9d7e0ce9a47b41213b681c6167))
|
|
8
8
|
* eject manifest ([ae556fa](https://github.com/aziontech/vulcan/commit/ae556fa3ffdf7b2b97e01e2bf9ae4a766beca8df))
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* local env loop ([99c3742](https://github.com/aziontech/vulcan/commit/99c37420102d5b49bb029133b6580f165b19f32b))
|
|
14
|
+
* local env loop ([#319](https://github.com/aziontech/vulcan/issues/319)) ([05c4679](https://github.com/aziontech/vulcan/commit/05c4679d8ba6fd1d6d52f9bd44382fd6d1d9df93))
|
|
15
|
+
|
|
16
|
+
## [2.7.0-stage.2](https://github.com/aziontech/vulcan/compare/v2.7.0-stage.1...v2.7.0-stage.2) (2024-05-07)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* local env loop ([99c3742](https://github.com/aziontech/vulcan/commit/99c37420102d5b49bb029133b6580f165b19f32b))
|
|
22
|
+
* local env loop ([#319](https://github.com/aziontech/vulcan/issues/319)) ([05c4679](https://github.com/aziontech/vulcan/commit/05c4679d8ba6fd1d6d52f9bd44382fd6d1d9df93))
|
|
23
|
+
|
|
10
24
|
### [2.6.2](https://github.com/aziontech/vulcan/compare/v2.6.1...v2.6.2) (2024-04-22)
|
|
11
25
|
|
|
12
26
|
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Table:
|
|
|
40
40
|
| Simple Js Esm | ✅ |
|
|
41
41
|
| Simple Ts Esm | ✅ |
|
|
42
42
|
|
|
43
|
-
Last test run date: 05/
|
|
43
|
+
Last test run date: 05/07/24 02:56:50 AM
|
|
44
44
|
## Quick Installation
|
|
45
45
|
|
|
46
46
|
For those who just want to use Vulcan in their project without contributing to the development, you can install it directly from npm.
|
|
@@ -123,7 +123,7 @@ class Dispatcher {
|
|
|
123
123
|
* @returns {object} - Preset files
|
|
124
124
|
*/
|
|
125
125
|
async loadPreset() {
|
|
126
|
-
feedback.build.info('Loading build context...');
|
|
126
|
+
feedback.build.info('Loading build context ...');
|
|
127
127
|
|
|
128
128
|
const VALID_BUILD_PRESETS = presets.getKeys();
|
|
129
129
|
const vulcanRootPath = resolve(this.vulcanLibPath, '..');
|
|
@@ -343,10 +343,15 @@ class Dispatcher {
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
static async generateFinalManifest() {
|
|
346
|
-
feedback.build.info(
|
|
346
|
+
feedback.build.info(
|
|
347
|
+
'Checking Azion Edge Application configuration file...',
|
|
348
|
+
);
|
|
347
349
|
const buildConfigPath = join(process.cwd(), 'azion.config.js');
|
|
348
|
-
|
|
349
|
-
|
|
350
|
+
let vulcanCustomConfigModule = {};
|
|
351
|
+
if (existsSync(buildConfigPath)) {
|
|
352
|
+
vulcanCustomConfigModule = (await import(buildConfigPath)).default;
|
|
353
|
+
}
|
|
354
|
+
await generateManifest(vulcanCustomConfigModule, true);
|
|
350
355
|
feedback.build.success('Manifest generated successfully.');
|
|
351
356
|
}
|
|
352
357
|
|
|
@@ -19,11 +19,11 @@ import { Commands } from '#namespaces';
|
|
|
19
19
|
*
|
|
20
20
|
* devCommand('./path/to/entry.js', { port: 3000 });
|
|
21
21
|
*/
|
|
22
|
-
async function devCommand(entry, {
|
|
22
|
+
async function devCommand(entry, { firewall, port }) {
|
|
23
23
|
const parsedPort = parseInt(port, 10);
|
|
24
24
|
const { server } = await import('#env');
|
|
25
25
|
const entryPoint = entry || join(process.cwd(), '.edge/worker.js');
|
|
26
|
-
server(entryPoint,
|
|
26
|
+
server(entryPoint, firewall, parsedPort);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export default devCommand;
|
package/lib/env/server.env.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import net from 'net';
|
|
1
2
|
import { debug, readWorkerFile, feedback, helperHandlerCode } from '#utils';
|
|
2
3
|
import { Messages } from '#constants';
|
|
3
4
|
import { runServer, EdgeRuntime } from 'edge-runtime';
|
|
@@ -9,6 +10,39 @@ import buildCommand from '../commands/build.commands.js';
|
|
|
9
10
|
let currentServer;
|
|
10
11
|
let isChangeHandlerRunning = false;
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Checks if a port is in use by trying to connect to it.
|
|
15
|
+
* @param {number} port - The port number to check.
|
|
16
|
+
* @returns {Promise<boolean>} - True if the port is in use, false otherwise.
|
|
17
|
+
*/
|
|
18
|
+
function checkPortAvailability(port) {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const client = new net.Socket();
|
|
21
|
+
client.setTimeout(1000); // Timeout for the connection attempt
|
|
22
|
+
|
|
23
|
+
client.on('connect', () => {
|
|
24
|
+
client.destroy(); // Destroy the socket after successful connection
|
|
25
|
+
resolve(true); // Port is in use
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
client.on('timeout', () => {
|
|
29
|
+
client.destroy();
|
|
30
|
+
resolve(false); // Timeout likely means the port is not in use
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
client.on('error', (err) => {
|
|
34
|
+
client.destroy();
|
|
35
|
+
if (err.code === 'ECONNREFUSED') {
|
|
36
|
+
resolve(false); // Connection refused means the port is not in use
|
|
37
|
+
} else {
|
|
38
|
+
resolve(true); // Assume port is in use if there's an error
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
client.connect(port, '127.0.0.1');
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
12
46
|
/**
|
|
13
47
|
* Read the worker code from a specified path.
|
|
14
48
|
* @param {string} workerPath - Path to the worker file.
|
|
@@ -74,14 +108,14 @@ async function buildToLocalServer(isFirewall) {
|
|
|
74
108
|
*/
|
|
75
109
|
async function manageServer(workerPath, port, isFirewall) {
|
|
76
110
|
try {
|
|
77
|
-
await buildToLocalServer(isFirewall);
|
|
78
|
-
|
|
79
|
-
const workerCode = await readWorkerCode(workerPath);
|
|
80
|
-
|
|
81
111
|
if (currentServer) {
|
|
82
112
|
await currentServer.close();
|
|
83
113
|
}
|
|
84
114
|
|
|
115
|
+
await buildToLocalServer(isFirewall);
|
|
116
|
+
|
|
117
|
+
const workerCode = await readWorkerCode(workerPath);
|
|
118
|
+
|
|
85
119
|
try {
|
|
86
120
|
currentServer = await initializeServer(port, workerCode);
|
|
87
121
|
feedback.server.success(
|
|
@@ -139,10 +173,17 @@ async function handleFileChange(path, workerPath, port, isFirewall) {
|
|
|
139
173
|
/**
|
|
140
174
|
* Entry point function to start the server and watch for file changes.
|
|
141
175
|
* @param {string} workerPath - Path to the worker file.
|
|
142
|
-
* @param {number} port - The port number.
|
|
143
176
|
* @param {boolean} isFirewall - (Experimental) Enable isFirewall for local environment.
|
|
177
|
+
* @param {number} port - The port number.
|
|
144
178
|
*/
|
|
145
|
-
async function startServer(workerPath,
|
|
179
|
+
async function startServer(workerPath, isFirewall, port) {
|
|
180
|
+
const IsPortInUse = await checkPortAvailability(port);
|
|
181
|
+
if (IsPortInUse) {
|
|
182
|
+
feedback.server.error(
|
|
183
|
+
`Port ${port} is in use. Please choose another port.`,
|
|
184
|
+
);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
146
187
|
await manageServer(workerPath, port, isFirewall); // Initialize the server for the first time
|
|
147
188
|
|
|
148
189
|
const watcher = chokidar.watch('./', {
|
package/lib/main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
2
|
+
import { resolve, join } from 'path';
|
|
3
|
+
import { readFileSync, readdirSync, unlinkSync } from 'fs';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { satisfies } from 'semver';
|
|
6
6
|
import { feedback, debug, getAbsoluteLibDirPath } from '#utils';
|
|
@@ -57,6 +57,55 @@ function setVulcanEnvironment() {
|
|
|
57
57
|
}
|
|
58
58
|
globalThis.vulcan = vulcanContext;
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Removes all temporary files starting with 'vulcan-' and ending with '.temp.js'.
|
|
63
|
+
*/
|
|
64
|
+
function cleanUpTempFiles() {
|
|
65
|
+
const directory = process.cwd();
|
|
66
|
+
const tempFiles = readdirSync(directory).filter(
|
|
67
|
+
(file) => file.startsWith('vulcan-') && file.endsWith('.temp.js'),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
tempFiles.forEach((file) => {
|
|
71
|
+
const filePath = join(directory, file);
|
|
72
|
+
unlinkSync(filePath);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Sets up event handlers for cleanup and error handling.
|
|
78
|
+
*/
|
|
79
|
+
function setupVulcanProcessHandlers() {
|
|
80
|
+
process.on('exit', cleanUpTempFiles);
|
|
81
|
+
process.on('SIGINT', () => {
|
|
82
|
+
cleanUpTempFiles();
|
|
83
|
+
process.exit(0);
|
|
84
|
+
});
|
|
85
|
+
process.on('SIGTERM', () => {
|
|
86
|
+
cleanUpTempFiles();
|
|
87
|
+
process.exit(0);
|
|
88
|
+
});
|
|
89
|
+
process.on('SIGHUP', () => {
|
|
90
|
+
cleanUpTempFiles();
|
|
91
|
+
process.exit(0);
|
|
92
|
+
});
|
|
93
|
+
process.on('SIGBREAK', () => {
|
|
94
|
+
cleanUpTempFiles();
|
|
95
|
+
process.exit(0);
|
|
96
|
+
});
|
|
97
|
+
process.on('uncaughtException', (error) => {
|
|
98
|
+
console.error('Uncaught Exception:', error);
|
|
99
|
+
cleanUpTempFiles();
|
|
100
|
+
process.exit(1);
|
|
101
|
+
});
|
|
102
|
+
process.on('unhandledRejection', (reason) => {
|
|
103
|
+
console.error('Unhandled Promise Rejection:', reason);
|
|
104
|
+
cleanUpTempFiles();
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
60
109
|
/**
|
|
61
110
|
* Starts the command-line interface program.
|
|
62
111
|
* @example
|
|
@@ -105,7 +154,7 @@ function startVulcanProgram() {
|
|
|
105
154
|
.command('dev')
|
|
106
155
|
.description('Start local environment')
|
|
107
156
|
.arguments('[entry]')
|
|
108
|
-
.option('-p, --port <port>', 'Specify the port', '
|
|
157
|
+
.option('-p, --port <port>', 'Specify the port', '3333')
|
|
109
158
|
.option(
|
|
110
159
|
'--firewall',
|
|
111
160
|
'To enable the firewall (Experimental) for local environment (default: false)',
|
|
@@ -137,6 +186,7 @@ try {
|
|
|
137
186
|
if (validateNodeMinVersion()) {
|
|
138
187
|
setVulcanEnvironment();
|
|
139
188
|
startVulcanProgram();
|
|
189
|
+
setupVulcanProcessHandlers();
|
|
140
190
|
}
|
|
141
191
|
if (!validateNodeMinVersion()) {
|
|
142
192
|
feedback.error(Messages.errors.invalid_node_version(MIN_NODE_VERSION));
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
const Utils = {};
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @namespace Platform
|
|
10
|
+
* @description Contains functions and actions to interact with the edge platform (Azion).
|
|
11
|
+
*/
|
|
12
|
+
const Platform = {};
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* @namespace Build
|
|
10
16
|
* @description Represents the structure responsible for pre-build and build processes for the edge.
|
|
@@ -42,4 +48,20 @@ const Commands = {};
|
|
|
42
48
|
*/
|
|
43
49
|
const Polyfills = {};
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @namespace Services
|
|
53
|
+
* @description Azion Platform Services.
|
|
54
|
+
*/
|
|
55
|
+
const Services = {};
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
Utils,
|
|
59
|
+
Platform,
|
|
60
|
+
Build,
|
|
61
|
+
Env,
|
|
62
|
+
Presets,
|
|
63
|
+
Edge,
|
|
64
|
+
Polyfills,
|
|
65
|
+
Commands,
|
|
66
|
+
Services,
|
|
67
|
+
};
|
|
@@ -40,9 +40,9 @@ const methods = {
|
|
|
40
40
|
logLevel: 'info',
|
|
41
41
|
},
|
|
42
42
|
option: {
|
|
43
|
-
badge: '
|
|
44
|
-
color: '
|
|
45
|
-
label: '',
|
|
43
|
+
badge: '🟣',
|
|
44
|
+
color: 'magenta',
|
|
45
|
+
label: 'option',
|
|
46
46
|
logLevel: 'info',
|
|
47
47
|
},
|
|
48
48
|
};
|
|
@@ -106,6 +106,33 @@ const scopes = {
|
|
|
106
106
|
types: methods,
|
|
107
107
|
}),
|
|
108
108
|
},
|
|
109
|
+
platform: {
|
|
110
|
+
...global.scope('Vulcan', 'Platform'),
|
|
111
|
+
interactive: getLogger({
|
|
112
|
+
interactive: true,
|
|
113
|
+
scope: ['Vulcan', 'Platform'],
|
|
114
|
+
types: methods,
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
statics: {
|
|
118
|
+
...global.scope('Vulcan', 'Storage'),
|
|
119
|
+
interactive: getLogger({
|
|
120
|
+
interactive: true,
|
|
121
|
+
scope: ['Vulcan', 'storage'],
|
|
122
|
+
types: methods,
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
125
|
+
logs: (scope1, scope2, scope3) => ({
|
|
126
|
+
...global.scope('Azion', `${scope1}`, scope2, scope3),
|
|
127
|
+
}),
|
|
128
|
+
propagation: {
|
|
129
|
+
...global.scope('Azion', 'Edge Network'),
|
|
130
|
+
interactive: getLogger({
|
|
131
|
+
interactive: true,
|
|
132
|
+
scope: ['Vulcan', 'Azion Network'],
|
|
133
|
+
types: methods,
|
|
134
|
+
}),
|
|
135
|
+
},
|
|
109
136
|
};
|
|
110
137
|
|
|
111
138
|
/**
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { writeFileSync,
|
|
1
|
+
import { existsSync, writeFileSync, readFileSync, mkdirSync, rm } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import Ajv from 'ajv';
|
|
4
4
|
import ajvErrors from 'ajv-errors';
|
|
5
5
|
import addKeywords from 'ajv-keywords';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import lodash from 'lodash';
|
|
6
8
|
|
|
7
9
|
import azionConfigSchema from './fixtures/schema.js';
|
|
10
|
+
import debug from '../debug/debug.utils.js';
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* Validates the provided configuration against a JSON Schema.
|
|
10
14
|
* This function uses AJV (Another JSON Schema Validator) to validate the configuration.
|
|
@@ -249,44 +253,34 @@ function processManifestConfig(config) {
|
|
|
249
253
|
}
|
|
250
254
|
|
|
251
255
|
/**
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* If the file does not exist, the function will attempt to use the provided configuration module.
|
|
255
|
-
* If no module is provided, a minimal default configuration is returned.
|
|
256
|
-
* @param {string} configPath - The path to the custom configuration file.
|
|
257
|
-
* @param {object} configModule - An alternative configuration module provided as a fallback.
|
|
258
|
-
* @returns {Promise<object>} A promise that resolves to the loaded configuration object.
|
|
256
|
+
* Removes the temporary folder used to store the manifest file.
|
|
257
|
+
* This function is typically called after the manifest is generated and copied to the edge directory.
|
|
259
258
|
*/
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
259
|
+
function removeTmpFolder() {
|
|
260
|
+
const manifestPath = globalThis.vulcan.tmpManifestFile;
|
|
261
|
+
if (manifestPath) {
|
|
262
|
+
const dirName = manifestPath.substring(0, manifestPath.lastIndexOf('/'));
|
|
263
|
+
rm(dirName, { recursive: true }, (err) => {
|
|
264
|
+
if (err) {
|
|
265
|
+
debug.error(err);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
269
268
|
}
|
|
270
|
-
|
|
271
|
-
rules: {
|
|
272
|
-
request: [{}], // minimal configuration
|
|
273
|
-
},
|
|
274
|
-
};
|
|
269
|
+
globalThis.vulcan.tmpManifestFile = null;
|
|
275
270
|
}
|
|
276
271
|
|
|
277
272
|
/**
|
|
278
|
-
*
|
|
279
|
-
* It checks the 'type' key in the 'package.json' file at the project root.
|
|
280
|
-
* If 'type' is 'commonjs' or absent, returns true. Otherwise, returns false.
|
|
281
|
-
* @returns {boolean} True if the project uses CommonJS, false if it uses ES Modules.
|
|
273
|
+
* Create the final manifest file to the edge directory.
|
|
282
274
|
*/
|
|
283
|
-
function
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
275
|
+
async function generateFinalManifest() {
|
|
276
|
+
const manifestPath = globalThis.vulcan.tmpManifestFile;
|
|
277
|
+
const finalManifestPath = join(process.cwd(), '.edge', 'manifest.json');
|
|
278
|
+
if (existsSync(manifestPath)) {
|
|
279
|
+
writeFileSync(finalManifestPath, readFileSync(manifestPath));
|
|
280
|
+
removeTmpFolder();
|
|
281
|
+
} else {
|
|
282
|
+
throw new Error('Manifest file not found');
|
|
288
283
|
}
|
|
289
|
-
return true; // Default to CommonJS if 'package.json' does not exist or 'type' key is absent
|
|
290
284
|
}
|
|
291
285
|
|
|
292
286
|
/**
|
|
@@ -294,31 +288,64 @@ function useCommonJS() {
|
|
|
294
288
|
* If an existing manifest is found, it merges the configurations, prioritizing the custom module.
|
|
295
289
|
* This function is typically called during the prebuild stage to prepare the CDN configuration.
|
|
296
290
|
* @param {object} configModule - The custom configuration module provided by the user.
|
|
291
|
+
* @param {boolean} shouldGenerateFinalManifest - A flag indicating whether the final manifest should be generated after the temporary manifest is created.
|
|
297
292
|
* @async
|
|
298
293
|
*/
|
|
299
|
-
async function generateManifest(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
async function generateManifest(
|
|
295
|
+
configModule,
|
|
296
|
+
shouldGenerateFinalManifest = false,
|
|
297
|
+
) {
|
|
298
|
+
const edgeDirPath = join(process.cwd(), '.edge');
|
|
299
|
+
const tmpDirPath = join(os.tmpdir(), 'vulcan');
|
|
300
|
+
|
|
301
|
+
if (!existsSync(tmpDirPath)) {
|
|
302
|
+
mkdirSync(tmpDirPath);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let manifestPath = globalThis.vulcan.tmpManifestFile;
|
|
306
|
+
if (!manifestPath) {
|
|
307
|
+
manifestPath = join(tmpDirPath, `manifest-${new Date().getTime()}.json`);
|
|
308
|
+
globalThis.vulcan.tmpManifestFile = manifestPath;
|
|
309
|
+
}
|
|
303
310
|
|
|
304
|
-
|
|
305
|
-
|
|
311
|
+
// preset configuration (existingManifest) have priority over user azion.config.js
|
|
312
|
+
let existingManifest = {};
|
|
313
|
+
|
|
314
|
+
if (!existsSync(edgeDirPath)) {
|
|
315
|
+
mkdirSync(edgeDirPath);
|
|
306
316
|
}
|
|
307
317
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (!existsSync(configPath)) {
|
|
312
|
-
const moduleExportStyle = useCommonJS()
|
|
313
|
-
? 'module.exports ='
|
|
314
|
-
: 'export default';
|
|
315
|
-
writeFileSync(
|
|
316
|
-
configPath,
|
|
317
|
-
`${moduleExportStyle} ${JSON.stringify(AzionConfig, null, 2)};`,
|
|
318
|
-
);
|
|
318
|
+
if (existsSync(manifestPath)) {
|
|
319
|
+
const existingManifestRaw = readFileSync(manifestPath, 'utf8');
|
|
320
|
+
existingManifest = JSON.parse(existingManifestRaw);
|
|
319
321
|
}
|
|
320
322
|
|
|
321
|
-
|
|
323
|
+
const newManifestConfig = processManifestConfig(configModule);
|
|
324
|
+
|
|
325
|
+
// eslint-disable-next-line
|
|
326
|
+
function customizer(objValue, srcValue) {
|
|
327
|
+
if (Array.isArray(objValue)) {
|
|
328
|
+
return objValue.concat(
|
|
329
|
+
srcValue.filter(
|
|
330
|
+
(srcItem) =>
|
|
331
|
+
!objValue.some((objItem) => objItem?.name === srcItem?.name),
|
|
332
|
+
),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Merge the new configuration with the existing manifest with priority to the existing manifest
|
|
338
|
+
const mergeManifest = lodash.mergeWith(
|
|
339
|
+
existingManifest,
|
|
340
|
+
newManifestConfig,
|
|
341
|
+
customizer,
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
writeFileSync(manifestPath, JSON.stringify(mergeManifest, null, 2));
|
|
345
|
+
|
|
346
|
+
if (shouldGenerateFinalManifest) {
|
|
347
|
+
await generateFinalManifest();
|
|
348
|
+
}
|
|
322
349
|
}
|
|
323
350
|
|
|
324
351
|
export { processManifestConfig, generateManifest };
|
|
@@ -1,7 +1,113 @@
|
|
|
1
1
|
import { describe, expect } from '@jest/globals';
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import mockFs from 'mock-fs';
|
|
4
|
+
import {
|
|
5
|
+
generateManifest,
|
|
6
|
+
processManifestConfig,
|
|
7
|
+
} from './generateManifest.utils.js';
|
|
3
8
|
|
|
4
9
|
describe('Utils - generateManifest', () => {
|
|
10
|
+
it('should correctly merge config when generateManifest is called multiple times', async () => {
|
|
11
|
+
globalThis.vulcan = {};
|
|
12
|
+
const presetConfig = {
|
|
13
|
+
rules: {
|
|
14
|
+
request: [
|
|
15
|
+
{
|
|
16
|
+
name: 'Main_Rule',
|
|
17
|
+
match: '^\\/',
|
|
18
|
+
runFunction: {
|
|
19
|
+
path: '.edge/worker.js',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const azionConfig = {
|
|
26
|
+
origin: [
|
|
27
|
+
{
|
|
28
|
+
name: 'my origin storage',
|
|
29
|
+
type: 'object_storage',
|
|
30
|
+
bucket: 'mybucket',
|
|
31
|
+
prefix: 'myfolder',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
rules: {
|
|
35
|
+
request: [
|
|
36
|
+
{
|
|
37
|
+
name: 'my-rule-origin',
|
|
38
|
+
match: '/^/_statics/;',
|
|
39
|
+
setOrigin: {
|
|
40
|
+
name: 'my origin storage',
|
|
41
|
+
type: 'object_storage',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
mockFs({
|
|
48
|
+
'.edge/manifest.json': '{}',
|
|
49
|
+
});
|
|
50
|
+
await generateManifest(presetConfig);
|
|
51
|
+
await generateManifest(azionConfig, true);
|
|
52
|
+
const manifest = readFileSync('.edge/manifest.json', 'utf8');
|
|
53
|
+
mockFs.restore();
|
|
54
|
+
expect(JSON.parse(manifest)).toEqual(
|
|
55
|
+
expect.objectContaining({
|
|
56
|
+
origin: expect.arrayContaining([
|
|
57
|
+
{
|
|
58
|
+
name: 'my origin storage',
|
|
59
|
+
origin_type: 'object_storage',
|
|
60
|
+
bucket: 'mybucket',
|
|
61
|
+
prefix: 'myfolder',
|
|
62
|
+
},
|
|
63
|
+
]),
|
|
64
|
+
rules: expect.arrayContaining([
|
|
65
|
+
{
|
|
66
|
+
name: 'my-rule-origin',
|
|
67
|
+
criteria: [
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
71
|
+
variable: '${uri}',
|
|
72
|
+
operator: 'matches',
|
|
73
|
+
conditional: 'if',
|
|
74
|
+
input_value: '/^/_statics/;',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
],
|
|
78
|
+
behaviors: [
|
|
79
|
+
{
|
|
80
|
+
name: 'set_origin',
|
|
81
|
+
target: 'my origin storage',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Main_Rule',
|
|
87
|
+
criteria: [
|
|
88
|
+
[
|
|
89
|
+
{
|
|
90
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
91
|
+
variable: '${uri}',
|
|
92
|
+
operator: 'matches',
|
|
93
|
+
conditional: 'if',
|
|
94
|
+
input_value: '^\\/',
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
],
|
|
98
|
+
behaviors: [
|
|
99
|
+
{
|
|
100
|
+
name: 'run_function',
|
|
101
|
+
target: '.edge/worker.js',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
]),
|
|
106
|
+
cache: [],
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
5
111
|
describe('processManifestConfig', () => {
|
|
6
112
|
it('should throw an error for invalid mathematical expressions', () => {
|
|
7
113
|
const azionConfig = {
|
|
@@ -67,19 +173,10 @@ describe('Utils - generateManifest', () => {
|
|
|
67
173
|
const result = processManifestConfig(azionConfig);
|
|
68
174
|
expect(result.rules[0].behaviors).toEqual(
|
|
69
175
|
expect.arrayContaining([
|
|
70
|
-
expect.objectContaining(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
captured_array: 'other',
|
|
75
|
-
regex: '^(./)([^/])$',
|
|
76
|
-
// eslint-disable-next-line no-template-curly-in-string
|
|
77
|
-
subject: '${uri}',
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
// eslint-disable-next-line no-template-curly-in-string
|
|
81
|
-
{ name: 'rewrite_request', target: '/${other[0]}/${other[1]}' },
|
|
82
|
-
),
|
|
176
|
+
expect.objectContaining({
|
|
177
|
+
name: 'rewrite_request',
|
|
178
|
+
target: expect.stringContaining('/%{other[0]}/%{other[1]}'), // Updated from 'params' to 'target'
|
|
179
|
+
}),
|
|
83
180
|
]),
|
|
84
181
|
);
|
|
85
182
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edge-functions",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.7.0
|
|
4
|
+
"version": "2.7.0",
|
|
5
5
|
"description": "Tool to launch and build JavaScript/Frameworks. This tool automates polyfills for Edge Computing and assists in creating Workers, notably for the Azion platform.",
|
|
6
6
|
"main": "lib/main.js",
|
|
7
7
|
"bin": {
|