zapier-platform-schema 17.2.0 → 17.3.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": "17.2.0",
2
+ "version": "17.3.0",
3
3
  "schemas": {
4
4
  "AppSchema": {
5
5
  "id": "/AppSchema",
@@ -669,6 +669,13 @@
669
669
  }
670
670
  }
671
671
  },
672
+ "KeySchema": {
673
+ "id": "/KeySchema",
674
+ "description": "A unique identifier for this item.",
675
+ "type": "string",
676
+ "minLength": 2,
677
+ "pattern": "^[a-zA-Z]+[a-zA-Z0-9_]*$"
678
+ },
672
679
  "PlainInputFieldSchema": {
673
680
  "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`",
674
681
  "id": "/PlainInputFieldSchema",
@@ -765,6 +772,10 @@
765
772
  "meta": {
766
773
  "description": "Allows for additional metadata to be stored on the field. Supports simple key-values only (no sub-objects or arrays).",
767
774
  "$ref": "/FieldMetaSchema"
775
+ },
776
+ "group": {
777
+ "description": "References a group key from the operation's inputFieldGroups to organize this field with others.",
778
+ "$ref": "/KeySchema"
768
779
  }
769
780
  },
770
781
  "additionalProperties": false
@@ -875,6 +886,31 @@
875
886
  ]
876
887
  }
877
888
  },
889
+ "InputFieldGroupsSchema": {
890
+ "id": "/InputFieldGroupsSchema",
891
+ "description": "An array or collection of input field groups.",
892
+ "type": "array",
893
+ "items": {
894
+ "type": "object",
895
+ "required": ["key"],
896
+ "properties": {
897
+ "key": {
898
+ "description": "The unique identifier for this group.",
899
+ "$ref": "/KeySchema"
900
+ },
901
+ "label": {
902
+ "description": "The human-readable name for the group.",
903
+ "type": "string",
904
+ "minLength": 1
905
+ },
906
+ "emphasize": {
907
+ "description": "Whether this group should be visually emphasized in the UI.",
908
+ "type": "boolean"
909
+ }
910
+ }
911
+ },
912
+ "additionalProperties": false
913
+ },
878
914
  "OutputFieldsSchema": {
879
915
  "id": "/OutputFieldsSchema",
880
916
  "description": "An array or collection of output fields.",
@@ -890,13 +926,6 @@
890
926
  ]
891
927
  }
892
928
  },
893
- "KeySchema": {
894
- "id": "/KeySchema",
895
- "description": "A unique identifier for this item.",
896
- "type": "string",
897
- "minLength": 2,
898
- "pattern": "^[a-zA-Z]+[a-zA-Z0-9_]*$"
899
- },
900
929
  "LockObjectSchema": {
901
930
  "id": "/LockObjectSchema",
902
931
  "description": "Zapier uses this configuration to ensure this action is performed one at a time per scope (avoid concurrency).",
@@ -1046,6 +1075,10 @@
1046
1075
  "description": "What should the form a user sees and configures look like?",
1047
1076
  "$ref": "/InputFieldsSchema"
1048
1077
  },
1078
+ "inputFieldGroups": {
1079
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1080
+ "$ref": "/InputFieldGroupsSchema"
1081
+ },
1049
1082
  "outputFields": {
1050
1083
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1051
1084
  "$ref": "/OutputFieldsSchema"
@@ -1156,6 +1189,10 @@
1156
1189
  "description": "What should the form a user sees and configures look like?",
1157
1190
  "$ref": "/InputFieldsSchema"
1158
1191
  },
1192
+ "inputFieldGroups": {
1193
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1194
+ "$ref": "/InputFieldGroupsSchema"
1195
+ },
1159
1196
  "outputFields": {
1160
1197
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1161
1198
  "$ref": "/OutputFieldsSchema"
@@ -1209,6 +1246,10 @@
1209
1246
  "description": "What should the form a user sees and configures look like?",
1210
1247
  "$ref": "/InputFieldsSchema"
1211
1248
  },
1249
+ "inputFieldGroups": {
1250
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1251
+ "$ref": "/InputFieldGroupsSchema"
1252
+ },
1212
1253
  "outputFields": {
1213
1254
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1214
1255
  "$ref": "/OutputFieldsSchema"
@@ -1271,6 +1312,10 @@
1271
1312
  "description": "What should the form a user sees and configures look like?",
1272
1313
  "$ref": "/InputFieldsSchema"
1273
1314
  },
1315
+ "inputFieldGroups": {
1316
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1317
+ "$ref": "/InputFieldGroupsSchema"
1318
+ },
1274
1319
  "outputFields": {
1275
1320
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1276
1321
  "$ref": "/OutputFieldsSchema"
@@ -1513,6 +1558,10 @@
1513
1558
  "description": "What should the form a user sees and configures look like?",
1514
1559
  "$ref": "/InputFieldsSchema"
1515
1560
  },
