zapier-platform-schema 18.2.3 → 18.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/exported-schema.json +62 -7
- package/lib/functional-constraints/index.js +1 -0
- package/lib/functional-constraints/validateJsonFieldSchema.js +254 -0
- package/lib/schemas/AppFlagsSchema.js +1 -1
- package/lib/schemas/FieldChoicesSchema.js +1 -0
- package/lib/schemas/FieldDynamicChoicesSchema.js +54 -0
- package/lib/schemas/JsonSchemaSchema.js +47 -0
- package/lib/schemas/PlainFieldSchema.js +4 -0
- package/lib/schemas/PlainInputFieldSchema.js +66 -3
- package/lib/utils/makeValidator.js +2 -1
- package/package.json +3 -2
package/exported-schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "18.
|
|
2
|
+
"version": "18.4.0",
|
|
3
3
|
"schemas": {
|
|
4
4
|
"AppSchema": {
|
|
5
5
|
"id": "/AppSchema",
|
|
@@ -202,7 +202,10 @@
|
|
|
202
202
|
"oneOf": [
|
|
203
203
|
{
|
|
204
204
|
"type": "object",
|
|
205
|
-
"minProperties": 1
|
|
205
|
+
"minProperties": 1,
|
|
206
|
+
"not": {
|
|
207
|
+
"required": ["perform"]
|
|
208
|
+
}
|
|
206
209
|
},
|
|
207
210
|
{
|
|
208
211
|
"type": "array",
|
|
@@ -252,7 +255,8 @@
|
|
|
252
255
|
"file",
|
|
253
256
|
"password",
|
|
254
257
|
"copy",
|
|
255
|
-
"code"
|
|
258
|
+
"code",
|
|
259
|
+
"json"
|
|
256
260
|
]
|
|
257
261
|
},
|
|
258
262
|
"required": {
|
|
@@ -650,6 +654,26 @@
|
|
|
650
654
|
"type": "string",
|
|
651
655
|
"pattern": "^[a-zA-Z0-9_]+\\.[a-zA-Z0-9_\\s\\[\\]]+(\\.[a-zA-Z0-9_\\s\\[\\]]+(,[a-zA-Z0-9_\\s\\[\\]]+)*)?$"
|
|
652
656
|
},
|
|
657
|
+
"FieldDynamicChoicesSchema": {
|
|
658
|
+
"id": "/FieldDynamicChoicesSchema",
|
|
659
|
+
"description": "Describes dynamic dropdowns powered by a perform function or request.",
|
|
660
|
+
"type": "object",
|
|
661
|
+
"required": ["perform"],
|
|
662
|
+
"properties": {
|
|
663
|
+
"perform": {
|
|
664
|
+
"description": "A function or request that returns choices for this dynamic dropdown.",
|
|
665
|
+
"oneOf": [
|
|
666
|
+
{
|
|
667
|
+
"$ref": "/FunctionSchema"
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"$ref": "/RequestSchema"
|
|
671
|
+
}
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
"additionalProperties": false
|
|
676
|
+
},
|
|
653
677
|
"FieldMetaSchema": {
|
|
654
678
|
"id": "/FieldMetaSchema",
|
|
655
679
|
"type": "object",
|
|
@@ -678,6 +702,12 @@
|
|
|
678
702
|
"minLength": 2,
|
|
679
703
|
"pattern": "^[a-zA-Z]+[a-zA-Z0-9_]*$"
|
|
680
704
|
},
|
|
705
|
+
"JsonSchemaSchema": {
|
|
706
|
+
"id": "/JsonSchemaSchema",
|
|
707
|
+
"description": "A JSON Schema object that describes the expected structure of a JSON value. Validated against JSON Schema Draft 4, 6, or 7 meta-schema (based on the `$schema` field, defaulting to Draft 7) via the validateJsonFieldSchema functional constraint.",
|
|
708
|
+
"type": "object",
|
|
709
|
+
"additionalProperties": true
|
|
710
|
+
},
|
|
681
711
|
"PlainInputFieldSchema": {
|
|
682
712
|
"description": "Field schema specialized for input fields. In addition to the requirements below, the following keys are mutually exclusive:\n\n* `children` & `list`\n* `children` & `dict`\n* `children` & `type`\n* `children` & `placeholder`\n* `children` & `helpText`\n* `children` & `default`\n* `dict` & `list`\n* `dynamic` & `dict`\n* `dynamic` & `choices`",
|
|
683
713
|
"id": "/PlainInputFieldSchema",
|
|
@@ -707,7 +737,8 @@
|
|
|
707
737
|
"file",
|
|
708
738
|
"password",
|
|
709
739
|
"copy",
|
|
710
|
-
"code"
|
|
740
|
+
"code",
|
|
741
|
+
"json"
|
|
711
742
|
]
|
|
712
743
|
},
|
|
713
744
|
"required": {
|
|
@@ -749,9 +780,29 @@
|
|
|
749
780
|
"description": "A reference to a trigger that will power a dynamic dropdown.",
|
|
750
781
|
"$ref": "/RefResourceSchema"
|
|
751
782
|
},
|
|
783
|
+
"dependsOn": {
|
|
784
|
+
"description": "Specifies which other input fields this field depends on. These must be filled before this one becomes enabled, and when their values change, this field's value should be cleared.",
|
|
785
|
+
"type": "array",
|
|
786
|
+
"items": {
|
|
787
|
+
"type": "string"
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
"resource": {
|
|
791
|
+
"description": "Explicitly links this input field to a resource. Use the resource key (e.g., \"spreadsheet\") or dot notation for resource fields (e.g., \"spreadsheet.url\"). If not set for dynamic dropdowns, the resource is derived implicitly from the `dynamic` property.",
|
|
792
|
+
"type": "string",
|
|
793
|
+
"minLength": 1,
|
|
794
|
+
"pattern": "^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)?$"
|
|
795
|
+
},
|
|
752
796
|
"choices": {
|
|
753
|
-
"description": "
|
|
754
|
-
"
|
|
797
|
+
"description": "Describes how to populate this dropdown. Can be a static list or a dynamic object with pagination and search support.",
|
|
798
|
+
"oneOf": [
|
|
799
|
+
{
|
|
800
|
+
"$ref": "/FieldChoicesSchema"
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
"$ref": "/FieldDynamicChoicesSchema"
|
|
804
|
+
}
|
|
805
|
+
]
|
|
755
806
|
},
|
|
756
807
|
"placeholder": {
|
|
757
808
|
"description": "An example value that is not saved.",
|
|
@@ -778,6 +829,10 @@
|
|
|
778
829
|
"group": {
|
|
779
830
|
"description": "References a group key from the operation's inputFieldGroups to organize this field with others.",
|
|
780
831
|
"$ref": "/KeySchema"
|
|
832
|
+
},
|
|
833
|
+
"schema": {
|
|
834
|
+
"description": "A JSON Schema object that describes the expected structure of the JSON value. Only valid when `type` is `json`.",
|
|
835
|
+
"$ref": "/JsonSchemaSchema"
|
|
781
836
|
}
|
|
782
837
|
},
|
|
783
838
|
"additionalProperties": false
|
|
@@ -2152,7 +2207,7 @@
|
|
|
2152
2207
|
"type": "boolean"
|
|
2153
2208
|
},
|
|
2154
2209
|
"skipThrowForStatus": {
|
|
2155
|
-
"description": "Starting in `core` version `10.0.0`, `response.throwForStatus()` was called by default. We introduced a per-request way to opt-out of this behavior. This flag takes that a step further and controls that behavior integration-wide **for requests made using `z.request()`**. Unless they specify otherwise (per-request, or via middleware), [Shorthand requests](https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md#shorthand-http-requests) _always_ call `throwForStatus()`. `z.request()` calls can also ignore this flag if they set `skipThrowForStatus` directly",
|
|
2210
|
+
"description": "Starting in `core` version `10.0.0`, `response.throwForStatus()` was called by default. We introduced a per-request way to opt-out of this behavior. This flag takes that a step further and controls that behavior integration-wide **for requests made using `z.request()`**. Unless they specify otherwise (per-request, or via middleware), [Shorthand requests](https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md#shorthand-http-requests) _always_ call `throwForStatus()`. `z.request()` calls can also ignore this flag if they set `skipThrowForStatus` directly. It is important to note that for oauth2 or session auths with `authRefresh:true`, `401` status codes will throw a `RefreshAuthError` regardless of `skipThrowForStatus`, and will need to be handled manually if intervention is required.",
|
|
2156
2211
|
"type": "boolean"
|
|
2157
2212
|
},
|
|
2158
2213
|
"throwForThrottlingEarly": {
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const jsonschema = require('jsonschema');
|
|
5
|
+
|
|
6
|
+
const JSON_SCHEMA_SCHEMA_ID = '/JsonSchemaSchema';
|
|
7
|
+
const PLAIN_INPUT_FIELD_SCHEMA_ID = '/PlainInputFieldSchema';
|
|
8
|
+
|
|
9
|
+
const actionTypes = ['triggers', 'searches', 'creates', 'bulkReads'];
|
|
10
|
+
const resourceMethods = ['get', 'list', 'hook', 'search', 'create'];
|
|
11
|
+
|
|
12
|
+
// Load supported JSON Schema meta-schemas
|
|
13
|
+
const draft4MetaSchema = require('json-metaschema/draft-04-schema.json');
|
|
14
|
+
const draft6MetaSchema = require('json-metaschema/draft-06-schema.json');
|
|
15
|
+
const draft7MetaSchema = require('json-metaschema/draft-07-schema.json');
|
|
16
|
+
|
|
17
|
+
// Map of supported $schema URIs (without trailing #) to their meta-schemas
|
|
18
|
+
// HTTPS supported but normalized below
|
|
19
|
+
const SUPPORTED_META_SCHEMAS = {
|
|
20
|
+
'http://json-schema.org/draft-04/schema': draft4MetaSchema,
|
|
21
|
+
'http://json-schema.org/draft-06/schema': draft6MetaSchema,
|
|
22
|
+
'http://json-schema.org/draft-07/schema': draft7MetaSchema,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const metaValidator = new jsonschema.Validator();
|
|
26
|
+
|
|
27
|
+
// Translates jsonschema ValidationError from meta-schema validation
|
|
28
|
+
// into a human-readable error message.
|
|
29
|
+
const formatMetaSchemaError = (error, rootPath) => {
|
|
30
|
+
const ALLOWED_TYPE_NAMES = [
|
|
31
|
+
'object',
|
|
32
|
+
'array',
|
|
33
|
+
'string',
|
|
34
|
+
'number',
|
|
35
|
+
'integer',
|
|
36
|
+
'boolean',
|
|
37
|
+
'null',
|
|
38
|
+
];
|
|
39
|
+
const relativePath = error.property.replace(/^instance\.?/, '');
|
|
40
|
+
const fullPath = relativePath ? `${rootPath}.${relativePath}` : rootPath;
|
|
41
|
+
|
|
42
|
+
// "type" field: invalid JSON Schema type value
|
|
43
|
+
if (/\.type$/.test(error.property) || error.property === 'instance.type') {
|
|
44
|
+
if (error.name === 'anyOf') {
|
|
45
|
+
const value = error.instance;
|
|
46
|
+
if (typeof value === 'string') {
|
|
47
|
+
return `${fullPath}: invalid type "${value}". Must be one of: ${ALLOWED_TYPE_NAMES.join(', ')}`;
|
|
48
|
+
}
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
const invalid = value.filter(
|
|
51
|
+
(t) => typeof t !== 'string' || !ALLOWED_TYPE_NAMES.includes(t),
|
|
52
|
+
);
|
|
53
|
+
if (invalid.length > 0) {
|
|
54
|
+
return invalid
|
|
55
|
+
.map(
|
|
56
|
+
(t) =>
|
|
57
|
+
`${fullPath}: invalid type "${t}". Must be one of: ${ALLOWED_TYPE_NAMES.join(', ')}`,
|
|
58
|
+
)
|
|
59
|
+
.join('; ');
|
|
60
|
+
}
|
|
61
|
+
return `${fullPath}: must be a string or array of strings`;
|
|
62
|
+
}
|
|
63
|
+
return `${fullPath}: must be a string or array of strings`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Non-object where a JSON Schema object is expected
|
|
68
|
+
// Draft 7 allows boolean schemas, so argument may be ['object', 'boolean']
|
|
69
|
+
if (
|
|
70
|
+
error.name === 'type' &&
|
|
71
|
+
Array.isArray(error.argument) &&
|
|
72
|
+
error.argument.includes('object')
|
|
73
|
+
) {
|
|
74
|
+
return `${fullPath}: must be a valid JSON Schema object`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Non-array where an array is expected (required, enum, allOf, etc.)
|
|
78
|
+
if (error.name === 'type' && _.isEqual(error.argument, ['array'])) {
|
|
79
|
+
const fieldName = fullPath.split('.').pop();
|
|
80
|
+
return `${fieldName}: must be an array`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// anyOf failure for fields expecting a schema or specific structure
|
|
84
|
+
if (error.name === 'anyOf') {
|
|
85
|
+
const value = error.instance;
|
|
86
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
87
|
+
return `${fullPath}: must be a valid JSON Schema object`;
|
|
88
|
+
}
|
|
89
|
+
return `${fullPath}: must be a valid JSON Schema`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Default fallback
|
|
93
|
+
return `${fullPath}: ${error.message}`;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Resolves which meta-schema to validate against based on the $schema field.
|
|
97
|
+
// Returns { metaSchema, error } where error is a string if $schema is unsupported.
|
|
98
|
+
const resolveMetaSchema = (schema) => {
|
|
99
|
+
if (!schema.$schema) {
|
|
100
|
+
return { metaSchema: draft7MetaSchema, error: null };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof schema.$schema !== 'string') {
|
|
104
|
+
return { metaSchema: null, error: '`$schema` must be a string' };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const normalizedUri = schema.$schema
|
|
108
|
+
.replace(/#$/, '')
|
|
109
|
+
.replace(/^https:/, 'http:');
|
|
110
|
+
const metaSchema = SUPPORTED_META_SCHEMAS[normalizedUri];
|
|
111
|
+
|
|
112
|
+
if (!metaSchema) {
|
|
113
|
+
const supported = Object.keys(SUPPORTED_META_SCHEMAS).join(', ');
|
|
114
|
+
return {
|
|
115
|
+
metaSchema: null,
|
|
116
|
+
error: `unsupported JSON Schema version "${schema.$schema}". Supported versions: ${supported}`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { metaSchema, error: null };
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Validates that an object is a structurally valid JSON schema
|
|
124
|
+
// using the appropriate meta-schema via jsonschema library.
|
|
125
|
+
// Returns an array of error message strings
|
|
126
|
+
const collectSchemaErrors = (schema, rootPath) => {
|
|
127
|
+
if (typeof schema !== 'object' || schema === null || Array.isArray(schema)) {
|
|
128
|
+
return [`${rootPath}: must be a valid JSON Schema object`];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const { metaSchema, error } = resolveMetaSchema(schema);
|
|
132
|
+
if (error) {
|
|
133
|
+
return [`${rootPath}: ${error}`];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result = metaValidator.validate(schema, metaSchema);
|
|
137
|
+
return result.errors.map((err) => formatMetaSchemaError(err, rootPath));
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const checkSchemaField = (field, path) => {
|
|
141
|
+
let errors = [];
|
|
142
|
+
|
|
143
|
+
if (_.has(field, 'schema')) {
|
|
144
|
+
if (field.type !== 'json') {
|
|
145
|
+
errors.push(
|
|
146
|
+
new jsonschema.ValidationError(
|
|
147
|
+
'must have `type` set to `json` when `schema` is provided.',
|
|
148
|
+
field,
|
|
149
|
+
'/PlainInputFieldSchema',
|
|
150
|
+
path,
|
|
151
|
+
'invalidSchema',
|
|
152
|
+
'schema',
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
} else {
|
|
156
|
+
// Root schema type must be object or array, not primitives
|
|
157
|
+
const rootType = field.schema.type;
|
|
158
|
+
if (rootType !== undefined) {
|
|
159
|
+
const types = Array.isArray(rootType) ? rootType : [rootType];
|
|
160
|
+
const invalidTypes = types.filter(
|
|
161
|
+
(t) => t !== 'object' && t !== 'array',
|
|
162
|
+
);
|
|
163
|
+
if (invalidTypes.length > 0) {
|
|
164
|
+
errors.push(
|
|
165
|
+
new jsonschema.ValidationError(
|
|
166
|
+
`has an invalid JSON Schema in \`schema\`: schema: root \`type\` must be "object" or "array", got ${invalidTypes.map((t) => `"${t}"`).join(', ')}`,
|
|
167
|
+
field,
|
|
168
|
+
'/PlainInputFieldSchema',
|
|
169
|
+
path,
|
|
170
|
+
'invalidJsonSchema',
|
|
171
|
+
'schema',
|
|
172
|
+
),
|
|
173
|
+
);
|
|
174
|
+
// Skip meta-schema validation if root type is invalid
|
|
175
|
+
return errors;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const schemaErrors = collectSchemaErrors(field.schema, 'schema');
|
|
180
|
+
schemaErrors.forEach((message) => {
|
|
181
|
+
errors.push(
|
|
182
|
+
new jsonschema.ValidationError(
|
|
183
|
+
`has an invalid JSON Schema in \`schema\`: ${message}`,
|
|
184
|
+
field,
|
|
185
|
+
'/PlainInputFieldSchema',
|
|
186
|
+
path,
|
|
187
|
+
'invalidJsonSchema',
|
|
188
|
+
'schema',
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Recurse into children (nested PlainInputFieldSchema)
|
|
196
|
+
(field.children || []).forEach((child, childIndex) => {
|
|
197
|
+
errors = errors.concat(
|
|
198
|
+
checkSchemaField(child, `${path}.children[${childIndex}]`),
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return errors;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const validateJsonFieldSchema = (definition, mainSchema) => {
|
|
206
|
+
let errors = [];
|
|
207
|
+
|
|
208
|
+
// Handle individual field validation (for auto-tests of examples/antiExamples)
|
|
209
|
+
if (mainSchema.id === PLAIN_INPUT_FIELD_SCHEMA_ID) {
|
|
210
|
+
return checkSchemaField(definition, 'instance');
|
|
211
|
+
} else if (mainSchema.id === JSON_SCHEMA_SCHEMA_ID) {
|
|
212
|
+
return checkSchemaField(
|
|
213
|
+
// Make a fake PlainInputField object so checkSchemaField detects a json type and `schema` property
|
|
214
|
+
{ key: 'placeholder_field_key', type: 'json', schema: definition },
|
|
215
|
+
'instance',
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Handle full app definition validation
|
|
220
|
+
_.each(actionTypes, (actionType) => {
|
|
221
|
+
if (definition[actionType]) {
|
|
222
|
+
_.each(definition[actionType], (actionDef) => {
|
|
223
|
+
if (actionDef.operation && actionDef.operation.inputFields) {
|
|
224
|
+
_.each(actionDef.operation.inputFields, (field, index) => {
|
|
225
|
+
const path = `instance.${actionType}.${actionDef.key}.operation.inputFields[${index}]`;
|
|
226
|
+
errors = errors.concat(checkSchemaField(field, path));
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Handle resources if they exist
|
|
234
|
+
if (definition.resources) {
|
|
235
|
+
_.each(definition.resources, (resource, resourceKey) => {
|
|
236
|
+
resourceMethods.forEach((method) => {
|
|
237
|
+
if (
|
|
238
|
+
resource[method] &&
|
|
239
|
+
resource[method].operation &&
|
|
240
|
+
resource[method].operation.inputFields
|
|
241
|
+
) {
|
|
242
|
+
_.each(resource[method].operation.inputFields, (field, index) => {
|
|
243
|
+
const path = `instance.resources.${resourceKey}.${method}.operation.inputFields[${index}]`;
|
|
244
|
+
errors = errors.concat(checkSchemaField(field, path));
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return errors;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
module.exports = validateJsonFieldSchema;
|
|
@@ -14,7 +14,7 @@ module.exports = makeSchema({
|
|
|
14
14
|
},
|
|
15
15
|
skipThrowForStatus: {
|
|
16
16
|
description:
|
|
17
|
-
'Starting in `core` version `10.0.0`, `response.throwForStatus()` was called by default. We introduced a per-request way to opt-out of this behavior. This flag takes that a step further and controls that behavior integration-wide **for requests made using `z.request()`**. Unless they specify otherwise (per-request, or via middleware), [Shorthand requests](https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md#shorthand-http-requests) _always_ call `throwForStatus()`. `z.request()` calls can also ignore this flag if they set `skipThrowForStatus` directly',
|
|
17
|
+
'Starting in `core` version `10.0.0`, `response.throwForStatus()` was called by default. We introduced a per-request way to opt-out of this behavior. This flag takes that a step further and controls that behavior integration-wide **for requests made using `z.request()`**. Unless they specify otherwise (per-request, or via middleware), [Shorthand requests](https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md#shorthand-http-requests) _always_ call `throwForStatus()`. `z.request()` calls can also ignore this flag if they set `skipThrowForStatus` directly. It is important to note that for oauth2 or session auths with `authRefresh:true`, `401` status codes will throw a `RefreshAuthError` regardless of `skipThrowForStatus`, and will need to be handled manually if intervention is required.',
|
|
18
18
|
type: 'boolean',
|
|
19
19
|
},
|
|
20
20
|
throwForThrottlingEarly: {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
const FunctionSchema = require('./FunctionSchema');
|
|
6
|
+
const RequestSchema = require('./RequestSchema');
|
|
7
|
+
|
|
8
|
+
module.exports = makeSchema(
|
|
9
|
+
{
|
|
10
|
+
id: '/FieldDynamicChoicesSchema',
|
|
11
|
+
description:
|
|
12
|
+
'Describes dynamic dropdowns powered by a perform function or request.',
|
|
13
|
+
type: 'object',
|
|
14
|
+
required: ['perform'],
|
|
15
|
+
properties: {
|
|
16
|
+
perform: {
|
|
17
|
+
description:
|
|
18
|
+
'A function or request that returns choices for this dynamic dropdown.',
|
|
19
|
+
oneOf: [{ $ref: FunctionSchema.id }, { $ref: RequestSchema.id }],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
examples: [
|
|
24
|
+
{ perform: '$func$0$f$' },
|
|
25
|
+
{ perform: { source: 'return []' } },
|
|
26
|
+
{
|
|
27
|
+
perform: {
|
|
28
|
+
method: 'GET',
|
|
29
|
+
url: 'https://api.example.com/choices',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
antiExamples: [
|
|
34
|
+
{
|
|
35
|
+
example: {},
|
|
36
|
+
reason: 'Missing required key: perform',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
example: { someKey: 'value' },
|
|
40
|
+
reason: 'Missing required key: perform',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
example: { perform: 'invalid' },
|
|
44
|
+
reason:
|
|
45
|
+
'Invalid value for key: perform (must be a function or request)',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
example: { perform: '$func$0$f$', unknownKey: 'value' },
|
|
49
|
+
reason: 'Invalid extra property: unknownKey',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
[FunctionSchema, RequestSchema],
|
|
54
|
+
);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const makeSchema = require('../utils/makeSchema');
|
|
4
|
+
|
|
5
|
+
module.exports = makeSchema({
|
|
6
|
+
id: '/JsonSchemaSchema',
|
|
7
|
+
description:
|
|
8
|
+
'A JSON Schema object that describes the expected structure of a JSON value. Validated against JSON Schema Draft 4, 6, or 7 meta-schema (based on the `$schema` field, defaulting to Draft 7) via the validateJsonFieldSchema functional constraint.',
|
|
9
|
+
type: 'object',
|
|
10
|
+
additionalProperties: true,
|
|
11
|
+
examples: [
|
|
12
|
+
{ type: 'object', properties: { name: { type: 'string' } } },
|
|
13
|
+
{ type: 'array', items: { type: 'string' } },
|
|
14
|
+
{},
|
|
15
|
+
{
|
|
16
|
+
allOf: [{ type: 'object' }, { properties: { name: { type: 'string' } } }],
|
|
17
|
+
not: { type: 'array' },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
name: { type: 'string' },
|
|
23
|
+
age: { type: 'integer' },
|
|
24
|
+
},
|
|
25
|
+
required: ['name'],
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
name: { type: 'string' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
antiExamples: [
|
|
37
|
+
{
|
|
38
|
+
example: ['not', 'an', 'object'],
|
|
39
|
+
reason: 'JSON Schema must be an object, not an array',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
example: { type: 'string' },
|
|
43
|
+
reason:
|
|
44
|
+
"JSON Schema type should be an object or an array. If a primitive is needed, use `type: 'string'` on the input field directly",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
@@ -50,6 +50,7 @@ module.exports = makeSchema({
|
|
|
50
50
|
'password',
|
|
51
51
|
'copy',
|
|
52
52
|
'code',
|
|
53
|
+
'json',
|
|
53
54
|
],
|
|
54
55
|
},
|
|
55
56
|
required: {
|
|
@@ -97,6 +98,9 @@ module.exports = makeSchema({
|
|
|
97
98
|
|
|
98
99
|
// 6. A field with type=integer
|
|
99
100
|
{ key: 'abc_int', type: 'integer' },
|
|
101
|
+
|
|
102
|
+
// 7. A field with type=json
|
|
103
|
+
{ key: 'abc_json', type: 'json' },
|
|
100
104
|
],
|
|
101
105
|
antiExamples: [
|
|
102
106
|
{
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
const makeSchema = require('../utils/makeSchema');
|
|
4
4
|
const RefResourceSchema = require('./RefResourceSchema');
|
|
5
5
|
const FieldChoicesSchema = require('./FieldChoicesSchema');
|
|
6
|
+
const FieldDynamicChoicesSchema = require('./FieldDynamicChoicesSchema');
|
|
6
7
|
const PlainFieldSchema = require('./PlainFieldSchema');
|
|
7
8
|
const FieldMetaSchema = require('./FieldMetaSchema');
|
|
8
9
|
const KeySchema = require('./KeySchema');
|
|
10
|
+
const JsonSchemaSchema = require('./JsonSchemaSchema');
|
|
9
11
|
|
|
10
12
|
module.exports = makeSchema(
|
|
11
13
|
{
|
|
@@ -39,10 +41,26 @@ module.exports = makeSchema(
|
|
|
39
41
|
'A reference to a trigger that will power a dynamic dropdown.',
|
|
40
42
|
$ref: RefResourceSchema.id,
|
|
41
43
|
},
|
|
44
|
+
dependsOn: {
|
|
45
|
+
description:
|
|
46
|
+
"Specifies which other input fields this field depends on. These must be filled before this one becomes enabled, and when their values change, this field's value should be cleared.",
|
|
47
|
+
type: 'array',
|
|
48
|
+
items: { type: 'string' },
|
|
49
|
+
},
|
|
50
|
+
resource: {
|
|
51
|
+
description:
|
|
52
|
+
'Explicitly links this input field to a resource. Use the resource key (e.g., "spreadsheet") or dot notation for resource fields (e.g., "spreadsheet.url"). If not set for dynamic dropdowns, the resource is derived implicitly from the `dynamic` property.',
|
|
53
|
+
type: 'string',
|
|
54
|
+
minLength: 1,
|
|
55
|
+
pattern: '^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)?$',
|
|
56
|
+
},
|
|
42
57
|
choices: {
|
|
43
58
|
description:
|
|
44
|
-
'
|
|
45
|
-
|
|
59
|
+
'Describes how to populate this dropdown. Can be a static list or a dynamic object with pagination and search support.',
|
|
60
|
+
oneOf: [
|
|
61
|
+
{ $ref: FieldChoicesSchema.id },
|
|
62
|
+
{ $ref: FieldDynamicChoicesSchema.id },
|
|
63
|
+
],
|
|
46
64
|
},
|
|
47
65
|
placeholder: {
|
|
48
66
|
description: 'An example value that is not saved.',
|
|
@@ -76,6 +94,11 @@ module.exports = makeSchema(
|
|
|
76
94
|
"References a group key from the operation's inputFieldGroups to organize this field with others.",
|
|
77
95
|
$ref: KeySchema.id,
|
|
78
96
|
},
|
|
97
|
+
schema: {
|
|
98
|
+
description:
|
|
99
|
+
'A JSON Schema object that describes the expected structure of the JSON value. Only valid when `type` is `json`.',
|
|
100
|
+
$ref: JsonSchemaSchema.id,
|
|
101
|
+
},
|
|
79
102
|
},
|
|
80
103
|
examples: [
|
|
81
104
|
{ key: 'abc' },
|
|
@@ -85,6 +108,10 @@ module.exports = makeSchema(
|
|
|
85
108
|
key: 'abc',
|
|
86
109
|
choices: [{ label: 'Red', sample: '#f00', value: '#f00' }],
|
|
87
110
|
},
|
|
111
|
+
{
|
|
112
|
+
key: 'abc',
|
|
113
|
+
choices: { perform: '$func$0$f$' },
|
|
114
|
+
},
|
|
88
115
|
{ key: 'abc', children: [{ key: 'abc' }] },
|
|
89
116
|
{ key: 'abc', type: 'integer' },
|
|
90
117
|
{
|
|
@@ -104,6 +131,29 @@ module.exports = makeSchema(
|
|
|
104
131
|
key: 'email',
|
|
105
132
|
group: 'contact',
|
|
106
133
|
},
|
|
134
|
+
{
|
|
135
|
+
key: 'payload',
|
|
136
|
+
type: 'json',
|
|
137
|
+
schema: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {
|
|
140
|
+
name: { type: 'string' },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
key: 'spreadsheet',
|
|
146
|
+
dependsOn: ['folder'],
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
key: 'worksheet',
|
|
150
|
+
dependsOn: ['folder', 'spreadsheet'],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
key: 'spreadsheet_id',
|
|
154
|
+
resource: 'spreadsheet',
|
|
155
|
+
choices: { perform: '$func$0$f$' },
|
|
156
|
+
},
|
|
107
157
|
],
|
|
108
158
|
antiExamples: [
|
|
109
159
|
{
|
|
@@ -137,7 +187,18 @@ module.exports = makeSchema(
|
|
|
137
187
|
reason:
|
|
138
188
|
'Invalid value for key: choices (must be either object or array)',
|
|
139
189
|
},
|
|
140
|
-
|
|
190
|
+
{
|
|
191
|
+
example: { key: 'abc', type: 'string', schema: { type: 'object' } },
|
|
192
|
+
reason: 'schema is only valid when type is json',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
example: {
|
|
196
|
+
key: 'abc',
|
|
197
|
+
type: 'json',
|
|
198
|
+
schema: { type: 'foobar' },
|
|
199
|
+
},
|
|
200
|
+
reason: 'schema must contain a valid JSON Schema (invalid type)',
|
|
201
|
+
},
|
|
141
202
|
{
|
|
142
203
|
example: { key: 'abc', children: ['$func$2$f$'] },
|
|
143
204
|
reason:
|
|
@@ -149,8 +210,10 @@ module.exports = makeSchema(
|
|
|
149
210
|
[
|
|
150
211
|
RefResourceSchema,
|
|
151
212
|
FieldChoicesSchema,
|
|
213
|
+
FieldDynamicChoicesSchema,
|
|
152
214
|
FieldMetaSchema,
|
|
153
215
|
PlainFieldSchema,
|
|
154
216
|
KeySchema,
|
|
217
|
+
JsonSchemaSchema,
|
|
155
218
|
],
|
|
156
219
|
);
|
|
@@ -32,7 +32,8 @@ const makePath = (path, newSegment) =>
|
|
|
32
32
|
const processBaseError = (err, path) => {
|
|
33
33
|
const completePath = makePath(path, err.property)
|
|
34
34
|
.replace(/\.instance\.?/g, '.')
|
|
35
|
-
.replace(/\.instance$/, '')
|
|
35
|
+
.replace(/\.instance$/, '')
|
|
36
|
+
.replace(/\.$/, ''); // Remove any trailing dots
|
|
36
37
|
|
|
37
38
|
const subSchemas = err.message.match(/\[subschema \d+\]/g);
|
|
38
39
|
if (subSchemas) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-schema",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.4.0",
|
|
4
4
|
"description": "Schema definition for CLI apps in the Zapier Developer Platform.",
|
|
5
5
|
"repository": "zapier/zapier-platform",
|
|
6
6
|
"homepage": "https://platform.zapier.com/",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"/schema.js"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
+
"json-metaschema": "1.3.0",
|
|
16
17
|
"jsonschema": "1.5.0",
|
|
17
18
|
"lodash": "4.17.23"
|
|
18
19
|
},
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
"preversion": "git pull && pnpm test && pnpm build",
|
|
27
28
|
"test": "mocha -t 10s --recursive test --exit",
|
|
28
29
|
"smoke-test": "mocha -t 10s --recursive smoke-test --exit",
|
|
29
|
-
"test:debug": "mocha --recursive
|
|
30
|
+
"test:debug": "mocha inspect --recursive test",
|
|
30
31
|
"lint": "eslint lib",
|
|
31
32
|
"lint:fix": "eslint --fix lib",
|
|
32
33
|
"coverage": "istanbul cover _mocha -- --recursive",
|