edge-functions 1.3.0 → 1.5.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/.eslintrc.json +4 -0
- package/aliases.js +1 -0
- package/examples/vue-static/yarn.lock +13094 -0
- package/examples/vue-vite-static/yarn.lock +333 -0
- package/jsconfig.json +3 -0
- package/lib/build/dispatcher/dispatcher.js +30 -21
- package/lib/commands/auth.commands.js +85 -0
- package/lib/commands/build.commands.js +47 -0
- package/lib/commands/deploy.commands.js +45 -0
- package/lib/commands/dev.commands.js +26 -0
- package/lib/commands/index.js +13 -0
- package/lib/commands/init.commands.js +61 -0
- package/lib/commands/logs.commands.js +34 -0
- package/lib/commands/presets.commands.js +97 -0
- package/lib/commands/storage.commands.js +22 -0
- package/lib/constants/framework-initializer.constants.js +2 -2
- package/lib/constants/messages/build.messages.js +1 -0
- package/lib/env/polyfills/fetch.polyfills.js +10 -10
- package/lib/env/runtime.env.js +1 -1
- package/lib/env/server.env.js +101 -23
- package/lib/env/vulcan.env.js +43 -21
- package/lib/main.js +36 -261
- package/lib/platform/actions/core/auth.actions.js +3 -3
- package/lib/platform/services/base.service.js +1 -2
- package/lib/presets/custom/next/deliver/prebuild.js +4 -1
- package/lib/presets/custom/vue/deliver/prebuild.js +2 -5
- package/lib/utils/getUrlFromResource/getUrlFromResource.utils.js +16 -0
- package/lib/utils/getUrlFromResource/index.js +3 -0
- package/lib/utils/index.js +2 -0
- package/package.json +4 -3
- package/releaserc.json +1 -0
- package/lib/polyfills/FetchEvent.polyfills.js +0 -13
- package/lib/polyfills/fetch.polyfills.js +0 -39
- package/lib/polyfills/index.js +0 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import authCommand from './auth.commands.js';
|
|
2
|
+
import buildCommand from './build.commands.js';
|
|
3
|
+
import deployCommand from './deploy.commands.js';
|
|
4
|
+
import devCommand from './dev.commands.js';
|
|
5
|
+
import initCommand from './init.commands.js';
|
|
6
|
+
import logsCommand from './logs.commands.js';
|
|
7
|
+
import presetsCommand from './presets.commands.js';
|
|
8
|
+
import storageCommand from './storage.commands.js';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
authCommand, buildCommand, deployCommand, devCommand,
|
|
12
|
+
initCommand, logsCommand, presetsCommand, storageCommand,
|
|
13
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createPromptModule } from 'inquirer';
|
|
2
|
+
import { FrameworkInitializer, Messages } from '#constants';
|
|
3
|
+
import { feedback } from '#utils';
|
|
4
|
+
import { vulcan } from '#env';
|
|
5
|
+
|
|
6
|
+
const prompt = createPromptModule();
|
|
7
|
+
/**
|
|
8
|
+
* A command to Initializes a new project with the selected framework template.
|
|
9
|
+
* @memberof commands
|
|
10
|
+
* This function prompts the user to select a framework template and enter a project name.
|
|
11
|
+
* Then it initializes a new project based on the selected template.
|
|
12
|
+
* @param {object} options - An object containing the name for the new project.
|
|
13
|
+
* @param {string} options.name - The name of the new project.
|
|
14
|
+
* If not provided, the function will prompt for it.
|
|
15
|
+
* @returns {Promise<void>} - A promise that resolves when the new project is initialized.
|
|
16
|
+
* @example
|
|
17
|
+
*
|
|
18
|
+
* initCommand({ name: 'my_new_project' });
|
|
19
|
+
*/
|
|
20
|
+
async function initComamnd({ name }) {
|
|
21
|
+
const AVALIABLE_TEMPLATES = Object.keys(FrameworkInitializer);
|
|
22
|
+
let projectName = name;
|
|
23
|
+
|
|
24
|
+
const { frameworkChoice } = await prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'list',
|
|
27
|
+
name: 'frameworkChoice',
|
|
28
|
+
message: 'Choose a template for your project:',
|
|
29
|
+
choices: AVALIABLE_TEMPLATES,
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
while (!projectName) {
|
|
34
|
+
// eslint-disable-next-line no-await-in-loop
|
|
35
|
+
const { projectName: inputName } = await prompt([
|
|
36
|
+
{
|
|
37
|
+
type: 'input',
|
|
38
|
+
name: 'projectName',
|
|
39
|
+
message: 'Enter your project name:',
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
if (inputName) {
|
|
44
|
+
projectName = inputName;
|
|
45
|
+
}
|
|
46
|
+
if (!inputName) {
|
|
47
|
+
feedback.pending(Messages.info.name_required);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const createFrameworkTemplate = FrameworkInitializer[frameworkChoice];
|
|
52
|
+
|
|
53
|
+
if (createFrameworkTemplate) {
|
|
54
|
+
process.env.VULCAN_CURRENT_PRESET = projectName; // for Azion CLI in Golang(temp)
|
|
55
|
+
await createFrameworkTemplate(projectName);
|
|
56
|
+
} else {
|
|
57
|
+
feedback.error(Messages.errors.invalid_choice);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default initComamnd;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { feedback } from '#utils';
|
|
2
|
+
import { Messages } from '#constants';
|
|
3
|
+
/**
|
|
4
|
+
* A comamnd to display logs for a specified function or application.
|
|
5
|
+
* @memberof commands
|
|
6
|
+
* This function allows the user to view logs for a specific function or application.
|
|
7
|
+
* Note that viewing logs for applications is currently unsupported.
|
|
8
|
+
* @param {string} type - The type of entity to show logs for.
|
|
9
|
+
* Accepted values are 'function' and 'application'.
|
|
10
|
+
* @param {string} id - The identifier for the function or application.
|
|
11
|
+
* @param {object} options - Additional options for fetching logs.
|
|
12
|
+
* @param {boolean} options.watch - If true, keep watching the logs and updating in real-time.
|
|
13
|
+
* @returns {Promise<void>} - A promise that resolves when logs are fetched and displayed.
|
|
14
|
+
* @example
|
|
15
|
+
*
|
|
16
|
+
* logsCommand('function', 'functionId123', { watch: true });
|
|
17
|
+
*/
|
|
18
|
+
async function logsCommand(type, id, { watch }) {
|
|
19
|
+
const { functions } = await import('#platform');
|
|
20
|
+
|
|
21
|
+
if (!['function', 'application'].includes(type)) {
|
|
22
|
+
feedback.error(Messages.platform.logs.errors.invalid_log_type);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (type === 'function') {
|
|
27
|
+
functions.actions.showFunctionLogs(id, watch);
|
|
28
|
+
}
|
|
29
|
+
if (type === 'application') {
|
|
30
|
+
feedback.info(Messages.platform.logs.info.unsupported_log_type);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default logsCommand;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createPromptModule } from 'inquirer';
|
|
2
|
+
import { Messages } from '#constants';
|
|
3
|
+
import { feedback, debug } from '#utils';
|
|
4
|
+
|
|
5
|
+
const prompt = createPromptModule();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manages presets for the application.
|
|
9
|
+
* @memberof commands
|
|
10
|
+
* This command allows the user to create or list presets.
|
|
11
|
+
* The user is guided by a series of prompts to enter a preset name and mode.
|
|
12
|
+
* @param {string} command - The operation to be performed:
|
|
13
|
+
* 'create' to create a preset, 'ls' to list presets.
|
|
14
|
+
* @returns {Promise<void>} - A promise that resolves when the action is complete.
|
|
15
|
+
* @example
|
|
16
|
+
*
|
|
17
|
+
* // To create a new preset
|
|
18
|
+
* presetsCommand('create');
|
|
19
|
+
*
|
|
20
|
+
* // To list existing presets
|
|
21
|
+
* presetsCommand('ls');
|
|
22
|
+
*/
|
|
23
|
+
async function presetsCommand(command) {
|
|
24
|
+
const { presets } = await import('#utils');
|
|
25
|
+
|
|
26
|
+
let name;
|
|
27
|
+
let mode;
|
|
28
|
+
|
|
29
|
+
switch (command) {
|
|
30
|
+
case 'create':
|
|
31
|
+
// eslint-disable-next-line no-constant-condition
|
|
32
|
+
while (true) {
|
|
33
|
+
// eslint-disable-next-line no-await-in-loop
|
|
34
|
+
const { inputPresetName } = await prompt([
|
|
35
|
+
{
|
|
36
|
+
type: 'input',
|
|
37
|
+
name: 'inputPresetName',
|
|
38
|
+
message: 'Enter the preset name:',
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const presetExists = presets
|
|
43
|
+
.getKeys()
|
|
44
|
+
.map((existingPresetName) => existingPresetName.toLowerCase())
|
|
45
|
+
.includes(inputPresetName.toLowerCase());
|
|
46
|
+
|
|
47
|
+
if (presetExists) {
|
|
48
|
+
feedback.error('A preset with this name already exists.');
|
|
49
|
+
} else if (!inputPresetName) {
|
|
50
|
+
feedback.error('Preset name cannot be empty.');
|
|
51
|
+
} else {
|
|
52
|
+
name = inputPresetName;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line no-constant-condition
|
|
58
|
+
while (true) {
|
|
59
|
+
// eslint-disable-next-line no-await-in-loop
|
|
60
|
+
const { inputMode } = await prompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'list',
|
|
63
|
+
name: 'inputMode',
|
|
64
|
+
message: 'Choose the mode:',
|
|
65
|
+
choices: ['compute', 'deliver'],
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
if (['compute', 'deliver'].includes(inputMode)) {
|
|
70
|
+
mode = inputMode;
|
|
71
|
+
break;
|
|
72
|
+
} else {
|
|
73
|
+
feedback.error('Invalid mode. Choose either "compute" or "deliver".');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
presets.set(name, mode);
|
|
79
|
+
feedback.success(`${name}(${mode}) created with success!`);
|
|
80
|
+
feedback.info(`Now open './lib/presets/${name}/${mode}' and work on your preset.`);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
debug.error(error);
|
|
83
|
+
feedback.error(Messages.errors.folder_creation_failed(name));
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case 'ls':
|
|
88
|
+
presets.getBeautify().forEach((preset) => feedback.option(preset));
|
|
89
|
+
break;
|
|
90
|
+
|
|
91
|
+
default:
|
|
92
|
+
feedback.error('Invalid argument provided.');
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default presetsCommand;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A command to uploads static files for a given version of the application.
|
|
5
|
+
* @memberof commands
|
|
6
|
+
* The function identifies the build version, prepares a base path for static files,
|
|
7
|
+
* and uploads these files to the storage of the core platform.
|
|
8
|
+
* @returns {Promise<void>} - A promise that resolves when static files are successfully uploaded.
|
|
9
|
+
* @example
|
|
10
|
+
*
|
|
11
|
+
* storageCommand();
|
|
12
|
+
*/
|
|
13
|
+
async function storageCommand() {
|
|
14
|
+
const { core } = await import('#platform');
|
|
15
|
+
const { getVulcanBuildId } = await import('#utils');
|
|
16
|
+
|
|
17
|
+
const versionId = getVulcanBuildId();
|
|
18
|
+
const basePath = join(process.cwd(), '.edge/storage/');
|
|
19
|
+
await core.actions.uploadStatics(versionId, basePath);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default storageCommand;
|
|
@@ -26,7 +26,7 @@ import { exec } from '#utils';
|
|
|
26
26
|
|
|
27
27
|
const FrameworkInitializer = {
|
|
28
28
|
Angular: async (projectName) => {
|
|
29
|
-
await exec(`npx
|
|
29
|
+
await exec(`npx @angular/cli new ${projectName}`, 'Angular', false, true);
|
|
30
30
|
},
|
|
31
31
|
Astro: async (projectName) => {
|
|
32
32
|
await exec(`npx create-astro ${projectName}`, 'Astro', false, true);
|
|
@@ -41,7 +41,7 @@ const FrameworkInitializer = {
|
|
|
41
41
|
await exec(`npx create-react-app ${projectName}`, 'React', false, true);
|
|
42
42
|
},
|
|
43
43
|
Vue: async (projectName) => {
|
|
44
|
-
await exec(`npx vue create ${projectName}`, 'Vue', false, true);
|
|
44
|
+
await exec(`npx @vue/cli create ${projectName}`, 'Vue', false, true);
|
|
45
45
|
},
|
|
46
46
|
Vite: async (projectName) => {
|
|
47
47
|
await exec(`npx create-vue ${projectName}`, 'Vue/Vite', false, true);
|
|
@@ -2,6 +2,7 @@ import { join } from 'path';
|
|
|
2
2
|
import { readFileSync } from 'fs';
|
|
3
3
|
import mime from 'mime-types';
|
|
4
4
|
import { EdgeRuntime } from 'edge-runtime';
|
|
5
|
+
import { getUrlFromResource, getVulcanBuildId } from '#utils';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* A custom fetch implementation that adds an additional path to the URL if it starts with 'file://'.
|
|
@@ -9,19 +10,18 @@ import { EdgeRuntime } from 'edge-runtime';
|
|
|
9
10
|
* it behaves as if the request is made from within the edge itself. In this case, an additional
|
|
10
11
|
* '.edge/storage' folder is appended to the URL to represent the edge environment.
|
|
11
12
|
* @param {EdgeRuntime} context - VMContext
|
|
12
|
-
* @param {URL}
|
|
13
|
+
* @param {URL|Request|string} resource - The resource to fetch.
|
|
13
14
|
* @param {object} [options] - The fetch options.
|
|
14
15
|
* @returns {Promise<Response>} A Promise that resolves to the Response object.
|
|
15
16
|
*/
|
|
16
|
-
async function fetchPolyfill(context,
|
|
17
|
-
const {
|
|
18
|
-
URL, Headers, Response,
|
|
19
|
-
} = context;
|
|
17
|
+
async function fetchPolyfill(context, resource, options) {
|
|
18
|
+
const { Headers, Response } = context;
|
|
20
19
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
20
|
+
const urlObj = getUrlFromResource(resource);
|
|
21
|
+
|
|
22
|
+
if (urlObj.href.startsWith('file://')) {
|
|
23
|
+
const versionId = getVulcanBuildId();
|
|
24
|
+
const file = urlObj.pathname.replace(`/${versionId}`, '');
|
|
25
25
|
const filePath = join(process.cwd(), '.edge', 'storage', file);
|
|
26
26
|
const fileContent = readFileSync(filePath);
|
|
27
27
|
const contentType = mime.lookup(filePath) || 'application/octet-stream';
|
|
@@ -33,7 +33,7 @@ async function fetchPolyfill(context, url, options) {
|
|
|
33
33
|
return response;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
return fetch(
|
|
36
|
+
return fetch(resource, options);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export default fetchPolyfill;
|
package/lib/env/runtime.env.js
CHANGED
|
@@ -36,7 +36,7 @@ import { fetchPolyfill, FetchEventPolyfill } from './polyfills/index.js';
|
|
|
36
36
|
*/
|
|
37
37
|
function runtime(code) {
|
|
38
38
|
const extend = (context) => {
|
|
39
|
-
context.fetch = (
|
|
39
|
+
context.fetch = (resource, options) => fetchPolyfill(context, resource, options);
|
|
40
40
|
context.FetchEvent = FetchEventPolyfill;
|
|
41
41
|
context.FirewallEvent = {}; // TODO: Firewall Event
|
|
42
42
|
/*
|
package/lib/env/server.env.js
CHANGED
|
@@ -1,46 +1,124 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
debug, readWorkerFile, feedback, exec,
|
|
3
|
+
} from '#utils';
|
|
2
4
|
import { Messages } from '#constants';
|
|
3
|
-
import
|
|
5
|
+
import edgeRuntimePackage from 'edge-runtime';
|
|
6
|
+
import chokidar from 'chokidar';
|
|
4
7
|
import runtime from './runtime.env.js';
|
|
8
|
+
import vulcan from './vulcan.env.js';
|
|
9
|
+
|
|
10
|
+
const { runServer, EdgeRuntimeServer } = edgeRuntimePackage;
|
|
11
|
+
|
|
12
|
+
let currentServer;
|
|
13
|
+
let isChangeHandlerRunning = false;
|
|
5
14
|
|
|
6
15
|
/**
|
|
7
|
-
* Read the worker code from
|
|
8
|
-
* @param {string} workerPath -
|
|
9
|
-
* @returns {Promise<string>}
|
|
16
|
+
* Read the worker code from a specified path.
|
|
17
|
+
* @param {string} workerPath - Path to the worker file.
|
|
18
|
+
* @returns {Promise<string>} - The worker code.
|
|
19
|
+
* @throws {Error} - If unable to read the worker file.
|
|
10
20
|
*/
|
|
11
21
|
async function readWorkerCode(workerPath) {
|
|
12
22
|
try {
|
|
13
|
-
|
|
14
|
-
return worker;
|
|
23
|
+
return await readWorkerFile(workerPath);
|
|
15
24
|
} catch (error) {
|
|
16
25
|
debug.error(error);
|
|
17
|
-
feedback.server.error(
|
|
18
|
-
Messages.env.server.errors.load_worker_failed(workerPath),
|
|
19
|
-
);
|
|
26
|
+
feedback.server.error(Messages.env.server.errors.load_worker_failed(workerPath));
|
|
20
27
|
throw error;
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
/**
|
|
25
|
-
*
|
|
26
|
-
* @param {
|
|
27
|
-
* @param {
|
|
32
|
+
* Initialize and run the server with the given port and worker code.
|
|
33
|
+
* @param {number} port - The port number.
|
|
34
|
+
* @param {string} workerCode - The worker code.
|
|
35
|
+
* @returns {Promise<EdgeRuntimeServer>} - The initialized server.
|
|
28
36
|
*/
|
|
29
|
-
async function
|
|
37
|
+
async function initializeServer(port, workerCode) {
|
|
38
|
+
const execution = runtime(workerCode);
|
|
39
|
+
return runServer({ port, host: 'localhost', runtime: execution });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Handle server operations: start, restart.
|
|
44
|
+
* @param {string} workerPath - Path to the worker file.
|
|
45
|
+
* @param {number} port - The port number.
|
|
46
|
+
*/
|
|
47
|
+
async function manageServer(workerPath, port) {
|
|
30
48
|
try {
|
|
31
49
|
const workerCode = await readWorkerCode(workerPath);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Messages.env.server.success.server_running(
|
|
40
|
-
)
|
|
50
|
+
|
|
51
|
+
if (currentServer) {
|
|
52
|
+
await currentServer.close();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
currentServer = await initializeServer(port, workerCode);
|
|
57
|
+
feedback.server.success(Messages.env.server.success.server_running(`http://localhost:${port}`));
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error.code === 'EADDRINUSE') {
|
|
60
|
+
await manageServer(workerPath, port + 1);
|
|
61
|
+
} else {
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
41
65
|
} catch (error) {
|
|
42
66
|
debug.error(error);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Handle file changes and prevent concurrent execution.
|
|
73
|
+
* @param {string} path - Path of the changed file.
|
|
74
|
+
* @param {string} workerPath - Path to the worker file.
|
|
75
|
+
* @param {number} port - The port number.
|
|
76
|
+
*/
|
|
77
|
+
async function handleFileChange(path, workerPath, port) {
|
|
78
|
+
if (isChangeHandlerRunning) return;
|
|
79
|
+
|
|
80
|
+
isChangeHandlerRunning = true;
|
|
81
|
+
|
|
82
|
+
if (path.startsWith('vulcan') || path.startsWith('.edge') || path.startsWith('node_modules/.cache')) {
|
|
83
|
+
isChangeHandlerRunning = false;
|
|
84
|
+
return;
|
|
43
85
|
}
|
|
86
|
+
|
|
87
|
+
const {
|
|
88
|
+
entry, preset, mode, useNodePolyfills,
|
|
89
|
+
} = await vulcan.readVulcanEnv('local');
|
|
90
|
+
|
|
91
|
+
feedback.build.info(Messages.build.info.rebuilding);
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await exec(`vulcan build --entry ${entry} --preset ${preset} --mode ${mode} --useNodePolyfills ${useNodePolyfills}`);
|
|
95
|
+
await manageServer(workerPath, port);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
debug.error(`Build or server restart failed: ${error}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
isChangeHandlerRunning = false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Entry point function to start the server and watch for file changes.
|
|
105
|
+
* @param {string} workerPath - Path to the worker file.
|
|
106
|
+
* @param {number} port - The port number.
|
|
107
|
+
*/
|
|
108
|
+
async function startServer(workerPath, port) {
|
|
109
|
+
await manageServer(workerPath, port); // Initialize the server for the first time
|
|
110
|
+
|
|
111
|
+
const watcher = chokidar.watch('./', {
|
|
112
|
+
persistent: true,
|
|
113
|
+
ignoreInitial: false,
|
|
114
|
+
depth: 99,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
watcher.on('change', async (path) => {
|
|
118
|
+
await handleFileChange(path, workerPath, port);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
watcher.on('error', (error) => debug.error(`Watcher error: ${error}`));
|
|
44
122
|
}
|
|
45
123
|
|
|
46
124
|
export default startServer;
|
package/lib/env/vulcan.env.js
CHANGED
|
@@ -4,17 +4,23 @@ import fs from 'fs/promises';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
* @param {
|
|
7
|
+
* Creates or updates Vulcan environment variables, either at the global or project level.
|
|
8
|
+
* @async
|
|
9
|
+
* @param {object} variables - An object containing the environment variables to set.
|
|
10
|
+
* @param {string} [scope='local'] - Determines the scope of the variable ('global' or 'local').
|
|
11
|
+
* @throws {Error} Throws an error if the environment file cannot be read or written.
|
|
12
|
+
* @example
|
|
13
|
+
* // Set multiple global environment variables
|
|
14
|
+
* createVulcanEnv({ API_KEY: 'abc123', ANOTHER_KEY: 'xyz' }, 'global')
|
|
15
|
+
* .catch(error => console.error(error));
|
|
10
16
|
*/
|
|
11
|
-
async function createVulcanEnv(
|
|
12
|
-
const
|
|
13
|
-
const vulcanEnvPath = path.join(
|
|
17
|
+
async function createVulcanEnv(variables, scope = 'global') {
|
|
18
|
+
const basePath = scope === 'global' ? path.join(process.env.HOME, '.azion') : path.join(process.cwd());
|
|
19
|
+
const vulcanEnvPath = path.join(basePath, 'vulcan.env');
|
|
14
20
|
|
|
15
21
|
// Create the .azion folder if it doesn't exist
|
|
16
22
|
try {
|
|
17
|
-
await fs.mkdir(
|
|
23
|
+
await fs.mkdir(basePath, { recursive: true });
|
|
18
24
|
} catch (error) {
|
|
19
25
|
debug.error(error);
|
|
20
26
|
feedback.error(Messages.errors.folder_creation_failed(vulcanEnvPath));
|
|
@@ -26,7 +32,6 @@ async function createVulcanEnv(name, value) {
|
|
|
26
32
|
try {
|
|
27
33
|
envData = await fs.readFile(vulcanEnvPath, 'utf8');
|
|
28
34
|
} catch (error) {
|
|
29
|
-
// Ignore error if the file doesn't exist
|
|
30
35
|
if (error.code !== 'ENOENT') {
|
|
31
36
|
debug.error(error);
|
|
32
37
|
feedback.error(Messages.errors.file_doesnt_exist(vulcanEnvPath));
|
|
@@ -34,15 +39,17 @@ async function createVulcanEnv(name, value) {
|
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
// Update or add
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
// Update or add each variable to the environment data
|
|
43
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
44
|
+
const variableLine = `${key}=${value}`;
|
|
45
|
+
const variableRegex = new RegExp(`${key}=.+`);
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
if (envData.match(variableRegex)) {
|
|
48
|
+
envData = envData.replace(variableRegex, variableLine);
|
|
49
|
+
} else {
|
|
50
|
+
envData += `${variableLine}\n`;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
46
53
|
|
|
47
54
|
// Write the updated environment data to the file
|
|
48
55
|
try {
|
|
@@ -55,12 +62,27 @@ async function createVulcanEnv(name, value) {
|
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
/**
|
|
58
|
-
* Reads the vulcan.env file
|
|
59
|
-
*
|
|
60
|
-
*
|
|
65
|
+
* Reads the vulcan.env file, either at the global or project level,
|
|
66
|
+
* and returns an object with the variables and their values.
|
|
67
|
+
* @param {string} [scope='local'] - Determines the scope of the environment
|
|
68
|
+
* file ('global' or 'local').
|
|
69
|
+
* @returns {Promise<object|null>} A promise that resolves to an object with
|
|
70
|
+
* the variables and their values, or null if the file doesn't exist.
|
|
71
|
+
* @throws {Error} Throws an error if the environment file cannot be read.
|
|
72
|
+
* @example
|
|
73
|
+
* // Read global environment variables
|
|
74
|
+
* readVulcanEnv('global')
|
|
75
|
+
* .then(env => console.log(env))
|
|
76
|
+
* .catch(error => console.error(error));
|
|
77
|
+
*
|
|
78
|
+
* // Read project-level environment variables
|
|
79
|
+
* readVulcanEnv('local')
|
|
80
|
+
* .then(env => console.log(env))
|
|
81
|
+
* .catch(error => console.error(error));
|
|
61
82
|
*/
|
|
62
|
-
async function readVulcanEnv() {
|
|
63
|
-
const
|
|
83
|
+
async function readVulcanEnv(scope = 'global') {
|
|
84
|
+
const basePath = scope === 'global' ? path.join(process.env.HOME, '.azion') : path.join(process.cwd());
|
|
85
|
+
const vulcanEnvPath = path.join(basePath, 'vulcan.env');
|
|
64
86
|
|
|
65
87
|
try {
|
|
66
88
|
// Check if the vulcan.env file exists
|