diff --git a/lib/api-routes/template-routes.js b/lib/api-routes/template-routes.js index 49ab6ee5..5a3fa4a6 100644 --- a/lib/api-routes/template-routes.js +++ b/lib/api-routes/template-routes.js @@ -247,22 +247,23 @@ async function init(args) { account: Joi.string().empty('').max(256).example('example').description('Account ID to list the templates for'), page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('AccountTemplatesRequest') }, response: { schema: Joi.object({ account: accountIdSchema.required(), - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), templates: Joi.array() .items( diff --git a/lib/routes-ui.js b/lib/routes-ui.js index 74f7c467..01fd3b53 100644 --- a/lib/routes-ui.js +++ b/lib/routes-ui.js @@ -221,7 +221,7 @@ const configWebhooksSchema = { notifyHeaders: Joi.string().empty('').trim(), notifyText: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false), notifyWebSafeHtml: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false), - notifyTextSize: Joi.number().empty(''), + notifyTextSize: Joi.number().integer().empty(''), notifyCalendarEvents: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false), inboxNewOnly: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false), @@ -266,7 +266,7 @@ const configDocumentStoreSchema = { const configLoggingSchema = { all: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').default(false).description('Enable logs for all accounts'), - maxLogLines: Joi.number().empty('').min(0).max(10000000).default(DEFAULT_MAX_LOG_LINES) + maxLogLines: Joi.number().integer().empty('').min(0).max(10000000).default(DEFAULT_MAX_LOG_LINES) }; const OKTA_OAUTH2_ISSUER = readEnvValue('OKTA_OAUTH2_ISSUER'); @@ -2214,8 +2214,8 @@ return true;` }, query: Joi.object({ - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE) + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE) }) } } @@ -2787,8 +2787,8 @@ return true;` }, query: Joi.object({ - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE) + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE) }) } } @@ -3487,8 +3487,8 @@ return payload;`) query: Joi.object({ account: accountIdSchema.default(null), - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE) + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE) }) } } @@ -4222,8 +4222,8 @@ return payload;`) }, query: Joi.object({ - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE) + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE) }) } } @@ -4437,6 +4437,7 @@ return payload;`) host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to').label('Hostname').required(), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -4563,6 +4564,7 @@ return payload;`) host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to').label('Hostname').required(), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -4661,6 +4663,7 @@ return payload;`) pass: Joi.string().empty('').max(1024).label('Password'), host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to').label('Hostname'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -4813,8 +4816,8 @@ return payload;`) query: Joi.object({ account: accountIdSchema.default(null), - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE) + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE) }) } } @@ -6154,8 +6157,8 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} }, query: Joi.object({ - page: Joi.number().min(1).max(1000000).default(1), - pageSize: Joi.number().min(1).max(250).default(DEFAULT_PAGE_SIZE), + page: Joi.number().integer().min(1).max(1000000).default(1), + pageSize: Joi.number().integer().min(1).max(250).default(DEFAULT_PAGE_SIZE), query: Joi.string().example('user@example').description('Filter accounts by name/email match').label('AccountQuery'), state: Joi.string() .trim() @@ -6598,6 +6601,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} imap_auth_pass: Joi.string().empty('').max(1024).required(), imap_host: Joi.string().hostname().required().example('imap.gmail.com').description('Hostname to connect to'), imap_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -6620,6 +6624,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} smtp_auth_pass: Joi.string().empty('').max(1024).required(), smtp_host: Joi.string().hostname().required().example('smtp.gmail.com').description('Hostname to connect to'), smtp_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -6762,6 +6767,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} imap_auth_pass: Joi.string().empty('').max(1024).required(), imap_host: Joi.string().hostname().required().example('imap.gmail.com').description('Hostname to connect to'), imap_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -6785,6 +6791,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} smtp_auth_pass: Joi.string().empty('').max(1024).required(), smtp_host: Joi.string().hostname().required().example('smtp.gmail.com').description('Hostname to connect to'), smtp_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -7417,6 +7424,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} imap_auth_pass: Joi.string().empty('').max(1024), imap_host: Joi.string().hostname().example('imap.gmail.com').description('Hostname to connect to'), imap_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(993) @@ -7434,7 +7442,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} .example(true) .description('Disable IMAP if you are using this email account to only send emails.'), - imap_resyncDelay: Joi.number().empty(''), + imap_resyncDelay: Joi.number().integer().empty(''), imap_sentMailPath: Joi.string() .empty('') @@ -7461,6 +7469,7 @@ ${Buffer.from(data.content, 'base64url').toString('base64')} smtp_auth_pass: Joi.string().empty('').max(1024), smtp_host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to'), smtp_port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -9360,7 +9369,7 @@ ${now}`, }, payload: Joi.object({ - thread: Joi.number().min(1).max(1000000).required().example(1).description('Thread ID') + thread: Joi.number().integer().min(1).max(1000000).required().example(1).description('Thread ID') }) } } @@ -9412,7 +9421,7 @@ ${now}`, }, payload: Joi.object({ - thread: Joi.number().empty('').min(0).max(1000000).required().example(1).description('Thread ID') + thread: Joi.number().integer().empty('').min(0).max(1000000).required().example(1).description('Thread ID') }) } } diff --git a/lib/schemas.js b/lib/schemas.js index c30e631c..de9e5985 100644 --- a/lib/schemas.js +++ b/lib/schemas.js @@ -157,7 +157,7 @@ const settingsSchema = { .falsy('N', 'false', 0, '') .description('Pre-process HTML in webhook notification to be web safe'), - notifyTextSize: Joi.number().min(0), + notifyTextSize: Joi.number().integer().min(0), notifyCalendarEvents: Joi.boolean() .truthy('Y', 'true', '1', 'on') @@ -214,7 +214,7 @@ const settingsSchema = { logs: Joi.object({ all: Joi.boolean().truthy('Y', 'true', '1').falsy('N', 'false', 0).default(false).example(false).description('Enable logs for all accounts'), - maxLogLines: Joi.number().min(0).max(1000000).default(10000) + maxLogLines: Joi.number().integer().min(0).max(1000000).default(10000) }).label('LogSettings'), imapStrategy: Joi.string() @@ -237,6 +237,7 @@ const settingsSchema = { smtpServerEnabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').description('Enable SMTP Interface'), smtpServerPort: Joi.number() + .integer() .min(0) .max(64 * 1024) .empty('') @@ -259,6 +260,7 @@ const settingsSchema = { imapProxyServerEnabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').description('Enable IMAP Proxy Interface'), imapProxyServerPort: Joi.number() + .integer() .min(0) .max(64 * 1024) .empty('') @@ -281,9 +283,9 @@ const settingsSchema = { .falsy('N', 'false', 0, '') .description('Enable TLS for the IMAP proxy interface. Requires a valid certificate.'), - queueKeep: Joi.number().empty('').min(0).description('How many completed or failed queue entries to keep'), + queueKeep: Joi.number().integer().empty('').min(0).description('How many completed or failed queue entries to keep'), - deliveryAttempts: Joi.number().empty('').min(0).description('How many times to retry an email sending before it is considered as failing'), + deliveryAttempts: Joi.number().integer().empty('').min(0).description('How many times to retry an email sending before it is considered as failing'), templateHeader: Joi.string() .empty('') @@ -424,6 +426,7 @@ const imapSchema = { .example('imap.gmail.com') .description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .when('disabled', { @@ -441,7 +444,7 @@ const imapSchema = { .unknown() .description('Optional TLS configuration') .label('TLS'), - resyncDelay: Joi.number().example(RESYNC_DELAY).description('Full resync delay in seconds').default(RESYNC_DELAY), + resyncDelay: Joi.number().integer().example(RESYNC_DELAY).description('Full resync delay in seconds').default(RESYNC_DELAY), disabled: Joi.boolean().example(false).description('Set to true to disable IMAP handling'), sentMailPath: Joi.string() @@ -503,6 +506,7 @@ const smtpSchema = { host: Joi.string().hostname().required().example('smtp.gmail.com').description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -598,6 +602,7 @@ const imapUpdateSchema = { host: Joi.string().hostname().example('imap.gmail.com').description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(993) @@ -610,7 +615,7 @@ const imapUpdateSchema = { .unknown() .description('Optional TLS configuration') .label('TLS'), - resyncDelay: Joi.number().example(RESYNC_DELAY).description('Full resync delay in seconds'), + resyncDelay: Joi.number().integer().example(RESYNC_DELAY).description('Full resync delay in seconds'), disabled: Joi.boolean().example(false).description('Set to true to disable IMAP handling'), @@ -674,6 +679,7 @@ const smtpUpdateSchema = { host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(587) @@ -723,7 +729,10 @@ const oauth2UpdateSchema = { const attachmentSchema = Joi.object({ id: Joi.string().example('AAAAAgAACrIyLjI').description('Attachment ID').label('AttachmentId'), contentType: Joi.string().example('image/gif').description('Mime type of the attachment'), - encodedSize: Joi.number().example(48).description('Encoded size of the attachment. Actual file size is usually smaller depending on the encoding'), + encodedSize: Joi.number() + .integer() + .example(48) + .description('Encoded size of the attachment. Actual file size is usually smaller depending on the encoding'), embedded: Joi.boolean().example(true).description('Is this image used in HTML img tag'), inline: Joi.boolean().example(true).description('Should this file be included in the message preview somehow'), contentId: Joi.string().example('').description('Usually used only for embedded images'), @@ -733,14 +742,14 @@ const attachmentSchema = Joi.object({ const messageEntrySchema = Joi.object({ id: Joi.string().example('AAAAAgAACrI').description('Message ID').label('MessageEntryId'), - uid: Joi.number().example(12345).description('UID of the message').label('MessageUid'), + uid: Joi.number().integer().example(12345).description('UID of the message').label('MessageUid'), emailId: Joi.string().example('1694937972638499881').description('Globally unique ID (if server supports it)').label('MessageEmailId'), threadId: Joi.string().example('1694936993596975454').description('Thread ID (if server supports it)').label('MessageThreadId'), date: Joi.date().iso().example('2021-03-22T13:13:31.000Z').description('Date (internal)'), draft: Joi.boolean().example(false).description('Is this message marked as a draft'), unseen: Joi.boolean().example(true).description('Is this message unseen'), flagged: Joi.boolean().example(true).description('Is this message marked as flagged'), - size: Joi.number().example(1040).description('Message size in bytes'), + size: Joi.number().integer().example(1040).description('Message size in bytes'), subject: Joi.string() .allow('') .example('What a wonderful message') @@ -773,8 +782,8 @@ const messageEntrySchema = Joi.object({ text: Joi.object({ id: Joi.string().example('AAAAAgAACqiTkaExkaEykA').description('Pointer to message text content'), encodedSize: Joi.object({ - plain: Joi.number().example(1013).description('How many bytes for plain text'), - html: Joi.number().example(1013).description('How many bytes for html content') + plain: Joi.number().integer().example(1013).description('How many bytes for plain text'), + html: Joi.number().integer().example(1013).description('How many bytes for html content') }).description('Encoded message part sizes') }).label('TextInfo'), @@ -783,7 +792,7 @@ const messageEntrySchema = Joi.object({ const messageDetailsSchema = Joi.object({ id: Joi.string().example('AAAAAgAACrI').description('Message ID').label('MessageEntryId'), - uid: Joi.number().example(12345).description('UID of the message').label('MessageUid'), + uid: Joi.number().integer().example(12345).description('UID of the message').label('MessageUid'), emailId: Joi.string().example('1694937972638499881').description('Globally unique ID (if server supports it)').label('MessageEmailId'), threadId: Joi.string() .example('1694936993596975454') @@ -793,7 +802,7 @@ const messageDetailsSchema = Joi.object({ draft: Joi.boolean().example(false).description('Is this message marked as a draft'), unseen: Joi.boolean().example(true).description('Is this message unseen'), flagged: Joi.boolean().example(true).description('Is this message marked as flagged'), - size: Joi.number().example(1040).description('Message size in bytes'), + size: Joi.number().integer().example(1040).description('Message size in bytes'), subject: Joi.string() .allow('') .example('What a wonderful message') @@ -836,8 +845,8 @@ const messageDetailsSchema = Joi.object({ .example('AAAAAgAACqiTkaExkaEykA') .description('Pointer to message text content. The value is `null` for messages retrieved from Document Store.'), encodedSize: Joi.object({ - plain: Joi.number().example(1013).description('How many bytes for plain text'), - html: Joi.number().example(1013).description('How many bytes for html content') + plain: Joi.number().integer().example(1013).description('How many bytes for plain text'), + html: Joi.number().integer().example(1013).description('How many bytes for html content') }).description('Encoded message part sizes'), plain: Joi.string().example('Hello from myself!').description('Plaintext content of the message'), html: Joi.string().example('

Hello from myself!

').description('HTML content of the message'), @@ -876,9 +885,9 @@ const messageDetailsSchema = Joi.object({ }).label('MessageListEntry'); const messageListSchema = Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), messages: Joi.array().items(messageEntrySchema).label('PageMessages') }).label('MessageList'); @@ -903,11 +912,15 @@ const mailboxesSchema = Joi.array().items( ) .label('MailboxSpecialUseSource'), noInferiors: Joi.boolean().example(false).description('If true, then adding subfolders is forbidden').label('MailboxSpecialUseSource'), - messages: Joi.number().example(120).description('Count of messages in mailbox').label('MailboxMessages'), - uidNext: Joi.number().example(121).description('Next expected UID').label('MailboxMUidNext'), + messages: Joi.number().integer().example(120).description('Count of messages in mailbox').label('MailboxMessages'), + uidNext: Joi.number().integer().example(121).description('Next expected UID').label('MailboxMUidNext'), status: Joi.object({ - messages: Joi.number().example(120).description('Count of messages in mailbox as reported by the STATUS command').label('StatusMessages'), - unseen: Joi.number().example(120).description('Count of unseen messages in mailbox as reported by the STATUS command').label('StatusUnseenMessages') + messages: Joi.number().integer().example(120).description('Count of messages in mailbox as reported by the STATUS command').label('StatusMessages'), + unseen: Joi.number() + .integer() + .example(120) + .description('Count of unseen messages in mailbox as reported by the STATUS command') + .label('StatusUnseenMessages') }) .description('Optional counters info') .label('MailboxResponseStatus') @@ -951,7 +964,7 @@ const lastErrorSchema = Joi.object({ tokenRequest: Joi.object({ grant: Joi.string().valid('refresh_token', 'authorization_code').example('refresh_token').description('Requested grant type'), provider: Joi.string().max(256).example('gmail').description('OAuth2 provider'), - status: Joi.number().example(400).description('HTTP status code for the OAuth2 request'), + status: Joi.number().integer().example(400).description('HTTP status code for the OAuth2 request'), clientId: Joi.string() .example('1023289917884-h3nu00e9cb7h252e24c23sv19l8k57ah.apps.googleusercontent.com') .description('OAuth2 client ID used to authenticate this request'), @@ -1017,12 +1030,14 @@ const searchSchema = Joi.object({ .label('Subject'), larger: Joi.number() + .integer() .min(0) .max(1024 * 1024 * 1024) .description('Matches messages larger than value') .label('MessageLarger'), smaller: Joi.number() + .integer() .min(0) .max(1024 * 1024 * 1024) .description('Matches messages smaller than value') @@ -1033,7 +1048,11 @@ const searchSchema = Joi.object({ .description('UID range') .label('UIDRange'), - modseq: Joi.number().min(0).description('Matches messages with modseq higher than value. Not allowed with `documentStore`.').label('ModseqLarger'), + modseq: Joi.number() + .integer() + .min(0) + .description('Matches messages with modseq higher than value. Not allowed with `documentStore`.') + .label('ModseqLarger'), before: Joi.date().description('Matches messages received before date').label('EnvelopeBefore'), since: Joi.date().description('Matches messages received after date').label('EnvelopeSince'), @@ -1241,8 +1260,8 @@ const tokenRestrictionsSchema = Joi.object({ .label('AddressAllowlist') .description('IP address allowlist'), rateLimit: Joi.object({ - maxRequests: Joi.number().min(1).example(20).description('Allowed count of requests in the rate limit time window'), - timeWindow: Joi.number().min(1).example(2).description('Rate limit time window in seconds') + maxRequests: Joi.number().integer().min(1).example(20).description('Allowed count of requests in the rate limit time window'), + timeWindow: Joi.number().integer().min(1).example(2).description('Rate limit time window in seconds') }) .allow(false) .default(false) diff --git a/workers/api.js b/workers/api.js index 139d8fd6..f3ecd0a4 100644 --- a/workers/api.js +++ b/workers/api.js @@ -487,6 +487,7 @@ const init = async () => { }, headers: Joi.object({ 'x-ee-timeout': Joi.number() + .integer() .min(0) .max(2 * 3600 * 1000) .optional() @@ -2709,13 +2710,14 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize'), + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize'), state: Joi.string() .valid('init', 'syncing', 'connecting', 'connected', 'authenticationError', 'connectError', 'unset', 'disconnected') .example('connected') @@ -2727,9 +2729,9 @@ When making API calls remember that requests against the same account are queued response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), accounts: Joi.array() .items( @@ -2977,8 +2979,8 @@ When making API calls remember that requests against the same account are queued counters: accountCountersSchema, quota: Joi.object({ - usage: Joi.number().example(8547884032).description('How many bytes has the account stored in emails'), - limit: Joi.number().example(16106127360).description('How many bytes can the account store emails'), + usage: Joi.number().integer().example(8547884032).description('How many bytes has the account stored in emails'), + limit: Joi.number().integer().example(16106127360).description('How many bytes can the account store emails'), status: Joi.string().example('53%').description('Textual information about the usage') }) .label('AccountQuota') @@ -3475,6 +3477,7 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ maxBytes: Joi.number() + .integer() .min(0) .max(1024 * 1024 * 1024) .example(5 * 1025 * 1024) @@ -3710,9 +3713,9 @@ When making API calls remember that requests against the same account are queued .description('Message ID. NB! This and other fields might not be present if server did not provide enough information') .label('MessageAppendId'), path: Joi.string().example('INBOX').description('Folder this message was uploaded to').label('MessageAppendPath'), - uid: Joi.number().example(12345).description('UID of uploaded message'), + uid: Joi.number().integer().example(12345).description('UID of uploaded message'), uidValidity: Joi.string().example('12345').description('UIDVALIDTITY of the target folder. Numeric value cast as string.'), - seq: Joi.number().example(12345).description('Sequence number of uploaded message'), + seq: Joi.number().integer().example(12345).description('Sequence number of uploaded message'), messageId: Joi.string().max(996).example('').description('Message ID'), @@ -3949,7 +3952,7 @@ When making API calls remember that requests against the same account are queued schema: Joi.object({ path: Joi.string().required().example('INBOX').description('Target mailbox folder path'), id: Joi.string().max(256).required().example('AAAAAQAACnA').description('Message ID'), - uid: Joi.number().example(12345).description('UID of moved message') + uid: Joi.number().integer().example(12345).description('UID of moved message') }).label('MessageMoveResponse'), failAction: 'log' } @@ -4238,6 +4241,7 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ maxBytes: Joi.number() + .integer() .min(0) .max(1024 * 1024 * 1024) .example(MAX_ATTACHMENT_SIZE) @@ -4327,13 +4331,14 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ path: Joi.string().required().example('INBOX').description('Mailbox folder path').label('Path'), page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize'), + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize'), documentStore: documentStoreSchema.default(false) }).label('MessageQuery') }, @@ -4430,12 +4435,13 @@ When making API calls remember that requests against the same account are queued .example('INBOX') .description('Mailbox folder path. Not required if `documentStore` is `true`'), page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page'), + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page'), documentStore: documentStoreSchema.default(false), exposeQuery: Joi.boolean() .truthy('Y', 'true', '1') @@ -4533,12 +4539,13 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page'), + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page'), exposeQuery: Joi.boolean() .truthy('Y', 'true', '1') .falsy('N', 'false', 0) @@ -4825,7 +4832,10 @@ When making API calls remember that requests against the same account are queued tz: Joi.string().empty('').max(100).example('Europe/Tallinn').description('Optional timezone'), sendAt: Joi.date().iso().example('2021-07-08T07:06:34.336Z').description('Send message at specified time'), - deliveryAttempts: Joi.number().example(10).description('How many delivery attempts to make until message is considered as failed'), + deliveryAttempts: Joi.number() + .integer() + .example(10) + .description('How many delivery attempts to make until message is considered as failed'), gateway: Joi.string().max(256).example('example').description('Optional SMTP gateway ID for message routing'), listId: Joi.string() @@ -5184,10 +5194,13 @@ When making API calls remember that requests against the same account are queued schema: Joi.object({ queue: Joi.string().empty('').trim().valid('notify', 'submit', 'documents').required().example('notify').description('Queue ID'), jobs: Joi.object({ - active: Joi.number().example(123).description('Jobs that are currently being processed'), - delayed: Joi.number().example(123).description('Jobs that are processed in the future'), - paused: Joi.number().example(123).description('Jobs that would be processed once queue processing is resumed'), - waiting: Joi.number().example(123).description('Jobs that should be processed, but are waiting until there are any free handlers') + active: Joi.number().integer().example(123).description('Jobs that are currently being processed'), + delayed: Joi.number().integer().example(123).description('Jobs that are processed in the future'), + paused: Joi.number().integer().example(123).description('Jobs that would be processed once queue processing is resumed'), + waiting: Joi.number() + .integer() + .example(123) + .description('Jobs that should be processed, but are waiting until there are any free handlers') }).label('QueueJobs'), paused: Joi.boolean().example(false).description('Is the queue paused or not') }).label('SettingsQueueResponse'), @@ -5342,6 +5355,7 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ seconds: Joi.number() + .integer() .empty('') .min(0) .max(MAX_DAYS_STATS * 24 * 3600) @@ -5356,17 +5370,17 @@ When making API calls remember that requests against the same account are queued schema: Joi.object({ version: Joi.string().example(packageData.version).description('EmailEngine version number'), license: Joi.string().example(packageData.license).description('EmailEngine license'), - accounts: Joi.number().example(26).description('Number of registered accounts'), + accounts: Joi.number().integer().example(26).description('Number of registered accounts'), node: Joi.string().example('16.10.0').description('Node.js Version'), redis: Joi.string().example('6.2.4').description('Redis Version'), connections: Joi.object({ - init: Joi.number().example(2).description('Accounts not yet initialized'), - connected: Joi.number().example(8).description('Successfully connected accounts'), - connecting: Joi.number().example(7).description('Connection is being established'), - authenticationError: Joi.number().example(3).description('Authentication failed'), - connectError: Joi.number().example(5).description('Connection failed due to technical error'), - unset: Joi.number().example(0).description('Accounts without valid IMAP settings'), - disconnected: Joi.number().example(1).description('IMAP connection was closed') + init: Joi.number().integer().example(2).description('Accounts not yet initialized'), + connected: Joi.number().integer().example(8).description('Successfully connected accounts'), + connecting: Joi.number().integer().example(7).description('Connection is being established'), + authenticationError: Joi.number().integer().example(3).description('Authentication failed'), + connectError: Joi.number().integer().example(5).description('Connection failed due to technical error'), + unset: Joi.number().integer().example(0).description('Accounts without valid IMAP settings'), + disconnected: Joi.number().integer().example(1).description('IMAP connection was closed') }) .description('Counts of accounts in different connection states') .label('ConnectionsStats'), @@ -5667,6 +5681,7 @@ When making API calls remember that requests against the same account are queued host: Joi.string().hostname().required().example('imap.gmail.com').description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -5681,6 +5696,7 @@ When making API calls remember that requests against the same account are queued host: Joi.string().hostname().required().example('imap.gmail.com').description('Hostname to connect to'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .required() @@ -5738,21 +5754,22 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('OutbixListFilter') }, response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), messages: Joi.array() .items( @@ -5777,8 +5794,11 @@ When making API calls remember that requests against the same account are queued scheduled: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('When this message is supposed to be delivered'), nextAttempt: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('Next delivery attempt'), - attemptsMade: Joi.number().example(3).description('How many times EmailEngine has tried to deliver this email'), - attempts: Joi.number().example(3).description('How many delivery attempts to make until message is considered as failed'), + attemptsMade: Joi.number().integer().example(3).description('How many times EmailEngine has tried to deliver this email'), + attempts: Joi.number() + .integer() + .example(3) + .description('How many delivery attempts to make until message is considered as failed'), progress: Joi.object({ status: Joi.string() @@ -5910,21 +5930,22 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('WebhookRoutesListRequest') }, response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), webhooks: Joi.array() .items( @@ -5941,7 +5962,7 @@ When making API calls remember that requests against the same account are queued updated: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('The time this route was last updated'), enabled: Joi.boolean().example(true).description('Is the route enabled').label('WebhookRouteEnabled'), targetUrl: settingsSchema.webhooks, - tcount: Joi.number().example(123).description('How many times this route has been applied') + tcount: Joi.number().integer().example(123).description('How many times this route has been applied') }).label('WebhookRoutesListEntry') ) .label('WebhookRoutesList') @@ -6010,7 +6031,7 @@ When making API calls remember that requests against the same account are queued updated: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('The time this route was last updated'), enabled: Joi.boolean().example(true).description('Is the route enabled').label('WebhookRouteEnabled'), targetUrl: settingsSchema.webhooks, - tcount: Joi.number().example(123).description('How many times this route has been applied'), + tcount: Joi.number().integer().example(123).description('How many times this route has been applied'), content: Joi.object({ fn: Joi.string().example('return true;').description('Filter function'), map: Joi.string().example('payload.ts = Date.now(); return payload;').description('Mapping function') @@ -6090,21 +6111,22 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('GatewaysFilter') }, response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), apps: Joi.array() .items( @@ -6283,7 +6305,10 @@ When making API calls remember that requests against the same account are queued .example('******') .description('PEM formatted service secret for 2-legged OAuth2 applications. Actual value is not revealed.'), - accounts: Joi.number().example(12).description('The number of accounts registered with this application. Not available for legacy apps.'), + accounts: Joi.number() + .integer() + .example(12) + .description('The number of accounts registered with this application. Not available for legacy apps.'), lastError: lastErrorSchema.allow(null) }).label('ApplicationResponse'), @@ -6511,7 +6536,10 @@ When making API calls remember that requests against the same account are queued schema: Joi.object({ id: Joi.string().max(256).required().example('AAABhaBPHscAAAAH').description('OAuth2 application ID'), deleted: Joi.boolean().truthy('Y', 'true', '1').falsy('N', 'false', 0).default(true).description('Was the gateway deleted'), - accounts: Joi.number().example(12).description('The number of accounts registered with this application. Not available for legacy apps.') + accounts: Joi.number() + .integer() + .example(12) + .description('The number of accounts registered with this application. Not available for legacy apps.') }).label('DeleteAppRequestResponse'), failAction: 'log' } @@ -6563,28 +6591,29 @@ When making API calls remember that requests against the same account are queued query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('GatewaysFilter') }, response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), gateways: Joi.array() .items( Joi.object({ gateway: Joi.string().max(256).required().example('example').description('Gateway ID'), name: Joi.string().max(256).example('My Email Gateway').description('Display name for the gateway'), - deliveries: Joi.number().empty('').example(100).description('Count of email deliveries using this gateway'), + deliveries: Joi.number().integer().empty('').example(100).description('Count of email deliveries using this gateway'), lastUse: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('Last delivery time'), lastError: lastErrorSchema.allow(null) }).label('GatewayResponseItem') @@ -6660,7 +6689,7 @@ When making API calls remember that requests against the same account are queued gateway: Joi.string().max(256).required().example('example').description('Gateway ID'), name: Joi.string().max(256).required().example('My Email Gateway').description('Display name for the gateway'), - deliveries: Joi.number().empty('').example(100).description('Count of email deliveries using this gateway'), + deliveries: Joi.number().integer().empty('').example(100).description('Count of email deliveries using this gateway'), lastUse: Joi.date().iso().example('2021-02-17T13:43:18.860Z').description('Last delivery time'), user: Joi.string().empty('').trim().max(1024).label('UserName'), @@ -6668,6 +6697,7 @@ When making API calls remember that requests against the same account are queued host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to').label('Hostname'), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -6743,6 +6773,7 @@ When making API calls remember that requests against the same account are queued host: Joi.string().hostname().example('smtp.gmail.com').description('Hostname to connect to').label('Hostname').required(), port: Joi.number() + .integer() .min(1) .max(64 * 1024) .example(465) @@ -6824,6 +6855,7 @@ When making API calls remember that requests against the same account are queued host: Joi.string().hostname().empty('').example('smtp.gmail.com').description('Hostname to connect to').label('Hostname'), port: Joi.number() + .integer() .min(1) .empty('') .max(64 * 1024) @@ -7326,27 +7358,28 @@ ${now}`, query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('PageListsRequest') }, response: { schema: Joi.object({ - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), blocklists: Joi.array() .items( Joi.object({ listId: Joi.string().max(256).required().example('example').description('List ID'), - count: Joi.number().example(12).description('Count of blocked addresses in this list') + count: Joi.number().integer().example(12).description('Count of blocked addresses in this list') }).label('BlocklistsResponseItem') ) .label('BlocklistsEntries') @@ -7408,22 +7441,23 @@ ${now}`, query: Joi.object({ page: Joi.number() + .integer() .min(0) .max(1024 * 1024) .default(0) .example(0) .description('Page number (zero indexed, so use 0 for first page)') .label('PageNumber'), - pageSize: Joi.number().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') + pageSize: Joi.number().integer().min(1).max(1000).default(20).example(20).description('How many entries per page').label('PageSize') }).label('PageListsRequest') }, response: { schema: Joi.object({ listId: Joi.string().max(256).required().example('example').description('List ID'), - total: Joi.number().example(120).description('How many matching entries').label('TotalNumber'), - page: Joi.number().example(0).description('Current page (0-based index)').label('PageNumber'), - pages: Joi.number().example(24).description('Total page count').label('PagesNumber'), + total: Joi.number().integer().example(120).description('How many matching entries').label('TotalNumber'), + page: Joi.number().integer().example(0).description('Current page (0-based index)').label('PageNumber'), + pages: Joi.number().integer().example(24).description('Total page count').label('PagesNumber'), addresses: Joi.array() .items( Joi.object({