From cfae9481fe385e52673c9c1452e33e1d259aae90 Mon Sep 17 00:00:00 2001 From: kola-er Date: Tue, 3 Oct 2023 15:03:36 +0100 Subject: [PATCH] PDE-4295 Add support for throttle configuration --- packages/schema/docs/build/schema.md | 37 ++++++++++ packages/schema/exported-schema.json | 41 +++++++++++ packages/schema/lib/schemas/AppSchema.js | 7 ++ .../lib/schemas/BasicActionOperationSchema.js | 1 + .../lib/schemas/BasicOperationSchema.js | 8 ++- .../lib/schemas/ThrottleObjectSchema.js | 70 +++++++++++++++++++ packages/schema/test/index.js | 2 +- 7 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 packages/schema/lib/schemas/ThrottleObjectSchema.js diff --git a/packages/schema/docs/build/schema.md b/packages/schema/docs/build/schema.md index d6c776cad..f947fa5bc 100644 --- a/packages/schema/docs/build/schema.md +++ b/packages/schema/docs/build/schema.md @@ -58,6 +58,7 @@ This is automatically generated by the `npm run docs` command in `zapier-platfor * [/SearchOrCreatesSchema](#searchorcreatesschema) * [/SearchSchema](#searchschema) * [/SearchesSchema](#searchesschema) +* [/ThrottleObjectSchema](#throttleobjectschema) * [/TriggerSchema](#triggerschema) * [/TriggersSchema](#triggersschema) * [/VersionSchema](#versionschema) @@ -126,6 +127,7 @@ Key | Required | Type | Description `searchOrCreates` | no | [/SearchOrCreatesSchema](#searchorcreatesschema) | 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. `searchAndCreates` | no | [/SearchAndCreatesSchema](#searchandcreatesschema) | An alias for "searchOrCreates". `flags` | no | [/AppFlagsSchema](#appflagsschema) | Top-level app options +`throttle` | no | [/ThrottleObjectSchema](#throttleobjectschema) | Zapier uses this configuration to throttle actions' perform method, individually, when their number of invocations exceeds the limit within a specific window. When set here, it is the default throttle configuration used on all the actions of an integration. And it can be overwritten on each action in the action's operation object. @@ -390,6 +392,7 @@ Key | Required | Type | Description `outputFields` | no | [/DynamicFieldsSchema](#dynamicfieldsschema) | What fields of data will this return? Will use resource outputFields if missing, will also use sample if available. `sample` | **yes** (with exceptions, see description) | `object` | What does a sample of data look like? Will use resource sample if missing. Requirement waived if `display.hidden` is true or if this belongs to a resource that has a top-level sample `lock` | no | [/LockObjectSchema](#lockobjectschema) | **INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking. +`throttle` | no | [/ThrottleObjectSchema](#throttleobjectschema) | Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window. #### Examples @@ -422,6 +425,7 @@ Key | Required | Type | Description `outputFields` | no | [/DynamicFieldsSchema](#dynamicfieldsschema) | What fields of data will this return? Will use resource outputFields if missing, will also use sample if available. `sample` | **yes** (with exceptions, see description) | `object` | What does a sample of data look like? Will use resource sample if missing. Requirement waived if `display.hidden` is true or if this belongs to a resource that has a top-level sample `lock` | no | [/LockObjectSchema](#lockobjectschema) | **INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking. +`throttle` | no | [/ThrottleObjectSchema](#throttleobjectschema) | Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window. `shouldLock` | no | `boolean` | Should this action be performed one at a time (avoid concurrency)? #### Examples @@ -543,6 +547,7 @@ Key | Required | Type | Description `outputFields` | no | [/DynamicFieldsSchema](#dynamicfieldsschema) | What fields of data will this return? Will use resource outputFields if missing, will also use sample if available. `sample` | **yes** (with exceptions, see description) | `object` | What does a sample of data look like? Will use resource sample if missing. Requirement waived if `display.hidden` is true or if this belongs to a resource that has a top-level sample `lock` | no | [/LockObjectSchema](#lockobjectschema) | **INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking. +`throttle` | no | [/ThrottleObjectSchema](#throttleobjectschema) | Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window. #### Examples @@ -2056,6 +2061,38 @@ Key | Required | Type | Description ----- +## /ThrottleObjectSchema + +Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window. + +#### Details + +* **Type** - `object` +* [**Source Code**](https://github.com/zapier/zapier-platform/blob/zapier-platform-schema@15.3.0/packages/schema/lib/schemas/ThrottleObjectSchema.js) + +#### Properties + +Key | Required | Type | Description +--- | -------- | ---- | ----------- +`window` | **yes** | `integer` | The timeframe in seconds to track the number of invocations to an action's perform method before resetting, to start all over again. +`limit` | **yes** | `integer` | The maximum number of invocations to an action's perform method, allowed within the timeframe window. +`scope` | no | `array`[`string` in (`'user'`, `'auth'`, `'account'`)] | The requester's attribute with which the invocations would be throttled by. You can set the scope to one or more of the following: 'user' - Throttles based on user ids. 'auth' - Throttles based on auth ids. 'account' - Throttles based on account ids for all users under a single account. By default, throttling is scoped to the account. + +#### Examples + +* `{ window: 60, limit: 100 }` +* `{ window: 600, limit: 100, scope: [ 'account', 'user' ] }` +* `{ window: 3600, limit: 10, scope: [ 'auth' ] }` + +#### Anti-Examples + +* `{ window: 60, limit: 100, scope: [ 'zap' ] }` - _Invalid scope provided: `zap`._ +* `{ limit: 10 }` - _Missing required key: `window`._ +* `{ window: 600 }` - _Missing required key: `limit`._ +* `{}` - _Missing required keys: `window` and `limit`._ + +----- + ## /TriggerSchema How will Zapier get notified of new objects? diff --git a/packages/schema/exported-schema.json b/packages/schema/exported-schema.json index cbf36c5f3..81e643593 100644 --- a/packages/schema/exported-schema.json +++ b/packages/schema/exported-schema.json @@ -75,6 +75,10 @@ "description": "Top-level app options", "$ref": "/AppFlagsSchema" }, + "throttle": { + "description": "Zapier uses this configuration to throttle actions' perform method, individually, when their number of invocations exceeds the limit within a specific window. When set here, it is the default throttle configuration used on all the actions of an integration. And it can be overwritten on each action in the action's operation object.", + "$ref": "/ThrottleObjectSchema" + }, "legacy": { "description": "**INTERNAL USE ONLY**. Zapier uses this to hold properties from a legacy Web Builder app.", "type": "object", @@ -652,6 +656,31 @@ "minProperties": 1 } }, + "ThrottleObjectSchema": { + "id": "/ThrottleObjectSchema", + "description": "Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window.", + "type": "object", + "required": ["window", "limit"], + "properties": { + "window": { + "description": "The timeframe in seconds to track the number of invocations to an action's perform method before resetting, to start all over again.", + "type": "integer" + }, + "limit": { + "description": "The maximum number of invocations to an action's perform method, allowed within the timeframe window.", + "type": "integer" + }, + "scope": { + "description": "The requester's attribute with which the invocations would be throttled by. You can set the scope to one or more of the following: 'user' - Throttles based on user ids. 'auth' - Throttles based on auth ids. 'account' - Throttles based on account ids for all users under a single account. By default, throttling is scoped to the account.", + "type": "array", + "items": { + "enum": ["user", "auth", "account"], + "type": "string" + } + } + }, + "additionalProperties": false + }, "BasicDisplaySchema": { "id": "/BasicDisplaySchema", "description": "Represents user information for a trigger, search, or create.", @@ -737,6 +766,10 @@ "lock": { "description": "**INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking.", "$ref": "/LockObjectSchema" + }, + "throttle": { + "description": "Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window.", + "$ref": "/ThrottleObjectSchema" } }, "additionalProperties": false @@ -954,6 +987,10 @@ "lock": { "description": "**INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking.", "$ref": "/LockObjectSchema" + }, + "throttle": { + "description": "Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window.", + "$ref": "/ThrottleObjectSchema" } }, "additionalProperties": false @@ -1318,6 +1355,10 @@ "description": "**INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking.", "$ref": "/LockObjectSchema" }, + "throttle": { + "description": "Zapier uses this configuration to throttle an action's perform method when its number of invocations exceeds the limit within a specific window.", + "$ref": "/ThrottleObjectSchema" + }, "shouldLock": { "description": "Should this action be performed one at a time (avoid concurrency)?", "type": "boolean" diff --git a/packages/schema/lib/schemas/AppSchema.js b/packages/schema/lib/schemas/AppSchema.js index 93ced5db4..13974aef1 100644 --- a/packages/schema/lib/schemas/AppSchema.js +++ b/packages/schema/lib/schemas/AppSchema.js @@ -16,6 +16,7 @@ const VersionSchema = require('./VersionSchema'); const MiddlewaresSchema = require('./MiddlewaresSchema'); const HydratorsSchema = require('./HydratorsSchema'); const AppFlagsSchema = require('./AppFlagsSchema'); +const ThrottleObjectSchema = require('./ThrottleObjectSchema'); module.exports = makeSchema( { @@ -105,6 +106,11 @@ module.exports = makeSchema( description: 'Top-level app options', $ref: AppFlagsSchema.id, }, + throttle: { + description: + 'Zapier uses this configuration to throttle actions\' perform method, individually, when their number of invocations exceeds the limit within a specific window. When set here, it is the default throttle configuration used on all the actions of an integration. And it can be overwritten on each action in the action\'s operation object.', + $ref: ThrottleObjectSchema.id, + }, legacy: { description: '**INTERNAL USE ONLY**. Zapier uses this to hold properties from a legacy Web Builder app.', @@ -150,5 +156,6 @@ module.exports = makeSchema( MiddlewaresSchema, HydratorsSchema, AppFlagsSchema, + ThrottleObjectSchema, ] ); diff --git a/packages/schema/lib/schemas/BasicActionOperationSchema.js b/packages/schema/lib/schemas/BasicActionOperationSchema.js index affbf8a96..fd2e9cc11 100644 --- a/packages/schema/lib/schemas/BasicActionOperationSchema.js +++ b/packages/schema/lib/schemas/BasicActionOperationSchema.js @@ -34,6 +34,7 @@ BasicActionOperationSchema.properties = { outputFields: BasicActionOperationSchema.properties.outputFields, sample: BasicActionOperationSchema.properties.sample, lock: BasicActionOperationSchema.properties.lock, + throttle: BasicActionOperationSchema.properties.throttle, }; BasicActionOperationSchema.examples = [ diff --git a/packages/schema/lib/schemas/BasicOperationSchema.js b/packages/schema/lib/schemas/BasicOperationSchema.js index cf2361d8b..96f44dc83 100644 --- a/packages/schema/lib/schemas/BasicOperationSchema.js +++ b/packages/schema/lib/schemas/BasicOperationSchema.js @@ -9,6 +9,7 @@ const RequestSchema = require('./RequestSchema'); const ResultsSchema = require('./ResultsSchema'); const KeySchema = require('./KeySchema'); const LockObjectSchema = require('./LockObjectSchema'); +const ThrottleObjectSchema = require('./ThrottleObjectSchema'); module.exports = makeSchema( { @@ -56,6 +57,11 @@ module.exports = makeSchema( '**INTERNAL USE ONLY**. Zapier uses this configuration for internal operation locking.', $ref: LockObjectSchema.id, }, + throttle: { + description: + 'Zapier uses this configuration to throttle an action\'s perform method when its number of invocations exceeds the limit within a specific window.', + $ref: ThrottleObjectSchema.id, + }, }, examples: [ { @@ -75,5 +81,5 @@ module.exports = makeSchema( ], additionalProperties: false, }, - [DynamicFieldsSchema, FunctionSchema, KeySchema, LockObjectSchema, RequestSchema, ResultsSchema] + [DynamicFieldsSchema, FunctionSchema, KeySchema, LockObjectSchema, RequestSchema, ResultsSchema, ThrottleObjectSchema] ); diff --git a/packages/schema/lib/schemas/ThrottleObjectSchema.js b/packages/schema/lib/schemas/ThrottleObjectSchema.js new file mode 100644 index 000000000..b5d98df8d --- /dev/null +++ b/packages/schema/lib/schemas/ThrottleObjectSchema.js @@ -0,0 +1,70 @@ +'use strict'; + +const makeSchema = require('../utils/makeSchema'); + +module.exports = makeSchema({ + id: '/ThrottleObjectSchema', + description: + 'Zapier uses this configuration to throttle an action\'s perform method when its number of invocations exceeds the limit within a specific window.', + type: 'object', + required: ['window', 'limit'], + properties: { + window: { + description: + 'The timeframe in seconds to track the number of invocations to an action\'s perform method before resetting, to start all over again.', + type: 'integer', + }, + limit: { + description: + 'The maximum number of invocations to an action\'s perform method, allowed within the timeframe window.', + type: 'integer', + }, + scope: { + description: `The requester's attribute with which the invocations would be throttled by. You can set the scope to one or more of the following: 'user' - Throttles based on user ids. 'auth' - Throttles based on auth ids. 'account' - Throttles based on account ids for all users under a single account. By default, throttling is scoped to the account.`, + type: 'array', + items: { + enum: ['user', 'auth', 'account'], + type: 'string', + }, + }, + }, + examples: [ + { + window: 60, + limit: 100, + }, + { + window: 600, + limit: 100, + scope: ['account', 'user'], + }, + { + window: 3600, + limit: 10, + scope: ['auth'], + }, + ], + antiExamples: [ + { + example: { + window: 60, + limit: 100, + scope: ['zap'], + }, + reason: 'Invalid scope provided: `zap`.', + }, + { + example: {limit: 10}, + reason: 'Missing required key: `window`.', + }, + { + example: {window: 600}, + reason: 'Missing required key: `limit`.', + }, + { + example: {}, + reason: 'Missing required keys: `window` and `limit`.', + }, + ], + additionalProperties: false, +}); diff --git a/packages/schema/test/index.js b/packages/schema/test/index.js index 31ab86fed..faface52f 100644 --- a/packages/schema/test/index.js +++ b/packages/schema/test/index.js @@ -9,7 +9,7 @@ const appDefinition = require('../examples/definition.json'); const copy = (o) => JSON.parse(JSON.stringify(o)); -const NUM_SCHEMAS = 53; // changes regularly as we expand +const NUM_SCHEMAS = 54; // changes regularly as we expand describe('app', () => { describe('validation', () => {