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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "18.2.3",
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": "An object of machine keys and human values to populate a static dropdown.",
754
- "$ref": "/FieldChoicesSchema"
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": {
@@ -23,6 +23,7 @@ const checks = [
23
23
  require('./pollingThrottle'),
24
24
  require('./AuthFieldisSafe'),
25
25
  require('./inputFieldGroupsConstraints'),
26
+ require('./validateJsonFieldSchema'),
26
27
  ];
27
28
 
28
29
  const runFunctionalConstraints = (definition, mainSchema) => {
@@ -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: {
@@ -13,6 +13,7 @@ module.exports = makeSchema(
13
13
  {
14
14
  type: 'object',
15
15
  minProperties: 1,
16
+ not: { required: ['perform'] },
16
17
  },
17
18
  {
18
19
  type: 'array',
@@ -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
- 'An object of machine keys and human values to populate a static dropdown.',
45
- $ref: FieldChoicesSchema.id,
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.2.3",
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 --inspect-brk test",
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",