@extrahorizon/exh-cli 1.10.0-dev-104-c76c2f8 → 1.10.0-dev-106-ff8535b
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/build/commands/data/schemas/init.js +1 -1
- package/build/commands/tasks/createrepo.js +1 -0
- package/build/commands/tasks/sync.d.ts +1 -1
- package/build/commands/tasks/taskConfig.js +25 -36
- package/build/config-json-schemas/TaskConfig.json +131 -0
- package/build/constants.js +2 -25
- package/build/helpers/util.d.ts +1 -0
- package/build/helpers/util.js +8 -1
- package/package.json +1 -1
|
@@ -29,7 +29,7 @@ const handler = async function init({ name, path }) {
|
|
|
29
29
|
exports.handler = handler;
|
|
30
30
|
function createSchema(name) {
|
|
31
31
|
return {
|
|
32
|
-
$schema:
|
|
32
|
+
$schema: `https://swagger.extrahorizon.com/cli/${(0, util_1.getCliVersion)()}/config-json-schemas/Schema.json`,
|
|
33
33
|
name,
|
|
34
34
|
description: `The ${name} schema`,
|
|
35
35
|
createMode: 'allUsers',
|
|
@@ -34,6 +34,7 @@ async function changePackageFile(name) {
|
|
|
34
34
|
}
|
|
35
35
|
try {
|
|
36
36
|
const taskConfig = JSON.parse((await (0, promises_1.readFile)(`${name}/task-config.json`)).toString());
|
|
37
|
+
taskConfig.$schema = `https://swagger.extrahorizon.com/cli/${(0, util_1.getCliVersion)()}/config-json-schemas/TaskConfig.json`;
|
|
37
38
|
taskConfig.name = name;
|
|
38
39
|
taskConfig.description = `${name} task`;
|
|
39
40
|
await (0, promises_1.writeFile)(`${name}/task-config.json`, JSON.stringify(taskConfig, null, 4));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="yargs" />
|
|
2
2
|
export declare const command = "sync";
|
|
3
3
|
export declare const desc = "Sync a task. Will create the task first if it doesn't exist yet";
|
|
4
|
-
export declare const builder: (yargs: any) => import("yargs").Argv<import("yargs").Omit<{}, "description" | "code" | "name" | "path" | "
|
|
4
|
+
export declare const builder: (yargs: any) => import("yargs").Argv<import("yargs").Omit<{}, "description" | "code" | "name" | "path" | "entryPoint" | "runtime" | "env" | "timeLimit" | "memoryLimit" | "executionPermission"> & import("yargs").InferredOptionTypes<{
|
|
5
5
|
path: {
|
|
6
6
|
demandOption: false;
|
|
7
7
|
describe: string;
|
|
@@ -4,33 +4,14 @@ exports.getValidatedConfigIterator = exports.loadSingleConfigFile = exports.vali
|
|
|
4
4
|
const assert_1 = require("assert");
|
|
5
5
|
const fs = require("fs/promises");
|
|
6
6
|
const ospath = require("path");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
7
|
+
const ajv_1 = require("ajv");
|
|
8
|
+
const taskConfigSchema = require("../../config-json-schemas/TaskConfig.json");
|
|
9
9
|
var permissionModes;
|
|
10
10
|
(function (permissionModes) {
|
|
11
11
|
permissionModes["permissionRequired"] = "permissionRequired";
|
|
12
12
|
permissionModes["allUsers"] = "allUsers";
|
|
13
13
|
permissionModes["public"] = "public";
|
|
14
14
|
})(permissionModes = exports.permissionModes || (exports.permissionModes = {}));
|
|
15
|
-
const taskConfigSchema = Joi.object({
|
|
16
|
-
name: Joi.string().pattern(/^[A-Za-z0-9-]+$/).required(),
|
|
17
|
-
description: Joi.string(),
|
|
18
|
-
entryPoint: Joi.string().required(),
|
|
19
|
-
runtime: Joi.string().valid(...constants_1.runtimeChoices).required(),
|
|
20
|
-
timeLimit: Joi.number().min(constants_1.limits.time.min).max(constants_1.limits.time.max),
|
|
21
|
-
memoryLimit: Joi.number().min(constants_1.limits.memory.min).max(constants_1.limits.memory.max),
|
|
22
|
-
path: Joi.string(),
|
|
23
|
-
retryPolicy: Joi.object({
|
|
24
|
-
enabled: Joi.boolean().required(),
|
|
25
|
-
errorsToRetry: Joi.array().items(Joi.string()),
|
|
26
|
-
}),
|
|
27
|
-
environment: Joi.object().pattern(/.*/, Joi.string()),
|
|
28
|
-
executionPermission: Joi.string().valid(...Object.values(permissionModes)),
|
|
29
|
-
executionCredentials: Joi.object({
|
|
30
|
-
email: Joi.string(),
|
|
31
|
-
permissions: Joi.array().items(Joi.string()).required(),
|
|
32
|
-
}),
|
|
33
|
-
});
|
|
34
15
|
function assertExecutionPermission(mode) {
|
|
35
16
|
if (mode !== undefined && !Object.values(permissionModes).includes(mode)) {
|
|
36
17
|
throw new assert_1.AssertionError({ message: `executionPermission incorrect. Should be one of ${Object.values(permissionModes).join(',')}` });
|
|
@@ -70,25 +51,20 @@ function replaceConfigVariables(config) {
|
|
|
70
51
|
return result;
|
|
71
52
|
}
|
|
72
53
|
async function validateConfig(config) {
|
|
54
|
+
const validate = new ajv_1.default().compile(taskConfigSchema);
|
|
55
|
+
const valid = validate(config);
|
|
56
|
+
if (!valid) {
|
|
57
|
+
const errors = getAjvErrorStrings(validate.errors);
|
|
58
|
+
throw new Error(errors[0] || 'Unknown config validation error');
|
|
59
|
+
}
|
|
73
60
|
try {
|
|
74
|
-
|
|
61
|
+
await fs.access(config.path);
|
|
75
62
|
}
|
|
76
63
|
catch (err) {
|
|
77
|
-
throw new Error(
|
|
64
|
+
throw new Error(`Please provide a valid directory path for your code, ${config.path} not found`);
|
|
78
65
|
}
|
|
79
|
-
if (config.path) {
|
|
80
|
-
|
|
81
|
-
await fs.access(config.path);
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
throw new Error(`Please provide a valid directory path for your code, ${config.path} not found`);
|
|
85
|
-
}
|
|
86
|
-
if ((await fs.stat(config.path)).isFile()) {
|
|
87
|
-
throw new Error(`please provide a valid directory path for your code, ${config.path} points to a file`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
throw new Error('Code path not specified');
|
|
66
|
+
if ((await fs.stat(config.path)).isFile()) {
|
|
67
|
+
throw new Error(`please provide a valid directory path for your code, ${config.path} points to a file`);
|
|
92
68
|
}
|
|
93
69
|
if (config.executionCredentials && config.environment) {
|
|
94
70
|
const restrictedProperties = ['API_HOST', 'API_OAUTH_CONSUMER_KEY', 'API_OAUTH_CONSUMER_SECRET', 'API_OAUTH_TOKEN', 'API_OAUTH_TOKEN_SECRET'];
|
|
@@ -178,3 +154,16 @@ async function* getValidatedConfigIterator({ path, name, code, entryPoint, runti
|
|
|
178
154
|
yield taskConfig;
|
|
179
155
|
}
|
|
180
156
|
exports.getValidatedConfigIterator = getValidatedConfigIterator;
|
|
157
|
+
function getAjvErrorStrings(errors) {
|
|
158
|
+
return errors.map(error => {
|
|
159
|
+
let message = '';
|
|
160
|
+
if (error.instancePath) {
|
|
161
|
+
const normalizedPath = error.instancePath
|
|
162
|
+
.replace(/^\//, '')
|
|
163
|
+
.replace(/\//g, '.');
|
|
164
|
+
message += `"${normalizedPath}" `;
|
|
165
|
+
}
|
|
166
|
+
message += error.message || 'has an unknown error';
|
|
167
|
+
return message;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"$schema": {
|
|
6
|
+
"type": "string"
|
|
7
|
+
},
|
|
8
|
+
"name": {
|
|
9
|
+
"description": "The unique identifier amongst all Functions.",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[A-Za-z0-9-]+$"
|
|
12
|
+
},
|
|
13
|
+
"description": {
|
|
14
|
+
"description": "A brief explanation regarding a Function's purpose.",
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"path": {
|
|
18
|
+
"description": "The location of the Function's source code, relative to the folder this configuration file is in. This should be a folder, the code will be zipped and uploaded. Use `./` for the current folder.",
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"entryPoint": {
|
|
22
|
+
"description": "The file and function name to be executed when the Function is invoked. The format is `fileName.functionName`, relative to the `path` property. For example, if the `path` is `./src` and the entry point is `index.handler`, it will look for `./src/index.js` and execute the `handler` function.",
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
"runtime": {
|
|
26
|
+
"description": "The runtime (or environment) the Function will be running in.",
|
|
27
|
+
"type": "string",
|
|
28
|
+
"enum": [
|
|
29
|
+
"nodejs22.x",
|
|
30
|
+
"nodejs20.x",
|
|
31
|
+
"nodejs18.x",
|
|
32
|
+
"nodejs16.x",
|
|
33
|
+
"python3.13",
|
|
34
|
+
"python3.12",
|
|
35
|
+
"python3.11",
|
|
36
|
+
"python3.10",
|
|
37
|
+
"python3.9",
|
|
38
|
+
"python3.8",
|
|
39
|
+
"java21",
|
|
40
|
+
"java17",
|
|
41
|
+
"java11",
|
|
42
|
+
"java8.al2",
|
|
43
|
+
"dotnet9",
|
|
44
|
+
"dotnet8",
|
|
45
|
+
"dotnet7",
|
|
46
|
+
"dotnet6",
|
|
47
|
+
"ruby3.4",
|
|
48
|
+
"ruby3.3",
|
|
49
|
+
"ruby3.2",
|
|
50
|
+
"provided.al2023",
|
|
51
|
+
"provided.al2"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"timeLimit": {
|
|
55
|
+
"description": "The maximum allowed execution time limit for this Function in seconds. It must be between 3 and 300 seconds.",
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"minimum": 3,
|
|
58
|
+
"maximum": 300
|
|
59
|
+
},
|
|
60
|
+
"memoryLimit": {
|
|
61
|
+
"description": "The maximum amount of memory (in MB) that this Function can use. It must be between 128 and 10240.",
|
|
62
|
+
"type": "integer",
|
|
63
|
+
"minimum": 128,
|
|
64
|
+
"maximum": 10240
|
|
65
|
+
},
|
|
66
|
+
"executionPermission": {
|
|
67
|
+
"description": "Defines access for executing the function directly or for invoking it as an API function.",
|
|
68
|
+
"enum": [
|
|
69
|
+
"permissionRequired",
|
|
70
|
+
"allUsers",
|
|
71
|
+
"public"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"environment": {
|
|
75
|
+
"description": "The environment variables added to the Function execution runtime.",
|
|
76
|
+
"type": "object",
|
|
77
|
+
"additionalProperties": {
|
|
78
|
+
"type": "string"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"retryPolicy": {
|
|
82
|
+
"description": "The policy that determines system behavior after the execution of a Function fails.",
|
|
83
|
+
"type": "object",
|
|
84
|
+
"properties": {
|
|
85
|
+
"enabled": {
|
|
86
|
+
"description": "The retry policy is disabled by default, If this field is set to true, the retry policy becomes active. If active the policy will retry a maximum of 3 times, with an increasing timeout of 2, 5 and 10 seconds respectively.",
|
|
87
|
+
"type": "boolean"
|
|
88
|
+
},
|
|
89
|
+
"errorsToRetry": {
|
|
90
|
+
"description": "A list of error names that should trigger a retry. If not specified, the default is to retry on all errors.",
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"type": "string"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"required": [
|
|
98
|
+
"enabled"
|
|
99
|
+
],
|
|
100
|
+
"additionalProperties": false
|
|
101
|
+
},
|
|
102
|
+
"executionCredentials": {
|
|
103
|
+
"description": "When this property is set, the CLI will automatically create a User and Global Role with the defined permissions for the Function. Credentials for this User will be injected into the Function's environment automatically. The Global Role and its permissions will be managed by the CLI and synchronized whenever the executionCredentials.permissions property is updated.",
|
|
104
|
+
"type": "object",
|
|
105
|
+
"properties": {
|
|
106
|
+
"permissions": {
|
|
107
|
+
"description": "The permissions that will be attached to the Global Role for the created user. The Global Role will be created with a name like exh.tasks.<your function name>.",
|
|
108
|
+
"type": "array",
|
|
109
|
+
"items": {
|
|
110
|
+
"type": "string"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"email": {
|
|
114
|
+
"description": "By default the CLI generates an email address like exh.tasks+<your function name>@extrahorizon.com for the User which is created for the Function. If you like you can change this behavior and provide your own email address to retain ownership of the user account.",
|
|
115
|
+
"type": "string"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"required": [
|
|
119
|
+
"permissions"
|
|
120
|
+
],
|
|
121
|
+
"additionalProperties": false
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"required": [
|
|
125
|
+
"name",
|
|
126
|
+
"path",
|
|
127
|
+
"entryPoint",
|
|
128
|
+
"runtime"
|
|
129
|
+
],
|
|
130
|
+
"additionalProperties": false
|
|
131
|
+
}
|
package/build/constants.js
CHANGED
|
@@ -3,33 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.limits = exports.runtimeChoices = exports.EXH_CONFIG_FILE = exports.EXH_CONFIG_FILE_DIR = void 0;
|
|
4
4
|
const os_1 = require("os");
|
|
5
5
|
const path = require("path");
|
|
6
|
+
const taskConfigSchema = require("./config-json-schemas/TaskConfig.json");
|
|
6
7
|
exports.EXH_CONFIG_FILE_DIR = path.join((0, os_1.homedir)(), '/.exh');
|
|
7
8
|
exports.EXH_CONFIG_FILE = `${exports.EXH_CONFIG_FILE_DIR}/credentials`;
|
|
8
|
-
exports.runtimeChoices =
|
|
9
|
-
'nodejs22.x',
|
|
10
|
-
'nodejs16.x',
|
|
11
|
-
'nodejs20.x',
|
|
12
|
-
'nodejs18.x',
|
|
13
|
-
'python3.13',
|
|
14
|
-
'python3.12',
|
|
15
|
-
'python3.11',
|
|
16
|
-
'python3.10',
|
|
17
|
-
'python3.9',
|
|
18
|
-
'python3.8',
|
|
19
|
-
'java21',
|
|
20
|
-
'java17',
|
|
21
|
-
'java11',
|
|
22
|
-
'java8.al2',
|
|
23
|
-
'dotnet9',
|
|
24
|
-
'dotnet8',
|
|
25
|
-
'dotnet7',
|
|
26
|
-
'dotnet6',
|
|
27
|
-
'ruby3.4',
|
|
28
|
-
'ruby3.3',
|
|
29
|
-
'ruby3.2',
|
|
30
|
-
'provided.al2023',
|
|
31
|
-
'provided.al2',
|
|
32
|
-
];
|
|
9
|
+
exports.runtimeChoices = taskConfigSchema.properties.runtime.enum;
|
|
33
10
|
exports.limits = {
|
|
34
11
|
time: {
|
|
35
12
|
min: 3,
|
package/build/helpers/util.d.ts
CHANGED
package/build/helpers/util.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadAndAssertCredentials = exports.asyncExec = exports.epilogue = void 0;
|
|
3
|
+
exports.getCliVersion = exports.loadAndAssertCredentials = exports.asyncExec = exports.epilogue = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
6
7
|
const chalk = require("chalk");
|
|
7
8
|
const constants_1 = require("../constants");
|
|
8
9
|
const error_1 = require("./error");
|
|
@@ -65,3 +66,9 @@ function loadAndAssertCredentials() {
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
exports.loadAndAssertCredentials = loadAndAssertCredentials;
|
|
69
|
+
function getCliVersion() {
|
|
70
|
+
const packageJsonPath = path.join(__dirname, '../../package.json');
|
|
71
|
+
const packageJsonString = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
72
|
+
return JSON.parse(packageJsonString).version;
|
|
73
|
+
}
|
|
74
|
+
exports.getCliVersion = getCliVersion;
|