zapier-platform-schema 11.1.1
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 +3 -0
- package/LICENSE +4 -0
- package/README.md +21 -0
- package/exported-schema.json +1418 -0
- package/lib/constants.js +21 -0
- package/lib/functional-constraints/deepNestedFields.js +68 -0
- package/lib/functional-constraints/index.js +35 -0
- package/lib/functional-constraints/labelWhenVisible.js +31 -0
- package/lib/functional-constraints/matchingKeys.js +35 -0
- package/lib/functional-constraints/mutuallyExclusiveFields.js +70 -0
- package/lib/functional-constraints/requiredSamples.js +56 -0
- package/lib/functional-constraints/searchOrCreateKeys.js +67 -0
- package/lib/functional-constraints/uniqueInputFieldKeys.js +67 -0
- package/lib/schemas/AppFlagsSchema.js +22 -0
- package/lib/schemas/AppSchema.js +148 -0
- package/lib/schemas/AuthenticationBasicConfigSchema.js +14 -0
- package/lib/schemas/AuthenticationCustomConfigSchema.js +14 -0
- package/lib/schemas/AuthenticationDigestConfigSchema.js +14 -0
- package/lib/schemas/AuthenticationOAuth1ConfigSchema.js +53 -0
- package/lib/schemas/AuthenticationOAuth2ConfigSchema.js +73 -0
- package/lib/schemas/AuthenticationSchema.js +118 -0
- package/lib/schemas/AuthenticationSessionConfigSchema.js +31 -0
- package/lib/schemas/BasicActionOperationSchema.js +59 -0
- package/lib/schemas/BasicCreateActionOperationSchema.js +26 -0
- package/lib/schemas/BasicDisplaySchema.js +92 -0
- package/lib/schemas/BasicHookOperationSchema.js +117 -0
- package/lib/schemas/BasicOperationSchema.js +73 -0
- package/lib/schemas/BasicPollingOperationSchema.js +41 -0
- package/lib/schemas/BulkReadSchema.js +72 -0
- package/lib/schemas/BulkReadsSchema.js +69 -0
- package/lib/schemas/BundleSchema.js +17 -0
- package/lib/schemas/CreateSchema.js +108 -0
- package/lib/schemas/CreatesSchema.js +78 -0
- package/lib/schemas/DynamicFieldsSchema.js +36 -0
- package/lib/schemas/FieldChoiceWithLabelSchema.js +37 -0
- package/lib/schemas/FieldChoicesSchema.js +40 -0
- package/lib/schemas/FieldOrFunctionSchema.js +40 -0
- package/lib/schemas/FieldSchema.js +183 -0
- package/lib/schemas/FieldsSchema.js +17 -0
- package/lib/schemas/FlatObjectSchema.js +45 -0
- package/lib/schemas/FunctionRequireSchema.js +28 -0
- package/lib/schemas/FunctionSchema.js +42 -0
- package/lib/schemas/FunctionSourceSchema.js +37 -0
- package/lib/schemas/HydratorsSchema.js +29 -0
- package/lib/schemas/KeySchema.js +30 -0
- package/lib/schemas/MiddlewaresSchema.js +35 -0
- package/lib/schemas/RedirectRequestSchema.js +41 -0
- package/lib/schemas/RefResourceSchema.js +24 -0
- package/lib/schemas/RequestSchema.js +109 -0
- package/lib/schemas/ResourceMethodCreateSchema.js +67 -0
- package/lib/schemas/ResourceMethodGetSchema.js +74 -0
- package/lib/schemas/ResourceMethodHookSchema.js +72 -0
- package/lib/schemas/ResourceMethodListSchema.js +76 -0
- package/lib/schemas/ResourceMethodSearchSchema.js +67 -0
- package/lib/schemas/ResourceSchema.js +168 -0
- package/lib/schemas/ResourcesMethodGetSchema.js +57 -0
- package/lib/schemas/ResourcesSchema.js +95 -0
- package/lib/schemas/ResultsSchema.js +25 -0
- package/lib/schemas/SearchOrCreateSchema.js +84 -0
- package/lib/schemas/SearchOrCreatesSchema.js +60 -0
- package/lib/schemas/SearchSchema.js +84 -0
- package/lib/schemas/SearchesSchema.js +54 -0
- package/lib/schemas/TriggerSchema.js +93 -0
- package/lib/schemas/TriggersSchema.js +61 -0
- package/lib/schemas/VersionSchema.js +18 -0
- package/lib/utils/buildDocs.js +213 -0
- package/lib/utils/exportSchema.js +23 -0
- package/lib/utils/links.js +27 -0
- package/lib/utils/makeSchema.js +27 -0
- package/lib/utils/makeValidator.js +150 -0
- package/package.json +40 -0
- package/schema.js +13 -0
package/lib/constants.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
ROOT_GITHUB: 'https://github.com/zapier/zapier-platform',
|
|
3
|
+
DOCS_PATH: 'docs/build/schema.md',
|
|
4
|
+
DOC_URL_TEMPLATE:
|
|
5
|
+
'https://platform.zapier.com/cli_docs/schema<%= anchor %>@<%= version %>',
|
|
6
|
+
SKIP_KEY: '_skipTest',
|
|
7
|
+
// the following pairs of keys can't be used together in FieldSchema
|
|
8
|
+
// they're stored here because they're used in a few places
|
|
9
|
+
INCOMPATIBLE_FIELD_SCHEMA_KEYS: [
|
|
10
|
+
['children', 'list'], // This is actually a Feature Request (https://github.com/zapier/zapier-platform-cli/issues/115)
|
|
11
|
+
['children', 'dict'], // dict is ignored
|
|
12
|
+
['children', 'type'], // type is ignored
|
|
13
|
+
['children', 'placeholder'], // placeholder is ignored
|
|
14
|
+
['children', 'helpText'], // helpText is ignored
|
|
15
|
+
['children', 'default'], // default is ignored
|
|
16
|
+
['dict', 'list'], // Use only one or the other
|
|
17
|
+
['dynamic', 'dict'], // dict is ignored
|
|
18
|
+
['dynamic', 'choices'], // choices are ignored
|
|
19
|
+
],
|
|
20
|
+
FIELD_SCHEMA_BOOLEANS: new Set(['dict', 'list']),
|
|
21
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
const collectErrors = (inputFields, path) => {
|
|
7
|
+
const errors = [];
|
|
8
|
+
|
|
9
|
+
_.each(inputFields, (inputField, index) => {
|
|
10
|
+
if (inputField.children) {
|
|
11
|
+
if (inputField.children.length === 0) {
|
|
12
|
+
errors.push(
|
|
13
|
+
new jsonschema.ValidationError(
|
|
14
|
+
'must not be empty.',
|
|
15
|
+
inputField,
|
|
16
|
+
'/FieldSchema',
|
|
17
|
+
`instance.${path}.inputFields[${index}].children`,
|
|
18
|
+
'empty',
|
|
19
|
+
'inputFields'
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
} else {
|
|
23
|
+
const hasDeeplyNestedChildren = _.some(
|
|
24
|
+
inputField.children,
|
|
25
|
+
(child) => child.children
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if (hasDeeplyNestedChildren) {
|
|
29
|
+
errors.push(
|
|
30
|
+
new jsonschema.ValidationError(
|
|
31
|
+
'must not contain deeply nested child fields. One level max.',
|
|
32
|
+
inputField,
|
|
33
|
+
'/FieldSchema',
|
|
34
|
+
`instance.${path}.inputFields[${index}]`,
|
|
35
|
+
'deepNesting',
|
|
36
|
+
'inputFields'
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return errors;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const validateFieldNesting = (definition) => {
|
|
48
|
+
let errors = [];
|
|
49
|
+
|
|
50
|
+
_.each(['triggers', 'searches', 'creates'], (typeOf) => {
|
|
51
|
+
if (definition[typeOf]) {
|
|
52
|
+
_.each(definition[typeOf], (actionDef) => {
|
|
53
|
+
if (actionDef.operation && actionDef.operation.inputFields) {
|
|
54
|
+
errors = errors.concat(
|
|
55
|
+
collectErrors(
|
|
56
|
+
actionDef.operation.inputFields,
|
|
57
|
+
`${typeOf}.${actionDef.key}`
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return errors;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = validateFieldNesting;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* Each check below is expected to return a list of ValidationSchema errors. An error is defined by:
|
|
4
|
+
* new jsonschema.ValidationError(
|
|
5
|
+
* message, // string that explains the problem, like 'must not have a URL that points to AWS'
|
|
6
|
+
* instance, // the snippet of the app defintion that is invalid
|
|
7
|
+
* schema, // name of the schema that failed, like '/TriggerSchema'
|
|
8
|
+
* propertyPath, // stringified path to problematic snippet, like 'instance.triggers.find_contact'
|
|
9
|
+
* name, // optional, the validation type that failed. Can make something up like 'invalidUrl'
|
|
10
|
+
* argument // optional
|
|
11
|
+
* );
|
|
12
|
+
*/
|
|
13
|
+
const checks = [
|
|
14
|
+
require('./searchOrCreateKeys'),
|
|
15
|
+
require('./deepNestedFields'),
|
|
16
|
+
require('./mutuallyExclusiveFields'),
|
|
17
|
+
require('./requiredSamples'),
|
|
18
|
+
require('./matchingKeys'),
|
|
19
|
+
require('./labelWhenVisible'),
|
|
20
|
+
require('./uniqueInputFieldKeys'),
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const runFunctionalConstraints = (definition, mainSchema) => {
|
|
24
|
+
return checks.reduce((errors, checkFunc) => {
|
|
25
|
+
const errorsForCheck = checkFunc(definition, mainSchema);
|
|
26
|
+
if (errorsForCheck) {
|
|
27
|
+
errors = errors.concat(errorsForCheck);
|
|
28
|
+
}
|
|
29
|
+
return errors;
|
|
30
|
+
}, []);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
run: runFunctionalConstraints,
|
|
35
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const jsonschema = require('jsonschema');
|
|
3
|
+
|
|
4
|
+
const actionTypes = ['triggers', 'searches', 'creates'];
|
|
5
|
+
|
|
6
|
+
const labelWhenVisible = (definition) => {
|
|
7
|
+
const errors = [];
|
|
8
|
+
|
|
9
|
+
for (const actionType of actionTypes) {
|
|
10
|
+
const group = definition[actionType] || {};
|
|
11
|
+
_.each(group, (action, key) => {
|
|
12
|
+
const { display } = action;
|
|
13
|
+
if (!display.hidden && !(display.label && display.description)) {
|
|
14
|
+
errors.push(
|
|
15
|
+
new jsonschema.ValidationError(
|
|
16
|
+
`visible actions must have a label and description`,
|
|
17
|
+
action,
|
|
18
|
+
`/BasicDisplaySchema`,
|
|
19
|
+
`instance.${actionType}.${key}.display`,
|
|
20
|
+
'invalid',
|
|
21
|
+
'key'
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return errors;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = labelWhenVisible;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
const actionTypes = ['triggers', 'searches', 'creates'];
|
|
7
|
+
|
|
8
|
+
const matchingKeys = (definition) => {
|
|
9
|
+
const errors = [];
|
|
10
|
+
|
|
11
|
+
// verifies that x.key === x
|
|
12
|
+
// otherwise, we double results in the compiled app via core's compileApp
|
|
13
|
+
|
|
14
|
+
for (const actionType of actionTypes) {
|
|
15
|
+
const group = definition[actionType] || {};
|
|
16
|
+
_.each(group, (action, key) => {
|
|
17
|
+
if (action.key !== key) {
|
|
18
|
+
errors.push(
|
|
19
|
+
new jsonschema.ValidationError(
|
|
20
|
+
`must have a matching top-level key (found "${key}" and "${action.key}")`,
|
|
21
|
+
action,
|
|
22
|
+
`/${_.capitalize(actionType)}Schema`,
|
|
23
|
+
`instance.${key}.key`,
|
|
24
|
+
'invalid',
|
|
25
|
+
'key'
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return errors;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
module.exports = matchingKeys;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
// NOTE: While it would be possible to accomplish this with a solution like
|
|
7
|
+
// https://stackoverflow.com/questions/28162509/mutually-exclusive-property-groups#28172831
|
|
8
|
+
// it was harder to read and understand.
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
INCOMPATIBLE_FIELD_SCHEMA_KEYS,
|
|
12
|
+
FIELD_SCHEMA_BOOLEANS,
|
|
13
|
+
} = require('../constants');
|
|
14
|
+
|
|
15
|
+
const verifyIncompatibilities = (inputFields, path) => {
|
|
16
|
+
const errors = [];
|
|
17
|
+
|
|
18
|
+
_.each(inputFields, (inputField, index) => {
|
|
19
|
+
_.each(INCOMPATIBLE_FIELD_SCHEMA_KEYS, ([firstField, secondField]) => {
|
|
20
|
+
if (_.has(inputField, firstField) && _.has(inputField, secondField)) {
|
|
21
|
+
// this could be ok if it's a boolean field and is falsy
|
|
22
|
+
// i'm reasonably sure that the editor handles this fine, but if it also checks
|
|
23
|
+
// for the existence of the property (not the truthiness), then there could be an issue
|
|
24
|
+
if (
|
|
25
|
+
(FIELD_SCHEMA_BOOLEANS.has(firstField) && !inputField[firstField]) ||
|
|
26
|
+
(FIELD_SCHEMA_BOOLEANS.has(secondField) && !inputField[secondField])
|
|
27
|
+
) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
errors.push(
|
|
32
|
+
new jsonschema.ValidationError(
|
|
33
|
+
`must not contain ${firstField} and ${secondField}, as they're mutually exclusive.`,
|
|
34
|
+
inputField,
|
|
35
|
+
'/FieldSchema',
|
|
36
|
+
`instance.${path}.inputFields[${index}]`,
|
|
37
|
+
'invalid',
|
|
38
|
+
'inputFields'
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return errors;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const mutuallyExclusiveFields = (definition) => {
|
|
49
|
+
let errors = [];
|
|
50
|
+
|
|
51
|
+
_.each(['triggers', 'searches', 'creates'], (typeOf) => {
|
|
52
|
+
if (definition[typeOf]) {
|
|
53
|
+
_.each(definition[typeOf], (actionDef) => {
|
|
54
|
+
if (actionDef.operation && actionDef.operation.inputFields) {
|
|
55
|
+
errors = [
|
|
56
|
+
...errors,
|
|
57
|
+
...verifyIncompatibilities(
|
|
58
|
+
actionDef.operation.inputFields,
|
|
59
|
+
`${typeOf}.${actionDef.key}`
|
|
60
|
+
),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return errors;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
module.exports = mutuallyExclusiveFields;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
// todo: deal with circular dep.
|
|
7
|
+
const RESOURCE_ID = '/ResourceSchema';
|
|
8
|
+
const RESOURCE_METHODS = ['get', 'hook', 'list', 'search', 'create'];
|
|
9
|
+
|
|
10
|
+
const check = (definition) => {
|
|
11
|
+
if (!definition.operation || _.get(definition, 'display.hidden')) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const samples = _.get(definition, 'operation.sample', {});
|
|
16
|
+
return !_.isEmpty(samples)
|
|
17
|
+
? null
|
|
18
|
+
: new jsonschema.ValidationError(
|
|
19
|
+
'requires "sample", because it\'s not hidden',
|
|
20
|
+
definition,
|
|
21
|
+
definition.id
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports = (definition, mainSchema) => {
|
|
26
|
+
let definitions = [];
|
|
27
|
+
|
|
28
|
+
if (mainSchema.id === RESOURCE_ID) {
|
|
29
|
+
definitions = RESOURCE_METHODS.map((method) => definition[method]).filter(
|
|
30
|
+
Boolean
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// allow method definitions to inherit the sample
|
|
34
|
+
if (definition.sample) {
|
|
35
|
+
definitions.forEach((methodDefinition) => {
|
|
36
|
+
if (methodDefinition.operation && !methodDefinition.operation.sample) {
|
|
37
|
+
methodDefinition.operation.sample = definition.sample;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!definitions.length) {
|
|
43
|
+
return [
|
|
44
|
+
new jsonschema.ValidationError(
|
|
45
|
+
'expected at least one resource operation',
|
|
46
|
+
definition,
|
|
47
|
+
definition.id
|
|
48
|
+
),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
definitions = [definition];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return definitions.map(check).filter(Boolean);
|
|
56
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
const validateSearchOrCreateKeys = (definition) => {
|
|
7
|
+
if (!definition.searchOrCreates) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const errors = [];
|
|
12
|
+
|
|
13
|
+
const searchKeys = _.keys(definition.searches);
|
|
14
|
+
const createKeys = _.keys(definition.creates);
|
|
15
|
+
|
|
16
|
+
_.each(definition.searchOrCreates, (searchOrCreateDef, key) => {
|
|
17
|
+
const searchOrCreateKey = searchOrCreateDef.key;
|
|
18
|
+
const searchKey = searchOrCreateDef.search;
|
|
19
|
+
const createKey = searchOrCreateDef.create;
|
|
20
|
+
|
|
21
|
+
// Confirm searchOrCreate.key matches a searches.key (current Zapier editor limitation)
|
|
22
|
+
if (!definition.searches[searchOrCreateKey]) {
|
|
23
|
+
errors.push(
|
|
24
|
+
new jsonschema.ValidationError(
|
|
25
|
+
`must match a "key" from a search (options: ${searchKeys})`,
|
|
26
|
+
searchOrCreateDef,
|
|
27
|
+
'/SearchOrCreateSchema',
|
|
28
|
+
`instance.searchOrCreates.${key}.key`,
|
|
29
|
+
'invalidKey',
|
|
30
|
+
'key'
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Confirm searchOrCreate.search matches a searches.key
|
|
36
|
+
if (!definition.searches[searchKey]) {
|
|
37
|
+
errors.push(
|
|
38
|
+
new jsonschema.ValidationError(
|
|
39
|
+
`must match a "key" from a search (options: ${searchKeys})`,
|
|
40
|
+
searchOrCreateDef,
|
|
41
|
+
'/SearchOrCreateSchema',
|
|
42
|
+
`instance.searchOrCreates.${key}.search`,
|
|
43
|
+
'invalidKey',
|
|
44
|
+
'search'
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Confirm searchOrCreate.create matches a creates.key
|
|
50
|
+
if (!definition.creates[createKey]) {
|
|
51
|
+
errors.push(
|
|
52
|
+
new jsonschema.ValidationError(
|
|
53
|
+
`must match a "key" from a create (options: ${createKeys})`,
|
|
54
|
+
searchOrCreateDef,
|
|
55
|
+
'/SearchOrCreateSchema',
|
|
56
|
+
`instance.searchOrCreates.${key}.create`,
|
|
57
|
+
'invalidKey',
|
|
58
|
+
'create'
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return errors;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
module.exports = validateSearchOrCreateKeys;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
const actionTypes = ['triggers', 'searches', 'creates'];
|
|
7
|
+
|
|
8
|
+
const uniqueInputFieldKeys = (definition) => {
|
|
9
|
+
const errors = [];
|
|
10
|
+
for (const actionType of actionTypes) {
|
|
11
|
+
const group = definition[actionType] || {};
|
|
12
|
+
_.each(group, (action, key) => {
|
|
13
|
+
const inputFields = _.get(action, ['operation', 'inputFields'], []);
|
|
14
|
+
|
|
15
|
+
const existingKeys = {}; // map of key to where it already lives
|
|
16
|
+
|
|
17
|
+
inputFields.forEach((inputField, index) => {
|
|
18
|
+
// could be a string or a non-field object (`source` or `require` function obj)
|
|
19
|
+
if (!inputField.key) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (existingKeys[inputField.key]) {
|
|
24
|
+
errors.push(
|
|
25
|
+
new jsonschema.ValidationError(
|
|
26
|
+
`inputField keys must be unique for each action. The key "${
|
|
27
|
+
inputField.key
|
|
28
|
+
}" is already in use at ${actionType}.${key}.operation.${
|
|
29
|
+
existingKeys[inputField.key]
|
|
30
|
+
}.key`,
|
|
31
|
+
inputField.key,
|
|
32
|
+
`/BasicOperationSchema`,
|
|
33
|
+
`instance.${actionType}.${key}.operation.inputFields[${index}].key`
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
} else {
|
|
37
|
+
existingKeys[inputField.key] = `inputFields[${index}]`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
(inputField.children || []).forEach((subField, subFieldIndex) => {
|
|
41
|
+
if (existingKeys[subField.key]) {
|
|
42
|
+
errors.push(
|
|
43
|
+
new jsonschema.ValidationError(
|
|
44
|
+
`inputField keys must be unique for each action, even if they're children. The key "${
|
|
45
|
+
subField.key
|
|
46
|
+
}" is already in use at ${actionType}.${key}.operation.${
|
|
47
|
+
existingKeys[subField.key]
|
|
48
|
+
}.key`,
|
|
49
|
+
subField.key,
|
|
50
|
+
`/BasicOperationSchema`,
|
|
51
|
+
`instance.${actionType}.${key}.operation.inputFields[${index}].children[${subFieldIndex}].key`
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
existingKeys[
|
|
56
|
+
subField.key
|
|
57
|
+
] = `inputFields[${index}].children[${subFieldIndex}]`;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return errors;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
module.exports = uniqueInputFieldKeys;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
module.exports = makeSchema({
|
|
6
|
+
id: '/AppFlagsSchema',
|
|
7
|
+
description: 'Codifies high-level options for your app.',
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
skipHttpPatch: {
|
|
11
|
+
description:
|
|
12
|
+
"By default, Zapier patches the core `http` module so that all requests (including those from 3rd-party SDKs) can be logged. Set this to true if you're seeing issues using an SDK (such as AWS).",
|
|
13
|
+
type: 'boolean',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
examples: [{ skipHttpPatch: true }, { skipHttpPatch: false }, {}],
|
|
18
|
+
antiExamples: [
|
|
19
|
+
{ example: { foo: true }, reason: 'Invalid key.' },
|
|
20
|
+
{ example: { skipHttpPatch: 'yes' }, reason: 'Invalid value.' },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
const AuthenticationSchema = require('./AuthenticationSchema');
|
|
6
|
+
const FlatObjectSchema = require('./FlatObjectSchema');
|
|
7
|
+
const ResourcesSchema = require('./ResourcesSchema');
|
|
8
|
+
const TriggersSchema = require('./TriggersSchema');
|
|
9
|
+
const ReadBulksSchema = require('./BulkReadsSchema');
|
|
10
|
+
const SearchesSchema = require('./SearchesSchema');
|
|
11
|
+
const CreatesSchema = require('./CreatesSchema');
|
|
12
|
+
const SearchOrCreatesSchema = require('./SearchOrCreatesSchema');
|
|
13
|
+
const RequestSchema = require('./RequestSchema');
|
|
14
|
+
const VersionSchema = require('./VersionSchema');
|
|
15
|
+
const MiddlewaresSchema = require('./MiddlewaresSchema');
|
|
16
|
+
const HydratorsSchema = require('./HydratorsSchema');
|
|
17
|
+
const AppFlagsSchema = require('./AppFlagsSchema');
|
|
18
|
+
|
|
19
|
+
module.exports = makeSchema(
|
|
20
|
+
{
|
|
21
|
+
id: '/AppSchema',
|
|
22
|
+
description: 'Represents a full app.',
|
|
23
|
+
type: 'object',
|
|
24
|
+
required: ['version', 'platformVersion'],
|
|
25
|
+
properties: {
|
|
26
|
+
version: {
|
|
27
|
+
description: 'A version identifier for your code.',
|
|
28
|
+
$ref: VersionSchema.id,
|
|
29
|
+
},
|
|
30
|
+
platformVersion: {
|
|
31
|
+
description:
|
|
32
|
+
'A version identifier for the Zapier execution environment.',
|
|
33
|
+
$ref: VersionSchema.id,
|
|
34
|
+
},
|
|
35
|
+
beforeApp: {
|
|
36
|
+
description:
|
|
37
|
+
'EXPERIMENTAL: Before the perform method is called on your app, you can modify the execution context.',
|
|
38
|
+
$ref: MiddlewaresSchema.id,
|
|
39
|
+
},
|
|
40
|
+
afterApp: {
|
|
41
|
+
description:
|
|
42
|
+
'EXPERIMENTAL: After the perform method is called on your app, you can modify the response.',
|
|
43
|
+
$ref: MiddlewaresSchema.id,
|
|
44
|
+
},
|
|
45
|
+
authentication: {
|
|
46
|
+
description: 'Choose what scheme your API uses for authentication.',
|
|
47
|
+
$ref: AuthenticationSchema.id,
|
|
48
|
+
},
|
|
49
|
+
requestTemplate: {
|
|
50
|
+
description:
|
|
51
|
+
'Define a request mixin, great for setting custom headers, content-types, etc.',
|
|
52
|
+
$ref: RequestSchema.id,
|
|
53
|
+
},
|
|
54
|
+
beforeRequest: {
|
|
55
|
+
description:
|
|
56
|
+
'Before an HTTP request is sent via our `z.request()` client, you can modify it.',
|
|
57
|
+
$ref: MiddlewaresSchema.id,
|
|
58
|
+
},
|
|
59
|
+
afterResponse: {
|
|
60
|
+
description:
|
|
61
|
+
'After an HTTP response is recieved via our `z.request()` client, you can modify it.',
|
|
62
|
+
$ref: MiddlewaresSchema.id,
|
|
63
|
+
},
|
|
64
|
+
hydrators: {
|
|
65
|
+
description:
|
|
66
|
+
"An optional bank of named functions that you can use in `z.hydrate('someName')` to lazily load data.",
|
|
67
|
+
$ref: HydratorsSchema.id,
|
|
68
|
+
},
|
|
69
|
+
resources: {
|
|
70
|
+
description:
|
|
71
|
+
'All the resources for your app. Zapier will take these and generate the relevent triggers/searches/creates automatically.',
|
|
72
|
+
$ref: ResourcesSchema.id,
|
|
73
|
+
},
|
|
74
|
+
triggers: {
|
|
75
|
+
description:
|
|
76
|
+
'All the triggers for your app. You can add your own here, or Zapier will automatically register any from the list/hook methods on your resources.',
|
|
77
|
+
$ref: TriggersSchema.id,
|
|
78
|
+
},
|
|
79
|
+
bulkReads: {
|
|
80
|
+
description:
|
|
81
|
+
'All of the read bulks (GETs) your app exposes to retrieve resources in batches.',
|
|
82
|
+
$ref: ReadBulksSchema.id,
|
|
83
|
+
},
|
|
84
|
+
searches: {
|
|
85
|
+
description:
|
|
86
|
+
'All the searches for your app. You can add your own here, or Zapier will automatically register any from the search method on your resources.',
|
|
87
|
+
$ref: SearchesSchema.id,
|
|
88
|
+
},
|
|
89
|
+
creates: {
|
|
90
|
+
description:
|
|
91
|
+
'All the creates for your app. You can add your own here, or Zapier will automatically register any from the create method on your resources.',
|
|
92
|
+
$ref: CreatesSchema.id,
|
|
93
|
+
},
|
|
94
|
+
searchOrCreates: {
|
|
95
|
+
description:
|
|
96
|
+
'All the search-or-create combos for your app. You can create your own here, or Zapier will automatically register any from resources that define a search, a create, and a get (or define a searchOrCreate directly). Register non-resource search-or-creates here as well.',
|
|
97
|
+
$ref: SearchOrCreatesSchema.id,
|
|
98
|
+
},
|
|
99
|
+
flags: {
|
|
100
|
+
description: 'Top-level app options',
|
|
101
|
+
$ref: AppFlagsSchema.id,
|
|
102
|
+
},
|
|
103
|
+
legacy: {
|
|
104
|
+
description:
|
|
105
|
+
'**INTERNAL USE ONLY**. Zapier uses this to hold properties from a legacy Web Builder app.',
|
|
106
|
+
type: 'object',
|
|
107
|
+
docAnnotation: {
|
|
108
|
+
hide: true,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
firehoseWebhooks: {
|
|
112
|
+
description:
|
|
113
|
+
'**INTERNAL USE ONLY**. Zapier uses this for internal webhook app configurations.',
|
|
114
|
+
type: 'object',
|
|
115
|
+
docAnnotation: {
|
|
116
|
+
hide: true,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
additionalProperties: false,
|
|
121
|
+
examples: [{ version: '1.0.0', platformVersion: '10.1.2' }],
|
|
122
|
+
antiExamples: [
|
|
123
|
+
{
|
|
124
|
+
example: { version: 'v1.0.0', platformVersion: '10.1.2' },
|
|
125
|
+
reason: 'Invalid value for version.',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
example: { version: '1.0.0', platformVersion: 'v10.1.2' },
|
|
129
|
+
reason: 'Invalid value for platformVersion.',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
[
|
|
134
|
+
AuthenticationSchema,
|
|
135
|
+
FlatObjectSchema,
|
|
136
|
+
ResourcesSchema,
|
|
137
|
+
ReadBulksSchema,
|
|
138
|
+
TriggersSchema,
|
|
139
|
+
SearchesSchema,
|
|
140
|
+
CreatesSchema,
|
|
141
|
+
SearchOrCreatesSchema,
|
|
142
|
+
RequestSchema,
|
|
143
|
+
VersionSchema,
|
|
144
|
+
MiddlewaresSchema,
|
|
145
|
+
HydratorsSchema,
|
|
146
|
+
AppFlagsSchema,
|
|
147
|
+
]
|
|
148
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
module.exports = makeSchema({
|
|
6
|
+
id: '/AuthenticationBasicConfigSchema',
|
|
7
|
+
description:
|
|
8
|
+
'Config for Basic Authentication. No extra properties are required to setup Basic Auth, so you can leave this empty if your app uses Basic Auth.',
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {},
|
|
11
|
+
additionalProperties: false,
|
|
12
|
+
examples: [{}],
|
|
13
|
+
antiExamples: [{ example: { foo: true }, reason: 'Invalid key.' }],
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
module.exports = makeSchema({
|
|
6
|
+
id: '/AuthenticationCustomConfigSchema',
|
|
7
|
+
description:
|
|
8
|
+
'Config for custom authentication (like API keys). No extra properties are required to setup this auth type, so you can leave this empty if your app uses a custom auth method.',
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {},
|
|
11
|
+
additionalProperties: false,
|
|
12
|
+
examples: [{}],
|
|
13
|
+
antiExamples: [{ example: { foo: true }, reason: 'Invalid key.' }],
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
module.exports = makeSchema({
|
|
6
|
+
id: '/AuthenticationDigestConfigSchema',
|
|
7
|
+
description:
|
|
8
|
+
'Config for Digest Authentication. No extra properties are required to setup Digest Auth, so you can leave this empty if your app uses Digets Auth.',
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {},
|
|
11
|
+
additionalProperties: false,
|
|
12
|
+
examples: [{}],
|
|
13
|
+
antiExamples: [{ example: { foo: true }, reason: 'Invalid key.' }],
|
|
14
|
+
});
|