@beseif-solutions/prow-core 0.0.34 → 0.0.36
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/dist/core.d.ts +10 -9
- package/dist/entities/commons.js +2 -1
- package/dist/entities/provider.d.ts +1 -0
- package/dist/entities/provider.js +2 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/minified-utils/context.js +22 -1
- package/dist/minified-utils/fields.d.ts +18 -8
- package/dist/minified-utils/fields.js +68 -52
- package/dist/minified-utils/locales.d.ts +1 -0
- package/dist/minified-utils/locales.js +6 -1
- package/dist/minified-utils/protocol.d.ts +12 -2
- package/dist/minified-utils/protocol.js +88 -4
- package/package.json +1 -1
- package/src/core.ts +11 -9
- package/src/entities/commons.ts +2 -1
- package/src/entities/provider.ts +3 -1
- package/src/index.ts +2 -2
- package/src/minified-utils/context.ts +24 -1
- package/src/minified-utils/fields.ts +114 -55
- package/src/minified-utils/locales.ts +8 -0
- package/src/minified-utils/protocol.ts +91 -7
package/dist/core.d.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AxiosStatic } from "axios";
|
|
2
2
|
import Joi from "joi";
|
|
3
|
-
import
|
|
3
|
+
import { LoDashStatic } from "lodash";
|
|
4
4
|
import moment from "moment-timezone";
|
|
5
5
|
import { FromCatalog, FromDirectory, T } from "./minified-utils/locales";
|
|
6
|
-
type
|
|
7
|
-
|
|
6
|
+
type SyncOrAsync<T> = T | Promise<T>;
|
|
7
|
+
export type SourceFunctions = {
|
|
8
|
+
register: <T>(source: string, data: T) => SyncOrAsync<{
|
|
8
9
|
id: string;
|
|
9
10
|
}>;
|
|
10
|
-
consume: <T>(source: string) =>
|
|
11
|
+
consume: <T>(source: string) => SyncOrAsync<{
|
|
11
12
|
id: string;
|
|
12
13
|
data: T;
|
|
13
14
|
}[]>;
|
|
14
|
-
unregister: (source: string, id: string) =>
|
|
15
|
+
unregister: (source: string, id: string) => SyncOrAsync<void>;
|
|
15
16
|
};
|
|
16
17
|
export type Core = {
|
|
17
|
-
axios:
|
|
18
|
+
axios: AxiosStatic;
|
|
18
19
|
moment: typeof moment;
|
|
19
|
-
lodash:
|
|
20
|
+
lodash: LoDashStatic;
|
|
20
21
|
env: Record<string, any>;
|
|
21
|
-
joi:
|
|
22
|
+
joi: Joi.Root;
|
|
22
23
|
sources?: SourceFunctions;
|
|
23
24
|
t: T;
|
|
24
25
|
};
|
package/dist/entities/commons.js
CHANGED
|
@@ -5,7 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.commonSchema = exports.idSchema = void 0;
|
|
7
7
|
const joi_1 = __importDefault(require("joi"));
|
|
8
|
-
const idSchema = () => joi_1.default.string().required().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
8
|
+
const idSchema = () => joi_1.default.string().required().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
9
|
+
.invalid(`ui`);
|
|
9
10
|
exports.idSchema = idSchema;
|
|
10
11
|
const commonSchema = () => joi_1.default.object({
|
|
11
12
|
id: (0, exports.idSchema)(),
|
|
@@ -5,12 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.providerSchema = void 0;
|
|
7
7
|
const joi_1 = __importDefault(require("joi"));
|
|
8
|
+
const commons_1 = require("./commons");
|
|
8
9
|
const credentials_1 = require("./credentials");
|
|
9
10
|
const events_1 = require("./events");
|
|
10
|
-
const commons_1 = require("./commons");
|
|
11
11
|
const source_1 = require("./source");
|
|
12
12
|
const providerSchema = () => joi_1.default.object({
|
|
13
13
|
id: (0, commons_1.idSchema)(),
|
|
14
|
+
version: joi_1.default.string().required(),
|
|
14
15
|
model: joi_1.default.valid(`provider`).required(),
|
|
15
16
|
credentials: joi_1.default.object()
|
|
16
17
|
.pattern((0, commons_1.idSchema)(), (0, credentials_1.credentialsSchema)())
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { Credentials, credentialsSchema, OAuthCredentials, oauthCredentialsSchem
|
|
|
4
4
|
export { Action, actionOutputSchema, actionSchema, Event, eventSchema, ImmediateTrigger, immediateTriggerSchema, Request, ScheduledTrigger, scheduledTriggerSchema, Trigger, triggerOutputSchema, triggerSchema } from './entities/events';
|
|
5
5
|
export { Provider, providerSchema } from './entities/provider';
|
|
6
6
|
export { Source } from './entities/source';
|
|
7
|
-
export { extract, Field, fieldSchema, fieldsSchema, SelectFieldChoice, validate, ValidationResult } from './minified-utils/fields';
|
|
8
|
-
export { i18n, localizeFields, localizeInputs, localizeOutputs, localizeProperties
|
|
7
|
+
export { extract, Field, fieldSchema, fieldsSchema, File, SelectFieldChoice, validate, ValidationResult } from './minified-utils/fields';
|
|
8
|
+
export { i18n, LocalizedField, LocalizedProperties, localizeFields, localizeGroup, localizeInputs, localizeOutputs, localizeProperties } from './minified-utils/locales';
|
|
9
9
|
export { Properties } from './minified-utils/properties';
|
|
10
10
|
export { Protocol } from './minified-utils/protocol';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Protocol = exports.Properties = exports.localizeProperties = exports.localizeOutputs = exports.localizeInputs = exports.localizeFields = exports.i18n = exports.validate = exports.fieldsSchema = exports.fieldSchema = exports.extract = exports.providerSchema = exports.triggerSchema = exports.triggerOutputSchema = exports.scheduledTriggerSchema = exports.immediateTriggerSchema = exports.eventSchema = exports.actionSchema = exports.actionOutputSchema = exports.staticCredentialsSchema = exports.sessionCredentialsSchema = exports.oauthCredentialsSchema = exports.credentialsSchema = exports.idSchema = exports.core = void 0;
|
|
3
|
+
exports.Protocol = exports.Properties = exports.localizeProperties = exports.localizeOutputs = exports.localizeInputs = exports.localizeGroup = exports.localizeFields = exports.i18n = exports.validate = exports.fieldsSchema = exports.fieldSchema = exports.extract = exports.providerSchema = exports.triggerSchema = exports.triggerOutputSchema = exports.scheduledTriggerSchema = exports.immediateTriggerSchema = exports.eventSchema = exports.actionSchema = exports.actionOutputSchema = exports.staticCredentialsSchema = exports.sessionCredentialsSchema = exports.oauthCredentialsSchema = exports.credentialsSchema = exports.idSchema = exports.core = void 0;
|
|
4
4
|
var core_1 = require("./core");
|
|
5
5
|
Object.defineProperty(exports, "core", { enumerable: true, get: function () { return core_1.core; } });
|
|
6
6
|
var commons_1 = require("./entities/commons");
|
|
@@ -28,6 +28,7 @@ Object.defineProperty(exports, "validate", { enumerable: true, get: function ()
|
|
|
28
28
|
var locales_1 = require("./minified-utils/locales");
|
|
29
29
|
Object.defineProperty(exports, "i18n", { enumerable: true, get: function () { return locales_1.i18n; } });
|
|
30
30
|
Object.defineProperty(exports, "localizeFields", { enumerable: true, get: function () { return locales_1.localizeFields; } });
|
|
31
|
+
Object.defineProperty(exports, "localizeGroup", { enumerable: true, get: function () { return locales_1.localizeGroup; } });
|
|
31
32
|
Object.defineProperty(exports, "localizeInputs", { enumerable: true, get: function () { return locales_1.localizeInputs; } });
|
|
32
33
|
Object.defineProperty(exports, "localizeOutputs", { enumerable: true, get: function () { return locales_1.localizeOutputs; } });
|
|
33
34
|
Object.defineProperty(exports, "localizeProperties", { enumerable: true, get: function () { return locales_1.localizeProperties; } });
|
|
@@ -23,11 +23,32 @@ class Context {
|
|
|
23
23
|
else {
|
|
24
24
|
return source;
|
|
25
25
|
}
|
|
26
|
-
if (!unresolved.includes(`{{`)) {
|
|
26
|
+
if (!unresolved || !unresolved.includes(`{{`)) {
|
|
27
27
|
return source;
|
|
28
28
|
}
|
|
29
29
|
const template = handlebars_1.default.compile(unresolved);
|
|
30
30
|
const resolved = template(data);
|
|
31
|
+
if (resolved.includes(`[object Object]`)) {
|
|
32
|
+
const clonedData = lodash_1.default.cloneDeep(data);
|
|
33
|
+
const parsed = handlebars_1.default.parseWithoutProcessing(unresolved);
|
|
34
|
+
for (const x of parsed.body) {
|
|
35
|
+
if (x.type === `MustacheStatement`) {
|
|
36
|
+
const get = lodash_1.default.get(clonedData, x[`path`].original);
|
|
37
|
+
if (lodash_1.default.isObject(get) || lodash_1.default.isArray(get)) {
|
|
38
|
+
if (isObject) {
|
|
39
|
+
unresolved = unresolved.replace(`"{{${x[`path`].original}}}"`, JSON.stringify(get));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
lodash_1.default.set(clonedData, `${x[`path`].original}.toString`, () => JSON.stringify(get));
|
|
43
|
+
if (x[`escaped`]) {
|
|
44
|
+
unresolved = unresolved.replace(`{{${x[`path`].original}}}`, `{{{${x[`path`].original}}}}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return this.resolve(isObject ? JSON.parse(unresolved) : unresolved, clonedData);
|
|
51
|
+
}
|
|
31
52
|
return isObject ? JSON.parse(resolved) : resolved;
|
|
32
53
|
};
|
|
33
54
|
handlebars_1.default.registerHelper({
|
|
@@ -22,8 +22,10 @@ type Common = {
|
|
|
22
22
|
array_length?: number;
|
|
23
23
|
});
|
|
24
24
|
export type Field<Extend = Record<never, never>> = Common & InputField<Extend>;
|
|
25
|
-
type InputField<Extend = Record<never, never>> = (AnyInputField<Extend> | StringInputField<Extend> | NumberInputField<Extend> | BooleanInputField<Extend> | DateTimeInputField<Extend> | DateInputField<Extend> | TimeInputField<Extend> | DictInputField<Extend>) & Extend;
|
|
26
|
-
type Any = string | number | boolean
|
|
25
|
+
type InputField<Extend = Record<never, never>> = (AnyInputField<Extend> | StringInputField<Extend> | NumberInputField<Extend> | BooleanInputField<Extend> | DateTimeInputField<Extend> | DateInputField<Extend> | TimeInputField<Extend> | DictInputField<Extend> | FileInputField<Extend>) & Extend;
|
|
26
|
+
type Any = string | number | boolean | Any[] | {
|
|
27
|
+
[key: string]: Any;
|
|
28
|
+
};
|
|
27
29
|
type AnyInputField<Extend = Record<never, never>> = {
|
|
28
30
|
type: `any`;
|
|
29
31
|
default?: Any | Any[];
|
|
@@ -36,7 +38,8 @@ type StringInputField<Extend = Record<never, never>> = {
|
|
|
36
38
|
max?: number;
|
|
37
39
|
regexp?: string;
|
|
38
40
|
pattern?: `email` | `uri`;
|
|
39
|
-
|
|
41
|
+
escape?: boolean;
|
|
42
|
+
} & (SelectField<string, Extend> | TextareaField | RichTextField | {});
|
|
40
43
|
type NumberInputField<Extend = Record<never, never>> = {
|
|
41
44
|
type: `number`;
|
|
42
45
|
default?: number | number[];
|
|
@@ -80,18 +83,25 @@ type DictInputField<Extend = Record<never, never>> = {
|
|
|
80
83
|
items?: Field<Extend>[];
|
|
81
84
|
unknown?: boolean;
|
|
82
85
|
};
|
|
83
|
-
type
|
|
86
|
+
export type File = {
|
|
87
|
+
name: string;
|
|
88
|
+
type: string;
|
|
89
|
+
content: string;
|
|
90
|
+
};
|
|
91
|
+
type FileInputField<Extend = Record<never, never>> = {
|
|
92
|
+
type: `file`;
|
|
93
|
+
default?: File | File[];
|
|
94
|
+
accept?: string | string[];
|
|
95
|
+
} & (SelectField<File, Extend> | {});
|
|
96
|
+
type SelectField<Values = string | number | boolean | File, Extend = Record<never, never>> = {
|
|
84
97
|
format: `select`;
|
|
85
98
|
choices: SelectFieldChoice<Values, Extend>[] | string;
|
|
86
99
|
unknown?: boolean;
|
|
87
100
|
};
|
|
88
|
-
export type SelectFieldChoice<Values = string | number | boolean, Extend = Record<never, never>> = {
|
|
101
|
+
export type SelectFieldChoice<Values = string | number | boolean | File, Extend = Record<never, never>> = {
|
|
89
102
|
key: string;
|
|
90
103
|
value: Values;
|
|
91
104
|
} & Extend;
|
|
92
|
-
type FileField = {
|
|
93
|
-
format: `file`;
|
|
94
|
-
};
|
|
95
105
|
type TextareaField = {
|
|
96
106
|
format: `textarea`;
|
|
97
107
|
};
|
|
@@ -6,10 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.extract = exports.validate = exports.fieldsSchema = exports.fieldSchema = void 0;
|
|
7
7
|
const joi_1 = __importDefault(require("joi"));
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
-
const where_1 = require("./where");
|
|
10
9
|
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
11
|
-
const axios_1 = __importDefault(require("axios"));
|
|
12
10
|
const context_1 = __importDefault(require("./context"));
|
|
11
|
+
const where_1 = require("./where");
|
|
13
12
|
const conditionSchema = () => joi_1.default.object({
|
|
14
13
|
condition: joi_1.default.object(),
|
|
15
14
|
overrides: joi_1.default.object(),
|
|
@@ -38,7 +37,7 @@ const commonFieldSchema = () => joi_1.default.object({
|
|
|
38
37
|
otherwise: joi_1.default.forbidden(),
|
|
39
38
|
}),
|
|
40
39
|
});
|
|
41
|
-
const types = [`any`, `string`, `number`, `boolean`, `date`, `datetime`, `time`, `dict`];
|
|
40
|
+
const types = [`any`, `string`, `number`, `boolean`, `date`, `datetime`, `time`, `dict`, `file`];
|
|
42
41
|
const inputFieldBaseSchema = () => joi_1.default.object({
|
|
43
42
|
type: joi_1.default.string().required()
|
|
44
43
|
.valid(...types),
|
|
@@ -56,7 +55,8 @@ const defaultSchema = (type) => joi_1.default.when(`as_array`, {
|
|
|
56
55
|
then: joi_1.default.array().items(type),
|
|
57
56
|
otherwise: type,
|
|
58
57
|
});
|
|
59
|
-
const anySchema = () => joi_1.default.alternatives(joi_1.default.string(), joi_1.default.bool(), joi_1.default.number())
|
|
58
|
+
const anySchema = () => joi_1.default.alternatives(joi_1.default.string(), joi_1.default.bool(), joi_1.default.number(), joi_1.default.array().items(joi_1.default.link(`#any`)), joi_1.default.object().pattern(joi_1.default.string(), joi_1.default.link(`#any`)))
|
|
59
|
+
.id(`any`);
|
|
60
60
|
const anyInputFieldSchema = () => joi_1.default.object({
|
|
61
61
|
default: defaultSchema(anySchema()),
|
|
62
62
|
})
|
|
@@ -77,7 +77,7 @@ const stringInputFieldSchema = () => joi_1.default.object({
|
|
|
77
77
|
pattern: joi_1.default.string().valid(`email`, `uri`),
|
|
78
78
|
})
|
|
79
79
|
.concat(joi_1.default.object({
|
|
80
|
-
format: joi_1.default.string().valid(`
|
|
80
|
+
format: joi_1.default.string().valid(`select`, `textarea`, `rich-text`),
|
|
81
81
|
choices: joi_1.default.when(`format`, {
|
|
82
82
|
is: `select`,
|
|
83
83
|
then: choicesSchema(joi_1.default.string()).required(),
|
|
@@ -147,6 +147,23 @@ const dictInputFieldSchema = () => joi_1.default.object({
|
|
|
147
147
|
otherwise: joi_1.default.forbidden(),
|
|
148
148
|
}),
|
|
149
149
|
});
|
|
150
|
+
const fileSchema = () => joi_1.default.object({
|
|
151
|
+
name: joi_1.default.string().required(),
|
|
152
|
+
type: joi_1.default.string().required(),
|
|
153
|
+
content: joi_1.default.string().required(),
|
|
154
|
+
});
|
|
155
|
+
const fileInputFieldSchema = () => joi_1.default.object({
|
|
156
|
+
default: defaultSchema(fileSchema()),
|
|
157
|
+
accept: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).optional(),
|
|
158
|
+
})
|
|
159
|
+
.concat(joi_1.default.object({
|
|
160
|
+
format: joi_1.default.string().valid(`select`),
|
|
161
|
+
choices: joi_1.default.when(`format`, {
|
|
162
|
+
is: `select`,
|
|
163
|
+
then: choicesSchema(fileSchema()).required(),
|
|
164
|
+
otherwise: joi_1.default.forbidden(),
|
|
165
|
+
}),
|
|
166
|
+
}));
|
|
150
167
|
const fieldSchema = () => inputFieldBaseSchema()
|
|
151
168
|
.id(`field`)
|
|
152
169
|
.when(joi_1.default.object({ type: joi_1.default.valid(`any`) }).unknown(), {
|
|
@@ -176,6 +193,10 @@ const fieldSchema = () => inputFieldBaseSchema()
|
|
|
176
193
|
.when(joi_1.default.object({ type: joi_1.default.valid(`dict`) }).unknown(), {
|
|
177
194
|
then: inputFieldBaseSchema()
|
|
178
195
|
.concat(dictInputFieldSchema()),
|
|
196
|
+
})
|
|
197
|
+
.when(joi_1.default.object({ type: joi_1.default.valid(`file`) }).unknown(), {
|
|
198
|
+
then: inputFieldBaseSchema()
|
|
199
|
+
.concat(fileInputFieldSchema()),
|
|
179
200
|
})
|
|
180
201
|
.when(joi_1.default.object({ type: joi_1.default.invalid(...types) }).unknown(), {
|
|
181
202
|
then: joi_1.default.forbidden(),
|
|
@@ -215,47 +236,6 @@ const getFieldSchema = (field) => {
|
|
|
215
236
|
if (field.pattern === `uri`) {
|
|
216
237
|
typeSchema = typeSchema.uri();
|
|
217
238
|
}
|
|
218
|
-
if (`format` in field && field.format === `file`) {
|
|
219
|
-
typeSchema = typeSchema.external(async (value, helpers) => {
|
|
220
|
-
if (!helpers.original && !field.required) {
|
|
221
|
-
return helpers.original;
|
|
222
|
-
}
|
|
223
|
-
const [asURL, asBase64] = await Promise.allSettled([
|
|
224
|
-
(async () => {
|
|
225
|
-
try {
|
|
226
|
-
const { value: url, error } = joi_1.default.string().uri().validate(helpers.original);
|
|
227
|
-
if (error) {
|
|
228
|
-
throw new Error(`Invalid URL schema`);
|
|
229
|
-
}
|
|
230
|
-
const { data: content } = await axios_1.default.get(url, { responseType: `arraybuffer` });
|
|
231
|
-
return Buffer.from(content).toString(`base64`);
|
|
232
|
-
}
|
|
233
|
-
catch (e) {
|
|
234
|
-
throw e;
|
|
235
|
-
}
|
|
236
|
-
})(),
|
|
237
|
-
(async () => {
|
|
238
|
-
try {
|
|
239
|
-
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
|
240
|
-
if (!base64regex.test(helpers.original)) {
|
|
241
|
-
throw new Error(`Invalid regexp`);
|
|
242
|
-
}
|
|
243
|
-
return Buffer.from(helpers.original, `base64`).toString(`base64`);
|
|
244
|
-
}
|
|
245
|
-
catch (e) {
|
|
246
|
-
throw e;
|
|
247
|
-
}
|
|
248
|
-
})(),
|
|
249
|
-
]);
|
|
250
|
-
if (asURL.status === `fulfilled`) {
|
|
251
|
-
return asURL.value;
|
|
252
|
-
}
|
|
253
|
-
else if (asBase64.status === `fulfilled`) {
|
|
254
|
-
return asBase64.value;
|
|
255
|
-
}
|
|
256
|
-
return helpers.message({ external: `invalid value, expected URL or Base64 string` });
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
239
|
break;
|
|
260
240
|
case `date`:
|
|
261
241
|
case `datetime`:
|
|
@@ -305,12 +285,37 @@ const getFieldSchema = (field) => {
|
|
|
305
285
|
}
|
|
306
286
|
break;
|
|
307
287
|
case `dict`:
|
|
288
|
+
let objSchema;
|
|
308
289
|
if (field.items) {
|
|
309
|
-
|
|
290
|
+
objSchema = getFieldsSchema(field.items).unknown(field.unknown || false);
|
|
310
291
|
}
|
|
311
292
|
else {
|
|
312
|
-
|
|
293
|
+
objSchema = joi_1.default.object().unknown(true);
|
|
313
294
|
}
|
|
295
|
+
typeSchema = joi_1.default.alternatives(objSchema, joi_1.default.string().external(async (value, helpers) => {
|
|
296
|
+
if (!helpers.original && !field.required) {
|
|
297
|
+
return helpers.original;
|
|
298
|
+
}
|
|
299
|
+
const parsed = JSON.parse(value);
|
|
300
|
+
const { value: objValue, error } = objSchema.validate(parsed, { abortEarly: false });
|
|
301
|
+
if (error) {
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
return objValue;
|
|
305
|
+
}));
|
|
306
|
+
break;
|
|
307
|
+
case `file`:
|
|
308
|
+
typeSchema = joi_1.default.alternatives(fileSchema(), joi_1.default.string().external(async (value, helpers) => {
|
|
309
|
+
if (!helpers.original && !field.required) {
|
|
310
|
+
return helpers.original;
|
|
311
|
+
}
|
|
312
|
+
const parsed = JSON.parse(value);
|
|
313
|
+
const { value: fileValue, error } = fileSchema().validate(parsed, { abortEarly: false });
|
|
314
|
+
if (error) {
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
return fileValue;
|
|
318
|
+
}));
|
|
314
319
|
break;
|
|
315
320
|
}
|
|
316
321
|
if (`format` in field && field.format === `select`) {
|
|
@@ -323,16 +328,27 @@ const getFieldSchema = (field) => {
|
|
|
323
328
|
}
|
|
324
329
|
}
|
|
325
330
|
if (field.as_array) {
|
|
326
|
-
|
|
331
|
+
let arraySchema = joi_1.default.array().items(typeSchema);
|
|
327
332
|
if (field.array_length) {
|
|
328
|
-
|
|
333
|
+
arraySchema = arraySchema.length(field.array_length);
|
|
329
334
|
}
|
|
330
335
|
if (field.array_min) {
|
|
331
|
-
|
|
336
|
+
arraySchema = arraySchema.min(field.array_min);
|
|
332
337
|
}
|
|
333
338
|
if (field.array_max) {
|
|
334
|
-
|
|
339
|
+
arraySchema = arraySchema.max(field.array_max);
|
|
335
340
|
}
|
|
341
|
+
typeSchema = joi_1.default.alternatives(arraySchema, joi_1.default.string().external(async (value, helpers) => {
|
|
342
|
+
if (!helpers.original && !field.required) {
|
|
343
|
+
return helpers.original;
|
|
344
|
+
}
|
|
345
|
+
const parsed = JSON.parse(value);
|
|
346
|
+
const { value: arrValue, error } = arraySchema.validate(parsed, { abortEarly: false });
|
|
347
|
+
if (error) {
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
return arrValue;
|
|
351
|
+
}));
|
|
336
352
|
}
|
|
337
353
|
if (field.disabled) {
|
|
338
354
|
typeSchema = typeSchema.forbidden();
|
|
@@ -34,6 +34,7 @@ export declare const i18n: (options: FromCatalog | FromDirectory) => {
|
|
|
34
34
|
};
|
|
35
35
|
export declare const localizeFields: (t: ReturnType<typeof i18n>[`t`], element: Action | Trigger | StaticCredentials | SessionCredentials | Source) => Field<LocalizedField>[];
|
|
36
36
|
export declare const localizeProperties: (t: ReturnType<typeof i18n>[`t`], element: Action | Trigger | Credentials | Provider | Source) => LocalizedProperties;
|
|
37
|
+
export declare const localizeGroup: (t: ReturnType<typeof i18n>[`t`], element: Action | Trigger) => LocalizedProperties;
|
|
37
38
|
export declare const localizeInputs: (t: ReturnType<typeof i18n>[`t`], element: Action) => (ConnectableEvent & LocalizedProperties)[];
|
|
38
39
|
export declare const localizeOutputs: (t: ReturnType<typeof i18n>[`t`], element: Action | Trigger) => (ConnectableEvent & LocalizedProperties)[];
|
|
39
40
|
export {};
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.localizeOutputs = exports.localizeInputs = exports.localizeProperties = exports.localizeFields = exports.i18n = exports.validateDirectory = void 0;
|
|
6
|
+
exports.localizeOutputs = exports.localizeInputs = exports.localizeGroup = exports.localizeProperties = exports.localizeFields = exports.i18n = exports.validateDirectory = void 0;
|
|
7
7
|
const i18n_1 = __importDefault(require("i18n"));
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -112,6 +112,11 @@ const localizeProperties = (t, element) => ({
|
|
|
112
112
|
description: t(`${element.id}.description`),
|
|
113
113
|
});
|
|
114
114
|
exports.localizeProperties = localizeProperties;
|
|
115
|
+
const localizeGroup = (t, element) => ({
|
|
116
|
+
name: t(`ui.groups.${element.ui.group}.name`, { fallback: true }),
|
|
117
|
+
description: t(`ui.groups.${element.ui.group}.description`),
|
|
118
|
+
});
|
|
119
|
+
exports.localizeGroup = localizeGroup;
|
|
115
120
|
const localizeConnectable = (t, element, type) => {
|
|
116
121
|
const response = [];
|
|
117
122
|
if (element[type] && element[type].length > 0) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Provider } from "../entities/provider";
|
|
2
2
|
export declare class Protocol {
|
|
3
3
|
private readonly provider;
|
|
4
|
-
private readonly
|
|
5
|
-
constructor(provider: Provider,
|
|
4
|
+
private readonly configuration;
|
|
5
|
+
constructor(provider: Provider, configuration: Protocol.Configuration);
|
|
6
6
|
evaluate: (req: Protocol.Command) => Promise<any>;
|
|
7
7
|
}
|
|
8
8
|
export declare namespace Protocol {
|
|
@@ -16,6 +16,8 @@ export declare namespace Protocol {
|
|
|
16
16
|
configuration: Record<string, any>;
|
|
17
17
|
};
|
|
18
18
|
context: {
|
|
19
|
+
organization: string;
|
|
20
|
+
workspace: number;
|
|
19
21
|
environment: Record<string, any>;
|
|
20
22
|
localization: {
|
|
21
23
|
locale: string;
|
|
@@ -39,4 +41,12 @@ export declare namespace Protocol {
|
|
|
39
41
|
command: `list:locales`;
|
|
40
42
|
};
|
|
41
43
|
type Command = Invoke | CredentialList | ActionList | TriggerList | SourceList | LocaleList;
|
|
44
|
+
type SourcesConfiguration = {
|
|
45
|
+
host: string;
|
|
46
|
+
token: string;
|
|
47
|
+
};
|
|
48
|
+
type Configuration = {
|
|
49
|
+
path: string;
|
|
50
|
+
sources: SourcesConfiguration;
|
|
51
|
+
};
|
|
42
52
|
}
|
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Protocol = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
7
8
|
const joi_1 = __importDefault(require("joi"));
|
|
8
9
|
const lodash_1 = __importDefault(require("lodash"));
|
|
10
|
+
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
9
11
|
const core_1 = require("../core");
|
|
10
12
|
const provider_1 = require("../entities/provider");
|
|
11
13
|
const locales_1 = require("./locales");
|
|
@@ -41,8 +43,87 @@ const localeListSchema = joi_1.default.object({
|
|
|
41
43
|
command: joi_1.default.string().valid(`list:locales`).required(),
|
|
42
44
|
}).required();
|
|
43
45
|
const commandSchema = joi_1.default.alternatives(invokeSchema, credentialListSchema, actionListSchema, triggerListSchema, sourceListSchema, localeListSchema);
|
|
46
|
+
const API_SOURCES = (provider, configuration, context) => ({
|
|
47
|
+
register: async (source, data) => {
|
|
48
|
+
try {
|
|
49
|
+
const { data: [created] } = await axios_1.default.post(`/api/v1/sources`, {
|
|
50
|
+
organization: context.organization,
|
|
51
|
+
workspace: context.workspace,
|
|
52
|
+
provider: provider.id,
|
|
53
|
+
version: provider.version,
|
|
54
|
+
source: source,
|
|
55
|
+
data: data,
|
|
56
|
+
created_date: (0, moment_timezone_1.default)().format(`YYYY-MM-DDTHH:mm:ssZ`),
|
|
57
|
+
}, {
|
|
58
|
+
baseURL: configuration.host,
|
|
59
|
+
headers: {
|
|
60
|
+
"X-Internal-Token": configuration.token,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
if (!created || !created.uuid) {
|
|
64
|
+
throw new Error(`Source registration failed`);
|
|
65
|
+
}
|
|
66
|
+
return { id: created.uuid };
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
unregister: async (source, id) => {
|
|
73
|
+
try {
|
|
74
|
+
const { data: [get] } = await axios_1.default.post(`/api/v1/sources/list`, {
|
|
75
|
+
organization: context.organization,
|
|
76
|
+
workspace: context.workspace,
|
|
77
|
+
provider: provider.id,
|
|
78
|
+
version: provider.version,
|
|
79
|
+
source: source,
|
|
80
|
+
uuid: id,
|
|
81
|
+
}, {
|
|
82
|
+
baseURL: configuration.host,
|
|
83
|
+
headers: {
|
|
84
|
+
"X-Internal-Token": configuration.token,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
if (!get) {
|
|
88
|
+
throw new Error(`Source with ID ${id} not found`);
|
|
89
|
+
}
|
|
90
|
+
await axios_1.default.delete(`/api/v1/sources/${get.id}`, {
|
|
91
|
+
baseURL: configuration.host,
|
|
92
|
+
headers: {
|
|
93
|
+
"X-Internal-Token": configuration.token,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
consume: async (source) => {
|
|
102
|
+
try {
|
|
103
|
+
const { data: sources } = await axios_1.default.post(`/api/v1/sources/list`, {
|
|
104
|
+
organization: context.organization,
|
|
105
|
+
workspace: context.workspace,
|
|
106
|
+
provider: provider.id,
|
|
107
|
+
version: provider.version,
|
|
108
|
+
source: source,
|
|
109
|
+
}, {
|
|
110
|
+
baseURL: configuration.host,
|
|
111
|
+
headers: {
|
|
112
|
+
"X-Internal-Token": configuration.token,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
return sources.map((s) => ({
|
|
116
|
+
id: s.uuid,
|
|
117
|
+
data: s.data,
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
throw e;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
});
|
|
44
125
|
class Protocol {
|
|
45
|
-
constructor(provider,
|
|
126
|
+
constructor(provider, configuration) {
|
|
46
127
|
this.evaluate = async (req) => {
|
|
47
128
|
try {
|
|
48
129
|
const validation = commandSchema.validate(req);
|
|
@@ -69,7 +150,7 @@ class Protocol {
|
|
|
69
150
|
response = Object.values(this.provider.sources || {});
|
|
70
151
|
break;
|
|
71
152
|
case `list:locales`:
|
|
72
|
-
const i18nInstance = (0, locales_1.i18n)({ directory: `${this.path}/locales` });
|
|
153
|
+
const i18nInstance = (0, locales_1.i18n)({ directory: `${this.configuration.path}/locales` });
|
|
73
154
|
response = i18nInstance.i18n.getLocales().map((l) => {
|
|
74
155
|
i18nInstance.i18n.setLocale(l);
|
|
75
156
|
return {
|
|
@@ -90,7 +171,10 @@ class Protocol {
|
|
|
90
171
|
const invokeInstance = (0, core_1.core)({
|
|
91
172
|
env: req.context.environment,
|
|
92
173
|
localization: req.context.localization,
|
|
93
|
-
sources:
|
|
174
|
+
sources: API_SOURCES(this.provider, this.configuration.sources, {
|
|
175
|
+
organization: req.context.organization,
|
|
176
|
+
workspace: req.context.workspace,
|
|
177
|
+
}),
|
|
94
178
|
});
|
|
95
179
|
response = await func(invokeInstance, req.params.configuration);
|
|
96
180
|
break;
|
|
@@ -108,7 +192,7 @@ class Protocol {
|
|
|
108
192
|
throw new Error(`Invalid provider for protocol`);
|
|
109
193
|
}
|
|
110
194
|
this.provider = provider;
|
|
111
|
-
this.
|
|
195
|
+
this.configuration = configuration;
|
|
112
196
|
}
|
|
113
197
|
}
|
|
114
198
|
exports.Protocol = Protocol;
|
package/package.json
CHANGED
package/src/core.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import axios from "axios";
|
|
1
|
+
import axios, { AxiosStatic } from "axios";
|
|
2
2
|
import Joi from "joi";
|
|
3
|
-
import _ from "lodash";
|
|
3
|
+
import _, { LoDashStatic } from "lodash";
|
|
4
4
|
import moment from "moment-timezone";
|
|
5
5
|
import { FromCatalog, FromDirectory, i18n, T } from "./minified-utils/locales";
|
|
6
6
|
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
type SyncOrAsync<T> = T | Promise<T>;
|
|
8
|
+
|
|
9
|
+
export type SourceFunctions = {
|
|
10
|
+
register: <T>(source: string, data: T) => SyncOrAsync<{ id: string }>,
|
|
11
|
+
consume: <T>(source: string) => SyncOrAsync<{ id: string, data: T }[]>,
|
|
12
|
+
unregister: (source: string, id: string) => SyncOrAsync<void>,
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
const FALLBACK_SOURCES: SourceFunctions = {
|
|
@@ -23,11 +25,11 @@ const FALLBACK_SOURCES: SourceFunctions = {
|
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export type Core = {
|
|
26
|
-
axios:
|
|
28
|
+
axios: AxiosStatic,
|
|
27
29
|
moment: typeof moment,
|
|
28
|
-
lodash:
|
|
30
|
+
lodash: LoDashStatic,
|
|
29
31
|
env: Record<string, any>,
|
|
30
|
-
joi:
|
|
32
|
+
joi: Joi.Root,
|
|
31
33
|
sources?: SourceFunctions,
|
|
32
34
|
t: T,
|
|
33
35
|
};
|
package/src/entities/commons.ts
CHANGED
|
@@ -31,7 +31,8 @@ export type Common<Config extends CommonConfig = {}> = {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const idSchema = () =>
|
|
34
|
-
Joi.string().required().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
34
|
+
Joi.string().required().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
35
|
+
.invalid(`ui`);
|
|
35
36
|
|
|
36
37
|
export const commonSchema = () =>
|
|
37
38
|
Joi.object({
|
package/src/entities/provider.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import Joi from "joi";
|
|
2
|
+
import { idSchema } from "./commons";
|
|
2
3
|
import { Credentials, credentialsSchema } from "./credentials";
|
|
3
4
|
import { Action, actionSchema, Trigger, triggerSchema } from "./events";
|
|
4
|
-
import { idSchema } from "./commons";
|
|
5
5
|
import { Source, sourceSchema } from "./source";
|
|
6
6
|
|
|
7
7
|
export type Provider = {
|
|
8
8
|
id: string,
|
|
9
|
+
version: string,
|
|
9
10
|
model: `provider`,
|
|
10
11
|
credentials: Record<string, Credentials>,
|
|
11
12
|
triggers: Record<string, Trigger>,
|
|
@@ -16,6 +17,7 @@ export type Provider = {
|
|
|
16
17
|
export const providerSchema = () =>
|
|
17
18
|
Joi.object({
|
|
18
19
|
id: idSchema(),
|
|
20
|
+
version: Joi.string().required(),
|
|
19
21
|
model: Joi.valid(`provider`).required(),
|
|
20
22
|
credentials: Joi.object()
|
|
21
23
|
.pattern(idSchema(), credentialsSchema())
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { Credentials, credentialsSchema, OAuthCredentials, oauthCredentialsSchem
|
|
|
4
4
|
export { Action, actionOutputSchema, actionSchema, Event, eventSchema, ImmediateTrigger, immediateTriggerSchema, Request, ScheduledTrigger, scheduledTriggerSchema, Trigger, triggerOutputSchema, triggerSchema } from './entities/events';
|
|
5
5
|
export { Provider, providerSchema } from './entities/provider';
|
|
6
6
|
export { Source } from './entities/source';
|
|
7
|
-
export { extract, Field, fieldSchema, fieldsSchema, SelectFieldChoice, validate, ValidationResult } from './minified-utils/fields';
|
|
8
|
-
export { i18n, localizeFields, localizeInputs, localizeOutputs, localizeProperties
|
|
7
|
+
export { extract, Field, fieldSchema, fieldsSchema, File, SelectFieldChoice, validate, ValidationResult } from './minified-utils/fields';
|
|
8
|
+
export { i18n, LocalizedField, LocalizedProperties, localizeFields, localizeGroup, localizeInputs, localizeOutputs, localizeProperties } from './minified-utils/locales';
|
|
9
9
|
export { Properties } from './minified-utils/properties';
|
|
10
10
|
export { Protocol } from './minified-utils/protocol';
|
|
@@ -43,10 +43,33 @@ class Context {
|
|
|
43
43
|
unresolved = source;
|
|
44
44
|
} else { return source; }
|
|
45
45
|
|
|
46
|
-
if (!unresolved.includes(`{{`)) { return source; }
|
|
46
|
+
if (!unresolved || !unresolved.includes(`{{`)) { return source; }
|
|
47
47
|
|
|
48
48
|
const template = Handlebars.compile(unresolved);
|
|
49
49
|
const resolved = template(data);
|
|
50
|
+
|
|
51
|
+
if (resolved.includes(`[object Object]`)) {
|
|
52
|
+
const clonedData = _.cloneDeep(data);
|
|
53
|
+
// overwrite toString method
|
|
54
|
+
const parsed = Handlebars.parseWithoutProcessing(unresolved);
|
|
55
|
+
for (const x of parsed.body) {
|
|
56
|
+
if (x.type === `MustacheStatement`) {
|
|
57
|
+
const get = _.get(clonedData, x[`path`].original);
|
|
58
|
+
if (_.isObject(get) || _.isArray(get)) {
|
|
59
|
+
if (isObject) {
|
|
60
|
+
unresolved = unresolved.replace(`"{{${x[`path`].original}}}"`, JSON.stringify(get));
|
|
61
|
+
} else {
|
|
62
|
+
_.set(clonedData, `${x[`path`].original}.toString`, () => JSON.stringify(get));
|
|
63
|
+
if (x[`escaped`]) { unresolved = unresolved.replace(`{{${x[`path`].original}}}`, `{{{${x[`path`].original}}}}`); }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return this.resolve(isObject ? JSON.parse(unresolved) : unresolved, clonedData);
|
|
71
|
+
}
|
|
72
|
+
|
|
50
73
|
return isObject ? JSON.parse(resolved) : resolved;
|
|
51
74
|
};
|
|
52
75
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import Joi, {
|
|
1
|
+
import Joi, { DateSchema, NumberSchema, StringSchema } from "joi";
|
|
2
2
|
import _ from "lodash";
|
|
3
|
-
import { OneOf } from "./types";
|
|
4
|
-
import { where, Where } from "./where";
|
|
5
3
|
import moment from "moment-timezone";
|
|
6
|
-
import axios from "axios";
|
|
7
4
|
import context from "./context";
|
|
5
|
+
import { OneOf } from "./types";
|
|
6
|
+
import { where, Where } from "./where";
|
|
8
7
|
|
|
9
8
|
export type Condition = {
|
|
10
9
|
condition: Where,
|
|
@@ -39,9 +38,10 @@ type InputField<Extend = Record<never, never>> = (
|
|
|
39
38
|
| DateInputField<Extend>
|
|
40
39
|
| TimeInputField<Extend>
|
|
41
40
|
| DictInputField<Extend>
|
|
41
|
+
| FileInputField<Extend>
|
|
42
42
|
) & Extend;
|
|
43
43
|
|
|
44
|
-
type Any = string | number | boolean;
|
|
44
|
+
type Any = string | number | boolean | Any[] | { [key: string]: Any };
|
|
45
45
|
|
|
46
46
|
type AnyInputField<Extend = Record<never, never>> = {
|
|
47
47
|
type: `any`,
|
|
@@ -59,9 +59,9 @@ type StringInputField<Extend = Record<never, never>> = {
|
|
|
59
59
|
max?: number,
|
|
60
60
|
regexp?: string,
|
|
61
61
|
pattern?: `email` | `uri`,
|
|
62
|
+
escape?: boolean,
|
|
62
63
|
} & (
|
|
63
64
|
| SelectField<string, Extend>
|
|
64
|
-
| FileField
|
|
65
65
|
| TextareaField
|
|
66
66
|
| RichTextField
|
|
67
67
|
| {}
|
|
@@ -127,24 +127,34 @@ type DictInputField<Extend = Record<never, never>> = {
|
|
|
127
127
|
unknown?: boolean,
|
|
128
128
|
};
|
|
129
129
|
|
|
130
|
+
export type File = {
|
|
131
|
+
name: string,
|
|
132
|
+
type: string,
|
|
133
|
+
content: string, // base64 encoded content
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
type FileInputField<Extend = Record<never, never>> = {
|
|
137
|
+
type: `file`,
|
|
138
|
+
default?: File | File[],
|
|
139
|
+
accept?: string | string[], // mime type
|
|
140
|
+
} & (
|
|
141
|
+
| SelectField<File, Extend>
|
|
142
|
+
| {}
|
|
143
|
+
);
|
|
144
|
+
|
|
130
145
|
/* select configuration */
|
|
131
|
-
type SelectField<Values = string | number | boolean, Extend = Record<never, never>> = {
|
|
146
|
+
type SelectField<Values = string | number | boolean | File, Extend = Record<never, never>> = {
|
|
132
147
|
format: `select`,
|
|
133
148
|
// el type string representa el nombre de una función del repositorio que devuelve SelectFieldChoice[]
|
|
134
149
|
choices: SelectFieldChoice<Values, Extend>[] | string,
|
|
135
150
|
unknown?: boolean,
|
|
136
151
|
};
|
|
137
152
|
|
|
138
|
-
export type SelectFieldChoice<Values = string | number | boolean, Extend = Record<never, never>> = {
|
|
153
|
+
export type SelectFieldChoice<Values = string | number | boolean | File, Extend = Record<never, never>> = {
|
|
139
154
|
key: string,
|
|
140
155
|
value: Values,
|
|
141
156
|
} & Extend;
|
|
142
157
|
|
|
143
|
-
/* file configuration */
|
|
144
|
-
type FileField = {
|
|
145
|
-
format: `file`,
|
|
146
|
-
};
|
|
147
|
-
|
|
148
158
|
/* textarea configuration */
|
|
149
159
|
type TextareaField = {
|
|
150
160
|
format: `textarea`,
|
|
@@ -201,7 +211,7 @@ const commonFieldSchema = () =>
|
|
|
201
211
|
}),
|
|
202
212
|
});
|
|
203
213
|
|
|
204
|
-
const types = [`any`, `string`, `number`, `boolean`, `date`, `datetime`, `time`, `dict`];
|
|
214
|
+
const types = [`any`, `string`, `number`, `boolean`, `date`, `datetime`, `time`, `dict`, `file`];
|
|
205
215
|
|
|
206
216
|
const inputFieldBaseSchema = () =>
|
|
207
217
|
Joi.object({
|
|
@@ -233,7 +243,13 @@ const defaultSchema = (type: Joi.Schema) =>
|
|
|
233
243
|
});
|
|
234
244
|
|
|
235
245
|
const anySchema = () =>
|
|
236
|
-
Joi.alternatives(
|
|
246
|
+
Joi.alternatives(
|
|
247
|
+
Joi.string(),
|
|
248
|
+
Joi.bool(),
|
|
249
|
+
Joi.number(),
|
|
250
|
+
Joi.array().items(Joi.link(`#any`)),
|
|
251
|
+
Joi.object().pattern(Joi.string(), Joi.link(`#any`)))
|
|
252
|
+
.id(`any`);
|
|
237
253
|
|
|
238
254
|
const anyInputFieldSchema = () =>
|
|
239
255
|
Joi.object({
|
|
@@ -259,7 +275,7 @@ const stringInputFieldSchema = () =>
|
|
|
259
275
|
})
|
|
260
276
|
.concat(
|
|
261
277
|
Joi.object({
|
|
262
|
-
format: Joi.string().valid(`
|
|
278
|
+
format: Joi.string().valid(`select`, `textarea`, `rich-text`),
|
|
263
279
|
choices: Joi.when(`format`, {
|
|
264
280
|
is: `select`,
|
|
265
281
|
then: choicesSchema(Joi.string()).required(),
|
|
@@ -341,6 +357,31 @@ const dictInputFieldSchema = () =>
|
|
|
341
357
|
}),
|
|
342
358
|
});
|
|
343
359
|
|
|
360
|
+
const fileSchema = () => Joi.object({
|
|
361
|
+
name: Joi.string().required(),
|
|
362
|
+
type: Joi.string().required(), // mime type
|
|
363
|
+
content: Joi.string().required(), // base64 encoded content
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const fileInputFieldSchema = () =>
|
|
367
|
+
Joi.object({
|
|
368
|
+
default: defaultSchema(fileSchema()),
|
|
369
|
+
accept: Joi.alternatives(
|
|
370
|
+
Joi.string(),
|
|
371
|
+
Joi.array().items(Joi.string())
|
|
372
|
+
).optional(),
|
|
373
|
+
})
|
|
374
|
+
.concat(
|
|
375
|
+
Joi.object({
|
|
376
|
+
format: Joi.string().valid(`select`),
|
|
377
|
+
choices: Joi.when(`format`, {
|
|
378
|
+
is: `select`,
|
|
379
|
+
then: choicesSchema(fileSchema()).required(),
|
|
380
|
+
otherwise: Joi.forbidden(),
|
|
381
|
+
}),
|
|
382
|
+
})
|
|
383
|
+
);
|
|
384
|
+
|
|
344
385
|
export const fieldSchema = () =>
|
|
345
386
|
inputFieldBaseSchema()
|
|
346
387
|
.id(`field`)
|
|
@@ -372,6 +413,11 @@ export const fieldSchema = () =>
|
|
|
372
413
|
then: inputFieldBaseSchema()
|
|
373
414
|
.concat(dictInputFieldSchema()),
|
|
374
415
|
})
|
|
416
|
+
.when(Joi.object({ type: Joi.valid(`file`) }).unknown(), {
|
|
417
|
+
then: inputFieldBaseSchema()
|
|
418
|
+
.concat(fileInputFieldSchema()),
|
|
419
|
+
})
|
|
420
|
+
// invalid fallback
|
|
375
421
|
.when(Joi.object({ type: Joi.invalid(...types) }).unknown(), {
|
|
376
422
|
then: Joi.forbidden(),
|
|
377
423
|
});
|
|
@@ -401,39 +447,6 @@ const getFieldSchema = (field: Field) => {
|
|
|
401
447
|
if (field.pattern === `email`) { typeSchema = (typeSchema as StringSchema).email(); }
|
|
402
448
|
if (field.pattern === `uri`) { typeSchema = (typeSchema as StringSchema).uri(); }
|
|
403
449
|
|
|
404
|
-
if (`format` in field && field.format === `file`) {
|
|
405
|
-
typeSchema = typeSchema.external(async (value, helpers) => {
|
|
406
|
-
if (!helpers.original && !field.required) { return helpers.original; }
|
|
407
|
-
|
|
408
|
-
const [asURL, asBase64] = await Promise.allSettled([
|
|
409
|
-
(async () => {
|
|
410
|
-
try {
|
|
411
|
-
const { value: url, error } = Joi.string().uri().validate(helpers.original);
|
|
412
|
-
if (error) { throw new Error(`Invalid URL schema`); }
|
|
413
|
-
|
|
414
|
-
const { data: content } = await axios.get(url, { responseType: `arraybuffer` });
|
|
415
|
-
return Buffer.from(content).toString(`base64`);
|
|
416
|
-
} catch (e) { throw e; }
|
|
417
|
-
})(),
|
|
418
|
-
(async () => {
|
|
419
|
-
try {
|
|
420
|
-
// fastest approach: https://stackoverflow.com/a/8571649
|
|
421
|
-
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
|
422
|
-
if (!base64regex.test(helpers.original)) { throw new Error(`Invalid regexp`); }
|
|
423
|
-
return Buffer.from(helpers.original, `base64`).toString(`base64`);
|
|
424
|
-
} catch (e) { throw e; }
|
|
425
|
-
})(),
|
|
426
|
-
]);
|
|
427
|
-
|
|
428
|
-
if (asURL.status === `fulfilled`) {
|
|
429
|
-
return asURL.value;
|
|
430
|
-
} else if (asBase64.status === `fulfilled`) {
|
|
431
|
-
return asBase64.value;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return helpers.message({ external: `invalid value, expected URL or Base64 string` });
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
450
|
break;
|
|
438
451
|
case `date`:
|
|
439
452
|
case `datetime`:
|
|
@@ -473,11 +486,43 @@ const getFieldSchema = (field: Field) => {
|
|
|
473
486
|
}
|
|
474
487
|
break;
|
|
475
488
|
case `dict`:
|
|
489
|
+
let objSchema: Joi.ObjectSchema;
|
|
476
490
|
if (field.items) {
|
|
477
|
-
|
|
491
|
+
objSchema = getFieldsSchema(field.items).unknown(field.unknown || false);
|
|
478
492
|
} else {
|
|
479
|
-
|
|
493
|
+
objSchema = Joi.object().unknown(true);
|
|
480
494
|
}
|
|
495
|
+
|
|
496
|
+
typeSchema = Joi.alternatives(
|
|
497
|
+
objSchema,
|
|
498
|
+
// support for stringified objects
|
|
499
|
+
Joi.string().external(async (value, helpers) => {
|
|
500
|
+
if (!helpers.original && !field.required) { return helpers.original; }
|
|
501
|
+
|
|
502
|
+
const parsed = JSON.parse(value);
|
|
503
|
+
const { value: objValue, error } = objSchema.validate(parsed, { abortEarly: false });
|
|
504
|
+
if (error) { throw error; }
|
|
505
|
+
|
|
506
|
+
return objValue;
|
|
507
|
+
})
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
break;
|
|
511
|
+
case `file`:
|
|
512
|
+
typeSchema = Joi.alternatives(
|
|
513
|
+
fileSchema(),
|
|
514
|
+
// support for stringified objects
|
|
515
|
+
Joi.string().external(async (value, helpers) => {
|
|
516
|
+
if (!helpers.original && !field.required) { return helpers.original; }
|
|
517
|
+
|
|
518
|
+
const parsed = JSON.parse(value);
|
|
519
|
+
const { value: fileValue, error } = fileSchema().validate(parsed, { abortEarly: false });
|
|
520
|
+
if (error) { throw error; }
|
|
521
|
+
|
|
522
|
+
return fileValue;
|
|
523
|
+
})
|
|
524
|
+
);
|
|
525
|
+
|
|
481
526
|
break;
|
|
482
527
|
}
|
|
483
528
|
|
|
@@ -492,11 +537,25 @@ const getFieldSchema = (field: Field) => {
|
|
|
492
537
|
}
|
|
493
538
|
|
|
494
539
|
if (field.as_array) {
|
|
495
|
-
|
|
540
|
+
let arraySchema = Joi.array().items(typeSchema);
|
|
496
541
|
|
|
497
|
-
if (field.array_length) {
|
|
498
|
-
if (field.array_min) {
|
|
499
|
-
if (field.array_max) {
|
|
542
|
+
if (field.array_length) { arraySchema = arraySchema.length(field.array_length); }
|
|
543
|
+
if (field.array_min) { arraySchema = arraySchema.min(field.array_min); }
|
|
544
|
+
if (field.array_max) { arraySchema = arraySchema.max(field.array_max); }
|
|
545
|
+
|
|
546
|
+
typeSchema = Joi.alternatives(
|
|
547
|
+
arraySchema,
|
|
548
|
+
// support for stringified arrays
|
|
549
|
+
Joi.string().external(async (value, helpers) => {
|
|
550
|
+
if (!helpers.original && !field.required) { return helpers.original; }
|
|
551
|
+
|
|
552
|
+
const parsed = JSON.parse(value);
|
|
553
|
+
const { value: arrValue, error } = arraySchema.validate(parsed, { abortEarly: false });
|
|
554
|
+
if (error) { throw error; }
|
|
555
|
+
|
|
556
|
+
return arrValue;
|
|
557
|
+
})
|
|
558
|
+
);
|
|
500
559
|
}
|
|
501
560
|
|
|
502
561
|
if (field.disabled) { typeSchema = typeSchema.forbidden(); }
|
|
@@ -157,6 +157,14 @@ export const localizeProperties = (
|
|
|
157
157
|
description: t(`${element.id}.description`),
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
export const localizeGroup = (
|
|
161
|
+
t: ReturnType<typeof i18n>[`t`],
|
|
162
|
+
element: Action | Trigger,
|
|
163
|
+
): LocalizedProperties => ({
|
|
164
|
+
name: t(`ui.groups.${element.ui.group}.name`, { fallback: true }),
|
|
165
|
+
description: t(`ui.groups.${element.ui.group}.description`),
|
|
166
|
+
});
|
|
167
|
+
|
|
160
168
|
const localizeConnectable = (
|
|
161
169
|
t: ReturnType<typeof i18n>[`t`],
|
|
162
170
|
element: Action | Trigger,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import axios from "axios";
|
|
1
2
|
import Joi from "joi";
|
|
2
3
|
import _ from "lodash";
|
|
3
|
-
import
|
|
4
|
+
import moment from "moment-timezone";
|
|
5
|
+
import { core, SourceFunctions } from "../core";
|
|
4
6
|
import { Credentials } from "../entities/credentials";
|
|
5
7
|
import { Action, Trigger } from "../entities/events";
|
|
6
8
|
import { Provider, providerSchema } from "../entities/provider";
|
|
@@ -52,16 +54,84 @@ const commandSchema = Joi.alternatives(
|
|
|
52
54
|
localeListSchema,
|
|
53
55
|
);
|
|
54
56
|
|
|
57
|
+
const API_SOURCES = (provider: Provider, configuration: Protocol.SourcesConfiguration, context: { organization: string, workspace: number }): SourceFunctions => ({
|
|
58
|
+
register: async (source, data) => {
|
|
59
|
+
try {
|
|
60
|
+
const { data: [created] } = await axios.post(`/api/v1/sources`, {
|
|
61
|
+
organization: context.organization,
|
|
62
|
+
workspace: context.workspace,
|
|
63
|
+
provider: provider.id,
|
|
64
|
+
version: provider.version,
|
|
65
|
+
source: source,
|
|
66
|
+
data: data,
|
|
67
|
+
created_date: moment().format(`YYYY-MM-DDTHH:mm:ssZ`),
|
|
68
|
+
}, {
|
|
69
|
+
baseURL: configuration.host,
|
|
70
|
+
headers: {
|
|
71
|
+
"X-Internal-Token": configuration.token,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (!created || !created.uuid) { throw new Error(`Source registration failed`); }
|
|
75
|
+
return { id: created.uuid };
|
|
76
|
+
} catch (e) { throw e; }
|
|
77
|
+
},
|
|
78
|
+
unregister: async (source, id) => {
|
|
79
|
+
try {
|
|
80
|
+
const { data: [get] } = await axios.post(`/api/v1/sources/list`, {
|
|
81
|
+
organization: context.organization,
|
|
82
|
+
workspace: context.workspace,
|
|
83
|
+
provider: provider.id,
|
|
84
|
+
version: provider.version,
|
|
85
|
+
source: source,
|
|
86
|
+
uuid: id,
|
|
87
|
+
}, {
|
|
88
|
+
baseURL: configuration.host,
|
|
89
|
+
headers: {
|
|
90
|
+
"X-Internal-Token": configuration.token,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
if (!get) { throw new Error(`Source with ID ${id} not found`); }
|
|
94
|
+
|
|
95
|
+
await axios.delete(`/api/v1/sources/${get.id}`, {
|
|
96
|
+
baseURL: configuration.host,
|
|
97
|
+
headers: {
|
|
98
|
+
"X-Internal-Token": configuration.token,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
} catch (e) { throw e; }
|
|
102
|
+
},
|
|
103
|
+
consume: async (source) => {
|
|
104
|
+
try {
|
|
105
|
+
const { data: sources } = await axios.post(`/api/v1/sources/list`, {
|
|
106
|
+
organization: context.organization,
|
|
107
|
+
workspace: context.workspace,
|
|
108
|
+
provider: provider.id,
|
|
109
|
+
version: provider.version,
|
|
110
|
+
source: source,
|
|
111
|
+
}, {
|
|
112
|
+
baseURL: configuration.host,
|
|
113
|
+
headers: {
|
|
114
|
+
"X-Internal-Token": configuration.token,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
return sources.map((s) => ({
|
|
118
|
+
id: s.uuid,
|
|
119
|
+
data: s.data,
|
|
120
|
+
}));
|
|
121
|
+
} catch (e) { throw e; }
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
55
125
|
export class Protocol {
|
|
56
126
|
|
|
57
127
|
private readonly provider: Provider;
|
|
58
|
-
private readonly
|
|
128
|
+
private readonly configuration: Protocol.Configuration;
|
|
59
129
|
|
|
60
|
-
constructor(provider: Provider,
|
|
130
|
+
constructor(provider: Provider, configuration: Protocol.Configuration) {
|
|
61
131
|
const providerValidation = providerSchema().validate(provider);
|
|
62
132
|
if (providerValidation.error) { throw new Error(`Invalid provider for protocol`); }
|
|
63
133
|
this.provider = provider;
|
|
64
|
-
this.
|
|
134
|
+
this.configuration = configuration;
|
|
65
135
|
}
|
|
66
136
|
|
|
67
137
|
public evaluate = async (req: Protocol.Command): Promise<any> => {
|
|
@@ -90,7 +160,7 @@ export class Protocol {
|
|
|
90
160
|
response = Object.values(this.provider.sources || {});
|
|
91
161
|
break;
|
|
92
162
|
case `list:locales`:
|
|
93
|
-
const i18nInstance = i18n({ directory: `${this.path}/locales` });
|
|
163
|
+
const i18nInstance = i18n({ directory: `${this.configuration.path}/locales` });
|
|
94
164
|
response = i18nInstance.i18n.getLocales().map((l) => {
|
|
95
165
|
i18nInstance.i18n.setLocale(l);
|
|
96
166
|
return {
|
|
@@ -109,8 +179,10 @@ export class Protocol {
|
|
|
109
179
|
const invokeInstance = core({
|
|
110
180
|
env: req.context.environment,
|
|
111
181
|
localization: req.context.localization,
|
|
112
|
-
|
|
113
|
-
|
|
182
|
+
sources: API_SOURCES(this.provider, this.configuration.sources, {
|
|
183
|
+
organization: req.context.organization,
|
|
184
|
+
workspace: req.context.workspace,
|
|
185
|
+
}),
|
|
114
186
|
});
|
|
115
187
|
|
|
116
188
|
response = await func(invokeInstance, req.params.configuration);
|
|
@@ -137,6 +209,8 @@ export namespace Protocol {
|
|
|
137
209
|
configuration: Record<string, any>,
|
|
138
210
|
},
|
|
139
211
|
context: {
|
|
212
|
+
organization: string,
|
|
213
|
+
workspace: number,
|
|
140
214
|
environment: Record<string, any>,
|
|
141
215
|
localization: {
|
|
142
216
|
locale: string,
|
|
@@ -166,4 +240,14 @@ export namespace Protocol {
|
|
|
166
240
|
};
|
|
167
241
|
|
|
168
242
|
export type Command = Invoke | CredentialList | ActionList | TriggerList | SourceList | LocaleList;
|
|
243
|
+
|
|
244
|
+
export type SourcesConfiguration = {
|
|
245
|
+
host: string,
|
|
246
|
+
token: string,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export type Configuration = {
|
|
250
|
+
path: string,
|
|
251
|
+
sources: SourcesConfiguration,
|
|
252
|
+
};
|
|
169
253
|
}
|