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 CHANGED
@@ -1,4 +1,4 @@
1
- ## [2.7.0-stage.1](https://github.com/aziontech/vulcan/compare/v2.6.2...v2.7.0-stage.1) (2024-05-02)
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/02/24 02:51:54 AM
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('Checking Azion configuration file...');
346
+ feedback.build.info(
347
+ 'Checking Azion Edge Application configuration file...',
348
+ );
347
349
  const buildConfigPath = join(process.cwd(), 'azion.config.js');
348
- const vulcanCustomConfigModule = (await import(buildConfigPath)).default;
349
- await generateManifest(vulcanCustomConfigModule);
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, { port, firewall }) {
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, parsedPort, firewall);
26
+ server(entryPoint, firewall, parsedPort);
27
27
  }
28
28
 
29
29
  export default devCommand;
@@ -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, port, isFirewall) {
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', '3000')
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
- export { Utils, Build, Env, Presets, Edge, Polyfills, Commands };
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: 'green',
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, existsSync, mkdirSync, readFileSync } from 'fs';
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
- * Loads the Azion deploy configuration from a local file or a provided module.
253
- * If a custom configuration file 'azion.config.js' exists in the root directory, it takes precedence and is loaded.
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
- async function loadAzionConfig(configPath, configModule) {
261
- const existCustomAzionConfig = existsSync(configPath); // user created azion.config.js in root directory
262
-
263
- // the file created has priorty over preset
264
- if (existCustomAzionConfig) {
265
- return (await import(configPath)).default;
266
- }
267
- if (!existCustomAzionConfig && configModule) {
268
- return configModule;
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
- return {
271
- rules: {
272
- request: [{}], // minimal configuration
273
- },
274
- };
269
+ globalThis.vulcan.tmpManifestFile = null;
275
270
  }
276
271
 
277
272
  /**
278
- * Determines if the project uses the CommonJS module system by default.
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 useCommonJS() {
284
- const packageJsonPath = join(process.cwd(), 'package.json');
285
- if (existsSync(packageJsonPath)) {
286
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
287
- return packageJson.type !== 'module'; // Returns true for 'commonjs' or no 'type' specified
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(configModule) {
300
- const configPath = join(process.cwd(), 'azion.config.js');
301
- const dotEdgeDir = join(process.cwd(), '.edge');
302
- const finalManifestPath = join(dotEdgeDir, 'manifest.json');
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
- if (!existsSync(dotEdgeDir)) {
305
- mkdirSync(dotEdgeDir);
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
- const AzionConfig = await loadAzionConfig(configPath, configModule);
309
- const manifest = processManifestConfig(AzionConfig);
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
- writeFileSync(finalManifestPath, JSON.stringify(manifest, null, 2));
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 { processManifestConfig } from './generateManifest.utils.js';
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
- name: 'capture_match_groups',
73
- target: {
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-stage.1",
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": {