1561
+ "inputFieldGroups": {
1562
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1563
+ "$ref": "/InputFieldGroupsSchema"
1564
+ },
1516
1565
  "outputFields": {
1517
1566
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1518
1567
  "$ref": "/OutputFieldsSchema"
@@ -1615,6 +1664,10 @@
1615
1664
  "description": "What should the form a user sees and configures look like?",
1616
1665
  "$ref": "/InputFieldsSchema"
1617
1666
  },
1667
+ "inputFieldGroups": {
1668
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1669
+ "$ref": "/InputFieldGroupsSchema"
1670
+ },
1618
1671
  "outputFields": {
1619
1672
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1620
1673
  "$ref": "/OutputFieldsSchema"
@@ -1731,6 +1784,10 @@
1731
1784
  "description": "What should the form a user sees and configures look like?",
1732
1785
  "$ref": "/InputFieldsSchema"
1733
1786
  },
1787
+ "inputFieldGroups": {
1788
+ "description": "Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.",
1789
+ "$ref": "/InputFieldGroupsSchema"
1790
+ },
1734
1791
  "outputFields": {
1735
1792
  "description": "What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.",
1736
1793
  "$ref": "/OutputFieldsSchema"
@@ -22,6 +22,7 @@ const checks = [
22
22
  require('./requirePerformConditionally'),
23
23
  require('./pollingThrottle'),
24
24
  require('./AuthFieldisSafe'),
25
+ require('./inputFieldGroupsConstraints'),
25
26
  ];
26
27
 
27
28
  const runFunctionalConstraints = (definition, mainSchema) => {
@@ -0,0 +1,144 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const jsonschema = require('jsonschema');
5
+
6
+ const actionTypes = ['triggers', 'searches', 'creates', 'bulkReads'];
7
+ const resourceMethods = ['get', 'list', 'hook', 'search', 'create'];
8
+
9
+ const validateInputFieldGroups = (
10
+ inputFields,
11
+ inputFieldGroups,
12
+ basePath,
13
+ schemaName,
14
+ ) => {
15
+ const errors = [];
16
+
17
+ // Check for duplicate group keys in inputFieldGroups
18
+ const groupKeys = inputFieldGroups.map((group) => group.key);
19
+ const duplicateKeys = groupKeys.filter(
20
+ (key, index) => groupKeys.indexOf(key) !== index,
21
+ );
22
+
23
+ if (duplicateKeys.length > 0) {
24
+ duplicateKeys.forEach((duplicateKey) => {
25
+ const duplicateIndex = groupKeys.lastIndexOf(duplicateKey);
26
+ errors.push(
27
+ new jsonschema.ValidationError(
28
+ `Duplicate group key "${duplicateKey}" found in inputFieldGroups. Group keys must be unique.`,
29
+ inputFieldGroups[duplicateIndex],
30
+ schemaName,
31
+ `${basePath}.inputFieldGroups[${duplicateIndex}].key`,
32
+ 'duplicateGroupKey',
33
+ 'inputFieldGroups',
34
+ ),
35
+ );
36
+ });
37
+ }
38
+
39
+ // Create a set of valid group keys
40
+ const validGroupKeys = new Set(groupKeys);
41
+
42
+ inputFields.forEach((inputField, index) => {
43
+ // Check children fields first - groups are not allowed in children
44
+ (inputField.children || []).forEach((childField, childIndex) => {
45
+ if (childField.group) {
46
+ errors.push(
47
+ new jsonschema.ValidationError(
48
+ `Group fields are not allowed in children fields. Remove the group property from this field.`,
49
+ childField.group,
50
+ '/PlainInputFieldSchema',
51
+ `${basePath}.inputFields[${index}].children[${childIndex}].group`,
52
+ 'groupInChildren',
53
+ 'group',
54
+ ),
55
+ );
56
+ }
57
+ });
58
+
59
+ // Check if group reference is valid
60
+ if (inputField.group) {
61
+ if (!validGroupKeys.has(inputField.group)) {
62
+ const availableGroups =
63
+ Array.from(validGroupKeys).length > 0
64
+ ? `[${Array.from(validGroupKeys).join(', ')}]`
65
+ : '[]';
66
+ errors.push(
67
+ new jsonschema.ValidationError(
68
+ `Group "${inputField.group}" is not defined in inputFieldGroups. Available groups: ${availableGroups}`,
69
+ inputField.group,
70
+ '/PlainInputFieldSchema',
71
+ `${basePath}.inputFields[${index}].group`,
72
+ 'invalidGroupReference',
73
+ 'group',
74
+ ),
75
+ );
76
+ }
77
+ }
78
+ });
79
+
80
+ return errors;
81
+ };
82
+
83
+ const inputFieldGroupsConstraints = (definition) => {
84
+ const errors = [];
85
+
86
+ // Validate action types (triggers, searches, creates, bulkReads)
87
+ for (const actionType of actionTypes) {
88
+ const group = definition[actionType] || {};
89
+ _.each(group, (action, actionKey) => {
90
+ const inputFields = _.get(action, ['operation', 'inputFields'], []);
91
+ const inputFieldGroups = _.get(
92
+ action,
93
+ ['operation', 'inputFieldGroups'],
94
+ [],
95
+ );
96
+
97
+ const basePath = `instance.${actionType}.${actionKey}.operation`;
98
+ const schemaName = '/BasicOperationSchema';
99
+
100
+ const actionErrors = validateInputFieldGroups(
101
+ inputFields,
102
+ inputFieldGroups,
103
+ basePath,
104
+ schemaName,
105
+ );
106
+ errors.push(...actionErrors);
107
+ });
108
+ }
109
+
110
+ // Validate resources
111
+ if (definition.resources) {
112
+ _.each(definition.resources, (resource, resourceKey) => {
113
+ resourceMethods.forEach((method) => {
114
+ if (resource[method] && resource[method].operation) {
115
+ const inputFields = _.get(
116
+ resource[method],
117
+ ['operation', 'inputFields'],
118
+ [],
119
+ );
120
+ const inputFieldGroups = _.get(
121
+ resource[method],
122
+ ['operation', 'inputFieldGroups'],
123
+ [],
124
+ );
125
+
126
+ const basePath = `instance.resources.${resourceKey}.${method}.operation`;
127
+ const schemaName = '/BasicOperationSchema';
128
+
129
+ const resourceErrors = validateInputFieldGroups(
130
+ inputFields,
131
+ inputFieldGroups,
132
+ basePath,
133
+ schemaName,
134
+ );
135
+ errors.push(...resourceErrors);
136
+ }
137
+ });
138
+ });
139
+ }
140
+
141
+ return errors;
142
+ };
143
+
144
+ module.exports = inputFieldGroupsConstraints;
@@ -31,6 +31,7 @@ BasicActionOperationSchema.properties = {
31
31
  oneOf: [{ $ref: RequestSchema.id }, { $ref: FunctionSchema.id }],
32
32
  },
33
33
  inputFields: BasicActionOperationSchema.properties.inputFields,
34
+ inputFieldGroups: BasicActionOperationSchema.properties.inputFieldGroups,
34
35
  outputFields: BasicActionOperationSchema.properties.outputFields,
35
36
  sample: BasicActionOperationSchema.properties.sample,
36
37
  lock: BasicActionOperationSchema.properties.lock,
@@ -81,6 +81,7 @@ BasicHookOperationSchema.properties = {
81
81
  },
82
82
  },
83
83
  inputFields: BasicHookOperationSchema.properties.inputFields,
84
+ inputFieldGroups: BasicHookOperationSchema.properties.inputFieldGroups,
84
85
  outputFields: BasicHookOperationSchema.properties.outputFields,
85
86
  sample: BasicHookOperationSchema.properties.sample,
86
87
  };
@@ -59,6 +59,7 @@ BasicHookToPollOperationSchema.properties = {
59
59
  oneOf: [{ $ref: RequestSchema.id }, { $ref: FunctionSchema.id }],
60
60
  },
61
61
  inputFields: BasicHookToPollOperationSchema.properties.inputFields,
62
+ inputFieldGroups: BasicHookToPollOperationSchema.properties.inputFieldGroups,
62
63
  outputFields: BasicHookToPollOperationSchema.properties.outputFields,
63
64
  sample: BasicHookToPollOperationSchema.properties.sample,
64
65
  maxPollingDelay: {
@@ -10,6 +10,7 @@ const KeySchema = require('./KeySchema');
10
10
  const LockObjectSchema = require('./LockObjectSchema');
11
11
  const ThrottleObjectSchema = require('./ThrottleObjectSchema');
12
12
  const InputFieldsSchema = require('./InputFieldsSchema');
13
+ const InputFieldGroupsSchema = require('./InputFieldGroupsSchema');
13
14
  const OutputFieldsSchema = require('./OutputFieldsSchema');
14
15
 
15
16
  module.exports = makeSchema(
@@ -35,6 +36,11 @@ module.exports = makeSchema(
35
36
  'What should the form a user sees and configures look like?',
36
37
  $ref: InputFieldsSchema.id,
37
38
  },
39
+ inputFieldGroups: {
40
+ description:
41
+ 'Defines groups for organizing input fields in the UI. Each group can have a key, label, and emphasis styling.',
42
+ $ref: InputFieldGroupsSchema.id,
43
+ },
38
44
  outputFields: {
39
45
  description:
40
46
  'What fields of data will this return? Will use resource outputFields if missing, will also use sample if available.',
@@ -84,6 +90,7 @@ module.exports = makeSchema(
84
90
  },
85
91
  [
86
92
  InputFieldsSchema,
93
+ InputFieldGroupsSchema,
87
94
  OutputFieldsSchema,
88
95
  FunctionSchema,
89
96
  KeySchema,
@@ -31,6 +31,7 @@ BasicPollingOperationSchema.properties = {
31
31
  type: 'boolean',
32
32
  },
33
33
  inputFields: BasicPollingOperationSchema.properties.inputFields,
34
+ inputFieldGroups: BasicPollingOperationSchema.properties.inputFieldGroups,
34
35
  outputFields: BasicPollingOperationSchema.properties.outputFields,
35
36
  sample: BasicPollingOperationSchema.properties.sample,
36
37
  throttle: BasicPollingOperationSchema.properties.throttle,
@@ -31,6 +31,7 @@ BasicSearchOperationSchema.properties = {
31
31
  oneOf: [{ $ref: RequestSchema.id }, { $ref: FunctionSchema.id }],
32
32
  },
33
33
  inputFields: BasicSearchOperationSchema.properties.inputFields,
34
+ inputFieldGroups: BasicSearchOperationSchema.properties.inputFieldGroups,
34
35
  outputFields: BasicSearchOperationSchema.properties.outputFields,
35
36
  sample: BasicSearchOperationSchema.properties.sample,
36
37
  lock: BasicSearchOperationSchema.properties.lock,
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const makeSchema = require('../utils/makeSchema');
4
+
5
+ const KeySchema = require('./KeySchema');
6
+
7
+ module.exports = makeSchema(
8
+ {
9
+ id: '/InputFieldGroupsSchema',
10
+ description: 'An array or collection of input field groups.',
11
+ type: 'array',
12
+ items: {
13
+ type: 'object',
14
+ required: ['key'],
15
+ properties: {
16
+ key: {
17
+ description: 'The unique identifier for this group.',
18
+ $ref: KeySchema.id,
19
+ },
20
+ label: {
21
+ description: 'The human-readable name for the group.',
22
+ type: 'string',
23
+ minLength: 1,
24
+ },
25
+ emphasize: {
26
+ description:
27
+ 'Whether this group should be visually emphasized in the UI.',
28
+ type: 'boolean',
29
+ },
30
+ },
31
+ },
32
+ examples: [[{ key: 'abc' }]],
33
+ antiExamples: [
34
+ { example: {}, reason: 'Must be an array' },
35
+ { example: [{ label: 'test label' }], reason: 'key is required' },
36
+ ],
37
+ additionalProperties: false,
38
+ },
39
+ [KeySchema],
40
+ );
@@ -5,6 +5,7 @@ const RefResourceSchema = require('./RefResourceSchema');
5
5
  const FieldChoicesSchema = require('./FieldChoicesSchema');
6
6
  const PlainFieldSchema = require('./PlainFieldSchema');
7
7
  const FieldMetaSchema = require('./FieldMetaSchema');
8
+ const KeySchema = require('./KeySchema');
8
9
 
9
10
  module.exports = makeSchema(
10
11
  {
@@ -70,6 +71,11 @@ module.exports = makeSchema(
70
71
  'Allows for additional metadata to be stored on the field. Supports simple key-values only (no sub-objects or arrays).',
71
72
  $ref: FieldMetaSchema.id,
72
73
  },
74
+ group: {
75
+ description:
76
+ "References a group key from the operation's inputFieldGroups to organize this field with others.",
77
+ $ref: KeySchema.id,
78
+ },
73
79
  },
74
80
  examples: [
75
81
  { key: 'abc' },
@@ -90,6 +96,14 @@ module.exports = makeSchema(
90
96
  display_order: 1,
91
97
  },
92
98
  },
99
+ {
100
+ key: 'name',
101
+ group: 'contact',
102
+ },
103
+ {
104
+ key: 'email',
105
+ group: 'contact',
106
+ },
93
107
  ],
94
108
  antiExamples: [
95
109
  {
@@ -132,5 +146,11 @@ module.exports = makeSchema(
132
146
  ],
133
147
  additionalProperties: false,
134
148
  },
135
- [RefResourceSchema, FieldChoicesSchema, FieldMetaSchema, PlainFieldSchema],
149
+ [
150
+ RefResourceSchema,
151
+ FieldChoicesSchema,
152
+ FieldMetaSchema,
153
+ PlainFieldSchema,
154
+ KeySchema,
155
+ ],
136
156
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-schema",
3
- "version": "17.2.0",
3
+ "version": "17.3.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/",