emailengine-app 2.61.5 → 2.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/data/google-crawlers.json +1 -1
- package/lib/account.js +20 -7
- package/lib/api-routes/account-routes.js +28 -5
- package/lib/api-routes/chat-routes.js +1 -1
- package/lib/api-routes/export-routes.js +316 -0
- package/lib/api-routes/message-routes.js +28 -23
- package/lib/api-routes/template-routes.js +28 -7
- package/lib/arf-detect.js +1 -1
- package/lib/autodetect-imap-settings.js +5 -5
- package/lib/consts.js +16 -0
- package/lib/db.js +3 -0
- package/lib/email-client/base-client.js +6 -4
- package/lib/email-client/gmail-client.js +205 -35
- package/lib/email-client/imap/mailbox.js +99 -8
- package/lib/email-client/imap/subconnection.js +5 -5
- package/lib/email-client/imap-client.js +76 -19
- package/lib/email-client/message-builder.js +3 -1
- package/lib/email-client/notification-handler.js +12 -9
- package/lib/email-client/outlook-client.js +364 -73
- package/lib/email-client/smtp-pool-manager.js +1 -1
- package/lib/export.js +528 -0
- package/lib/oauth/gmail.js +24 -16
- package/lib/oauth/mail-ru.js +26 -13
- package/lib/oauth/outlook.js +29 -19
- package/lib/oauth/pubsub/google.js +5 -0
- package/lib/routes-ui.js +268 -9
- package/lib/schemas.js +274 -81
- package/lib/stream-encrypt.js +263 -0
- package/lib/sub-script.js +2 -2
- package/lib/tools.js +194 -12
- package/lib/ui-routes/account-routes.js +23 -0
- package/lib/ui-routes/admin-config-routes.js +13 -6
- package/lib/ui-routes/admin-entities-routes.js +18 -0
- package/lib/webhooks.js +16 -20
- package/package.json +20 -20
- package/sbom.json +1 -1
- package/server.js +66 -7
- package/static/js/ace/ace.js +1 -1
- package/static/js/ace/ext-language_tools.js +1 -1
- package/static/licenses.html +118 -149
- package/translations/de.mo +0 -0
- package/translations/de.po +63 -36
- package/translations/en.mo +0 -0
- package/translations/en.po +64 -37
- package/translations/et.mo +0 -0
- package/translations/et.po +63 -36
- package/translations/fr.mo +0 -0
- package/translations/fr.po +63 -36
- package/translations/ja.mo +0 -0
- package/translations/ja.po +63 -36
- package/translations/messages.pot +84 -51
- package/translations/nl.mo +0 -0
- package/translations/nl.po +63 -36
- package/translations/pl.mo +0 -0
- package/translations/pl.po +63 -36
- package/views/accounts/account.hbs +375 -2
- package/views/config/network.hbs +45 -0
- package/views/config/service.hbs +35 -0
- package/workers/api.js +130 -47
- package/workers/documents.js +3 -2
- package/workers/export.js +933 -0
- package/workers/imap.js +34 -1
- package/workers/submit.js +33 -6
- package/workers/webhooks.js +20 -4
package/lib/schemas.js
CHANGED
|
@@ -43,7 +43,10 @@ const settingsSchema = {
|
|
|
43
43
|
.example('https://api.example.com/email/webhooks')
|
|
44
44
|
.description('Target URL that will receive webhook notifications via POST requests'),
|
|
45
45
|
|
|
46
|
-
webhookEvents: Joi.array()
|
|
46
|
+
webhookEvents: Joi.array()
|
|
47
|
+
.items(Joi.string().max(256).example('messageNew').label('WebhookEventType'))
|
|
48
|
+
.description('List of event types that will trigger webhook notifications')
|
|
49
|
+
.label('WebhookEvents'),
|
|
47
50
|
|
|
48
51
|
webhooksCustomHeaders: Joi.array()
|
|
49
52
|
.items(
|
|
@@ -61,8 +64,9 @@ const settingsSchema = {
|
|
|
61
64
|
.label('WebhooksCustomHeaders'),
|
|
62
65
|
|
|
63
66
|
notifyHeaders: Joi.array()
|
|
64
|
-
.items(Joi.string().max(256).example('List-ID'))
|
|
65
|
-
.description('Email headers to include in webhook payloads for additional context')
|
|
67
|
+
.items(Joi.string().max(256).example('List-ID').label('NotifyHeaderEntry'))
|
|
68
|
+
.description('Email headers to include in webhook payloads for additional context')
|
|
69
|
+
.label('NotifyHeaders'),
|
|
66
70
|
|
|
67
71
|
/* ────────────── URLs ────────────── */
|
|
68
72
|
|
|
@@ -105,9 +109,8 @@ const settingsSchema = {
|
|
|
105
109
|
.trim()
|
|
106
110
|
.valid('full', 'fast')
|
|
107
111
|
.example('full')
|
|
108
|
-
.description(
|
|
109
|
-
|
|
110
|
-
),
|
|
112
|
+
.description('IMAP indexing strategy:\n * full - Detect new, changed, and deleted messages (slower but complete)\n * fast - Detect only new messages')
|
|
113
|
+
.label('ImapIndexer'),
|
|
111
114
|
|
|
112
115
|
resolveGmailCategories: Joi.boolean()
|
|
113
116
|
.truthy('Y', 'true', '1', 'on')
|
|
@@ -210,12 +213,25 @@ const settingsSchema = {
|
|
|
210
213
|
|
|
211
214
|
proxyEnabled: Joi.boolean().truthy('Y', 'true', '1', 'on').falsy('N', 'false', 0, '').description('Route outbound connections through a proxy server'),
|
|
212
215
|
proxyUrl: Joi.string()
|
|
213
|
-
.uri({ scheme: ['http', 'https', 'socks', 'socks4', 'socks5'], allowRelative: false })
|
|
216
|
+
.uri({ scheme: ['http', 'https', 'socks', 'socks4', 'socks4a', 'socks5'], allowRelative: false })
|
|
214
217
|
.allow('')
|
|
215
218
|
.example('socks5://proxy.example.com:1080')
|
|
216
219
|
.description('Proxy server URL for outbound connections')
|
|
217
220
|
.label('ProxyURL'),
|
|
218
221
|
|
|
222
|
+
/* ────────────── HTTP Proxy ────────────── */
|
|
223
|
+
|
|
224
|
+
httpProxyEnabled: Joi.boolean()
|
|
225
|
+
.truthy('Y', 'true', '1', 'on')
|
|
226
|
+
.falsy('N', 'false', 0, '')
|
|
227
|
+
.description('Route outbound HTTP/HTTPS requests (webhooks, OAuth, API calls) through an HTTP proxy'),
|
|
228
|
+
httpProxyUrl: Joi.string()
|
|
229
|
+
.uri({ scheme: ['http', 'https', 'socks', 'socks4', 'socks4a', 'socks5'], allowRelative: false })
|
|
230
|
+
.allow('')
|
|
231
|
+
.example('http://proxy.example.com:8080')
|
|
232
|
+
.description('HTTP proxy URL for outbound HTTP/HTTPS requests')
|
|
233
|
+
.label('HttpProxyURL'),
|
|
234
|
+
|
|
219
235
|
/* ────────────── SMTP ────────────── */
|
|
220
236
|
|
|
221
237
|
smtpEhloName: Joi.string()
|
|
@@ -373,17 +389,24 @@ const settingsSchema = {
|
|
|
373
389
|
imapStrategy: Joi.string()
|
|
374
390
|
.empty('')
|
|
375
391
|
.valid(...ADDRESS_STRATEGIES.map(entry => entry.key))
|
|
376
|
-
.description('IP address selection strategy for outbound IMAP connections when multiple local addresses are available')
|
|
392
|
+
.description('IP address selection strategy for outbound IMAP connections when multiple local addresses are available')
|
|
393
|
+
.label('ImapStrategy'),
|
|
377
394
|
|
|
378
395
|
smtpStrategy: Joi.string()
|
|
379
396
|
.empty('')
|
|
380
397
|
.valid(...ADDRESS_STRATEGIES.map(entry => entry.key))
|
|
381
|
-
.description('IP address selection strategy for outbound SMTP connections when multiple local addresses are available')
|
|
398
|
+
.description('IP address selection strategy for outbound SMTP connections when multiple local addresses are available')
|
|
399
|
+
.label('SmtpStrategy'),
|
|
382
400
|
|
|
383
401
|
localAddresses: Joi.array()
|
|
384
|
-
.items(
|
|
402
|
+
.items(
|
|
403
|
+
Joi.string()
|
|
404
|
+
.ip({ version: ['ipv4', 'ipv6'], cidr: 'forbidden' })
|
|
405
|
+
.label('LocalAddressEntry')
|
|
406
|
+
)
|
|
385
407
|
.single()
|
|
386
|
-
.description('List of local IP addresses to use for outbound connections (requires appropriate network configuration)')
|
|
408
|
+
.description('List of local IP addresses to use for outbound connections (requires appropriate network configuration)')
|
|
409
|
+
.label('LocalAddresses'),
|
|
387
410
|
|
|
388
411
|
/* ────────────── Built-in SMTP Server ────────────── */
|
|
389
412
|
|
|
@@ -473,7 +496,8 @@ const settingsSchema = {
|
|
|
473
496
|
.max(100)
|
|
474
497
|
.example('fr')
|
|
475
498
|
.valid(...locales.map(l => l.locale))
|
|
476
|
-
.description('Default language/locale for the user interface')
|
|
499
|
+
.description('Default language/locale for the user interface')
|
|
500
|
+
.label('SettingsLocale'),
|
|
477
501
|
timezone: Joi.string().max(100).example('Europe/Tallinn').description('Default timezone for date/time display (IANA timezone identifier)'),
|
|
478
502
|
pageBrandName: Joi.string().allow('', null).max(1024).example('EmailEngine').description('Brand name displayed in page titles'),
|
|
479
503
|
|
|
@@ -494,13 +518,39 @@ const settingsSchema = {
|
|
|
494
518
|
.allow('')
|
|
495
519
|
.uri({ scheme: ['http', 'https', 'mailto'], allowRelative: false })
|
|
496
520
|
.example('https://github.com/postalsys/emailengine/issues')
|
|
497
|
-
.description('Support URL advertised via IMAP ID extension')
|
|
521
|
+
.description('Support URL advertised via IMAP ID extension'),
|
|
522
|
+
|
|
523
|
+
/* ────────────── Export ────────────── */
|
|
524
|
+
|
|
525
|
+
exportMaxConcurrent: Joi.number().integer().min(1).max(100).example(2).description('Maximum concurrent exports per account'),
|
|
526
|
+
|
|
527
|
+
exportMaxGlobalConcurrent: Joi.number().integer().min(1).max(100).example(8).description('Maximum concurrent exports system-wide across all accounts'),
|
|
528
|
+
|
|
529
|
+
gmailExportBatchSize: Joi.number()
|
|
530
|
+
.integer()
|
|
531
|
+
.min(1)
|
|
532
|
+
.max(50)
|
|
533
|
+
.example(10)
|
|
534
|
+
.description('Number of parallel message fetch requests for Gmail export operations (default: 10, max: 50)'),
|
|
535
|
+
|
|
536
|
+
outlookExportBatchSize: Joi.number()
|
|
537
|
+
.integer()
|
|
538
|
+
.min(1)
|
|
539
|
+
.max(20)
|
|
540
|
+
.example(20)
|
|
541
|
+
.description('Number of messages per batch request for Outlook export operations (default: 20, max: 20 - MS Graph API limit)'),
|
|
542
|
+
|
|
543
|
+
exportMaxMessages: Joi.number().integer().min(1).max(10000000).example(500000).description('Maximum number of messages per export (default: 500000)'),
|
|
544
|
+
|
|
545
|
+
exportMaxSize: Joi.number().integer().min(1).example(10737418240).description('Maximum export file size in bytes (default: 10GB)')
|
|
498
546
|
};
|
|
499
547
|
|
|
500
548
|
const addressSchema = Joi.object({
|
|
501
549
|
name: Joi.string().trim().empty('').max(256).example('Some Name').description('Display name for the email address'),
|
|
502
550
|
address: Joi.string().email({ ignoreLength: false }).example('user@example.com').required().description('Email address')
|
|
503
|
-
})
|
|
551
|
+
})
|
|
552
|
+
.description('Email address with optional display name')
|
|
553
|
+
.label('EmailAddress');
|
|
504
554
|
|
|
505
555
|
// generate a list of boolean values
|
|
506
556
|
const settingsQuerySchema = Object.fromEntries(
|
|
@@ -527,6 +577,7 @@ const imapSchema = {
|
|
|
527
577
|
.max(4 * 4096)
|
|
528
578
|
.example(false)
|
|
529
579
|
.description('OAuth2 access token (when using OAuth2 instead of password authentication)')
|
|
580
|
+
.label('ImapAccessToken')
|
|
530
581
|
})
|
|
531
582
|
.allow(false)
|
|
532
583
|
.when('useAuthServer', {
|
|
@@ -535,7 +586,7 @@ const imapSchema = {
|
|
|
535
586
|
otherwise: Joi.optional()
|
|
536
587
|
})
|
|
537
588
|
.description('Authentication credentials for the IMAP server')
|
|
538
|
-
.label('
|
|
589
|
+
.label('ImapAuthentication'),
|
|
539
590
|
|
|
540
591
|
useAuthServer: Joi.boolean().example(false).description('Use external authentication server to retrieve credentials dynamically'),
|
|
541
592
|
|
|
@@ -566,7 +617,7 @@ const imapSchema = {
|
|
|
566
617
|
})
|
|
567
618
|
.unknown()
|
|
568
619
|
.description('Advanced TLS configuration options')
|
|
569
|
-
.label('
|
|
620
|
+
.label('ImapTlsOptions'),
|
|
570
621
|
resyncDelay: Joi.number().integer().example(RESYNC_DELAY).description('Delay in seconds between full mailbox resynchronizations').default(RESYNC_DELAY),
|
|
571
622
|
disabled: Joi.boolean().example(false).description('Temporarily disable IMAP operations for this account'),
|
|
572
623
|
|
|
@@ -614,6 +665,7 @@ const smtpSchema = {
|
|
|
614
665
|
.max(4 * 4096)
|
|
615
666
|
.example(false)
|
|
616
667
|
.description('OAuth2 access token (when using OAuth2 instead of password authentication)')
|
|
668
|
+
.label('SmtpAccessToken')
|
|
617
669
|
})
|
|
618
670
|
.allow(false)
|
|
619
671
|
.when('useAuthServer', {
|
|
@@ -622,7 +674,7 @@ const smtpSchema = {
|
|
|
622
674
|
otherwise: Joi.optional()
|
|
623
675
|
})
|
|
624
676
|
.description('Authentication credentials for the SMTP server')
|
|
625
|
-
.label('
|
|
677
|
+
.label('SmtpAuthentication'),
|
|
626
678
|
|
|
627
679
|
useAuthServer: Joi.boolean().example(false).description('Use external authentication server to retrieve credentials dynamically'),
|
|
628
680
|
|
|
@@ -644,7 +696,7 @@ const smtpSchema = {
|
|
|
644
696
|
})
|
|
645
697
|
.unknown()
|
|
646
698
|
.description('Advanced TLS configuration options')
|
|
647
|
-
.label('
|
|
699
|
+
.label('SmtpTlsOptions')
|
|
648
700
|
};
|
|
649
701
|
|
|
650
702
|
const oauth2AuthSchema = Joi.object({
|
|
@@ -678,9 +730,10 @@ const oauth2Schema = {
|
|
|
678
730
|
is: true,
|
|
679
731
|
then: Joi.optional(),
|
|
680
732
|
otherwise: Joi.optional().valid(false, null)
|
|
681
|
-
})
|
|
733
|
+
})
|
|
734
|
+
.label('OAuth2RedirectUrl'),
|
|
682
735
|
|
|
683
|
-
provider: Joi.string().max(256).example('AAABhaBPHscAAAAH').description('OAuth2 Application ID configured in EmailEngine'),
|
|
736
|
+
provider: Joi.string().max(256).example('AAABhaBPHscAAAAH').description('OAuth2 Application ID configured in EmailEngine').label('OAuth2AppProvider'),
|
|
684
737
|
|
|
685
738
|
auth: oauth2AuthSchema,
|
|
686
739
|
|
|
@@ -689,7 +742,8 @@ const oauth2Schema = {
|
|
|
689
742
|
accessToken: Joi.string()
|
|
690
743
|
.max(4 * 4096)
|
|
691
744
|
.example('ya29.a0ARrdaM8a...')
|
|
692
|
-
.description('OAuth2 access token for the email account')
|
|
745
|
+
.description('OAuth2 access token for the email account')
|
|
746
|
+
.label('OAuth2SchemaAccessToken'),
|
|
693
747
|
refreshToken: Joi.string()
|
|
694
748
|
.max(4 * 4096)
|
|
695
749
|
.example('1//09Ie3CtORQYm...')
|
|
@@ -728,6 +782,7 @@ const imapUpdateSchema = {
|
|
|
728
782
|
.max(4 * 4096)
|
|
729
783
|
.example(false)
|
|
730
784
|
.description('OAuth2 access token (when using OAuth2 instead of password authentication)')
|
|
785
|
+
.label('ImapUpdateAccessToken')
|
|
731
786
|
})
|
|
732
787
|
.allow(false)
|
|
733
788
|
.when('useAuthServer', {
|
|
@@ -736,7 +791,7 @@ const imapUpdateSchema = {
|
|
|
736
791
|
otherwise: Joi.optional()
|
|
737
792
|
})
|
|
738
793
|
.description('Authentication credentials for the IMAP server')
|
|
739
|
-
.label('
|
|
794
|
+
.label('ImapUpdateAuthentication'),
|
|
740
795
|
|
|
741
796
|
useAuthServer: Joi.boolean().example(false).description('Use external authentication server to retrieve credentials dynamically'),
|
|
742
797
|
|
|
@@ -749,7 +804,7 @@ const imapUpdateSchema = {
|
|
|
749
804
|
})
|
|
750
805
|
.unknown()
|
|
751
806
|
.description('Advanced TLS configuration options')
|
|
752
|
-
.label('
|
|
807
|
+
.label('ImapUpdateTlsOptions'),
|
|
753
808
|
resyncDelay: Joi.number().integer().example(RESYNC_DELAY).description('Delay in seconds between full mailbox resynchronizations'),
|
|
754
809
|
|
|
755
810
|
disabled: Joi.boolean().example(false).description('Temporarily disable IMAP operations for this account'),
|
|
@@ -779,6 +834,7 @@ const smtpUpdateSchema = {
|
|
|
779
834
|
.max(4 * 4096)
|
|
780
835
|
.example(false)
|
|
781
836
|
.description('OAuth2 access token (when using OAuth2 instead of password authentication)')
|
|
837
|
+
.label('SmtpUpdateAccessToken')
|
|
782
838
|
})
|
|
783
839
|
.allow(false)
|
|
784
840
|
.when('useAuthServer', {
|
|
@@ -787,7 +843,7 @@ const smtpUpdateSchema = {
|
|
|
787
843
|
otherwise: Joi.optional()
|
|
788
844
|
})
|
|
789
845
|
.description('Authentication credentials for the SMTP server')
|
|
790
|
-
.label('
|
|
846
|
+
.label('SmtpUpdateAuthentication'),
|
|
791
847
|
|
|
792
848
|
useAuthServer: Joi.boolean().example(false).description('Use external authentication server to retrieve credentials dynamically'),
|
|
793
849
|
|
|
@@ -800,14 +856,14 @@ const smtpUpdateSchema = {
|
|
|
800
856
|
})
|
|
801
857
|
.unknown()
|
|
802
858
|
.description('Advanced TLS configuration options')
|
|
803
|
-
.label('
|
|
859
|
+
.label('SmtpUpdateTlsOptions')
|
|
804
860
|
};
|
|
805
861
|
|
|
806
862
|
const oauth2UpdateSchema = {
|
|
807
863
|
partial: partialSchema,
|
|
808
864
|
|
|
809
865
|
authorize: Joi.boolean().example(false).description('Request an OAuth2 authorization URL instead of directly configuring credentials'),
|
|
810
|
-
provider: Joi.string().max(256).example('AAABhaBPHscAAAAH').description('OAuth2 Application ID configured in EmailEngine'),
|
|
866
|
+
provider: Joi.string().max(256).example('AAABhaBPHscAAAAH').description('OAuth2 Application ID configured in EmailEngine').label('OAuth2UpdateAppProvider'),
|
|
811
867
|
|
|
812
868
|
auth: oauth2AuthSchema,
|
|
813
869
|
|
|
@@ -816,7 +872,8 @@ const oauth2UpdateSchema = {
|
|
|
816
872
|
accessToken: Joi.string()
|
|
817
873
|
.max(4 * 4096)
|
|
818
874
|
.example('ya29.a0ARrdaM8a...')
|
|
819
|
-
.description('OAuth2 access token for the email account')
|
|
875
|
+
.description('OAuth2 access token for the email account')
|
|
876
|
+
.label('OAuth2UpdateAccessToken'),
|
|
820
877
|
refreshToken: Joi.string()
|
|
821
878
|
.max(4 * 4096)
|
|
822
879
|
.example('1//09Ie3CtORQYm...')
|
|
@@ -839,7 +896,8 @@ const attachmentSchema = Joi.object({
|
|
|
839
896
|
encodedSize: Joi.number()
|
|
840
897
|
.integer()
|
|
841
898
|
.example(48)
|
|
842
|
-
.description('Size of the attachment as stored in the email (base64 encoded). The actual decoded file size is approximately 75% of this value.')
|
|
899
|
+
.description('Size of the attachment as stored in the email (base64 encoded). The actual decoded file size is approximately 75% of this value.')
|
|
900
|
+
.label('AttachmentEncodedSize'),
|
|
843
901
|
embedded: Joi.boolean().example(true).description('Whether the attachment is embedded in the HTML content'),
|
|
844
902
|
inline: Joi.boolean().example(true).description('Whether the attachment should be displayed inline rather than as a download'),
|
|
845
903
|
contentId: Joi.string().example('<unique-image-id@localhost>').description('Content-ID header value used for embedding images in HTML'),
|
|
@@ -892,7 +950,9 @@ const messageEntrySchema = Joi.object({
|
|
|
892
950
|
encodedSize: Joi.object({
|
|
893
951
|
plain: Joi.number().integer().example(1013).description('Size of the plain text part in bytes'),
|
|
894
952
|
html: Joi.number().integer().example(1013).description('Size of the HTML part in bytes')
|
|
895
|
-
})
|
|
953
|
+
})
|
|
954
|
+
.description('Sizes of different message parts')
|
|
955
|
+
.label('TextEncodedSize')
|
|
896
956
|
}).label('TextInfo'),
|
|
897
957
|
|
|
898
958
|
preview: Joi.string().description('Short preview of the message content')
|
|
@@ -947,7 +1007,9 @@ const messageDetailsSchema = Joi.object({
|
|
|
947
1007
|
encodedSize: Joi.object({
|
|
948
1008
|
plain: Joi.number().integer().example(1013).description('Size of the plain text part in bytes'),
|
|
949
1009
|
html: Joi.number().integer().example(1013).description('Size of the HTML part in bytes')
|
|
950
|
-
})
|
|
1010
|
+
})
|
|
1011
|
+
.description('Sizes of different message parts')
|
|
1012
|
+
.label('TextDetailEncodedSize'),
|
|
951
1013
|
plain: Joi.string().example('Hello from myself!').description('Plain text version of the message'),
|
|
952
1014
|
html: Joi.string().example('<p>Hello from myself!</p>').description('HTML version of the message'),
|
|
953
1015
|
hasMore: Joi.boolean().example(false).description('Whether the message content was truncated (true if more content is available via separate API call)')
|
|
@@ -958,7 +1020,7 @@ const messageDetailsSchema = Joi.object({
|
|
|
958
1020
|
Joi.object({
|
|
959
1021
|
message: Joi.string().max(256).required().example('AAAAAQAACnA').description('EmailEngine identifier of the bounce notification'),
|
|
960
1022
|
recipient: Joi.string().email().example('recipient@example.com').description('Email address that bounced'),
|
|
961
|
-
action: Joi.string().example('failed').description('Bounce action (failed, delayed, etc.)'),
|
|
1023
|
+
action: Joi.string().example('failed').description('Bounce action (failed, delayed, etc.)').label('BounceAction'),
|
|
962
1024
|
response: Joi.object({
|
|
963
1025
|
message: Joi.string().example('550 5.1.1 No such user').description('Error message from the receiving server'),
|
|
964
1026
|
status: Joi.string().example('5.1.1').description('SMTP status code')
|
|
@@ -1027,21 +1089,23 @@ const mailboxesSchema = Joi.array()
|
|
|
1027
1089
|
)
|
|
1028
1090
|
.label('MailboxesList');
|
|
1029
1091
|
|
|
1030
|
-
const shortMailboxesSchema = Joi.array()
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
.
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
)
|
|
1092
|
+
const shortMailboxesSchema = Joi.array()
|
|
1093
|
+
.items(
|
|
1094
|
+
Joi.object({
|
|
1095
|
+
path: Joi.string().required().example('Kalender/S&APw-nnip&AOQ-evad').description('Full path to the mailbox').label('MailboxPath'),
|
|
1096
|
+
delimiter: Joi.string().example('/').description('Hierarchy delimiter character used in paths'),
|
|
1097
|
+
parentPath: Joi.string().required().example('Kalender').description('Path to the parent mailbox').label('MailboxParentPath'),
|
|
1098
|
+
name: Joi.string().required().example('Sünnipäevad').description('Display name of the mailbox').label('MailboxName'),
|
|
1099
|
+
listed: Joi.boolean().example(true).description('Whether this mailbox appears in LIST command results').label('MailboxListed'),
|
|
1100
|
+
subscribed: Joi.boolean().example(true).description('Whether the user is subscribed to this mailbox').label('MailboxSubscribed'),
|
|
1101
|
+
specialUse: Joi.string()
|
|
1102
|
+
.example('\\Sent')
|
|
1103
|
+
.valid('\\All', '\\Archive', '\\Drafts', '\\Flagged', '\\Junk', '\\Sent', '\\Trash', '\\Inbox')
|
|
1104
|
+
.description('Special folder type (Inbox, Sent, Drafts, etc.)')
|
|
1105
|
+
.label('MailboxSpecialUse')
|
|
1106
|
+
}).label('MailboxShortResponseItem')
|
|
1107
|
+
)
|
|
1108
|
+
.label('ShortMailboxes');
|
|
1045
1109
|
|
|
1046
1110
|
const licenseSchema = Joi.object({
|
|
1047
1111
|
active: Joi.boolean().example(true).description('Whether a valid license is currently active'),
|
|
@@ -1056,18 +1120,25 @@ const licenseSchema = Joi.object({
|
|
|
1056
1120
|
.allow(false)
|
|
1057
1121
|
.label('LicenseDetails'),
|
|
1058
1122
|
suspended: Joi.boolean().example(false).description('Whether email operations are suspended due to license issues')
|
|
1059
|
-
});
|
|
1123
|
+
}).label('LicenseInfo');
|
|
1060
1124
|
|
|
1061
1125
|
const lastErrorSchema = Joi.object({
|
|
1062
|
-
response: Joi.string()
|
|
1126
|
+
response: Joi.string()
|
|
1127
|
+
.example('Token request failed for gmail (refresh_token, HTTP 400): invalid_grant - Token has been expired or revoked.')
|
|
1128
|
+
.description('Human-readable error message'),
|
|
1063
1129
|
serverResponseCode: Joi.string().example('OauthRenewError').description('Error code or classification'),
|
|
1064
1130
|
tokenRequest: Joi.object({
|
|
1065
|
-
grant: Joi.string()
|
|
1066
|
-
|
|
1067
|
-
|
|
1131
|
+
grant: Joi.string()
|
|
1132
|
+
.valid('refresh_token', 'authorization_code')
|
|
1133
|
+
.example('refresh_token')
|
|
1134
|
+
.description('OAuth2 grant type being requested')
|
|
1135
|
+
.label('OAuthGrant'),
|
|
1136
|
+
provider: Joi.string().max(256).example('gmail').description('OAuth2 provider name').label('OAuthProvider'),
|
|
1137
|
+
status: Joi.number().integer().example(400).description('HTTP status code from the OAuth2 server').label('OAuthStatusCode'),
|
|
1068
1138
|
clientId: Joi.string()
|
|
1069
1139
|
.example('1023289917884-h3nu00e9cb7h252e24c23sv19l8k57ah.apps.googleusercontent.com')
|
|
1070
|
-
.description('OAuth2 client ID used for authentication')
|
|
1140
|
+
.description('OAuth2 client ID used for authentication')
|
|
1141
|
+
.label('OAuthClientId'),
|
|
1071
1142
|
scopes: Joi.array()
|
|
1072
1143
|
.items(Joi.string().example('https://mail.google.com/').label('ScopeEntry').description('OAuth2 permission scope'))
|
|
1073
1144
|
.description('Requested OAuth2 permission scopes')
|
|
@@ -1079,7 +1150,10 @@ const lastErrorSchema = Joi.object({
|
|
|
1079
1150
|
})
|
|
1080
1151
|
.description('Raw error response from the OAuth2 server')
|
|
1081
1152
|
.unknown()
|
|
1082
|
-
|
|
1153
|
+
.label('OAuthTokenErrorResponse')
|
|
1154
|
+
})
|
|
1155
|
+
.description('Details about the failed OAuth2 token request')
|
|
1156
|
+
.label('OAuthTokenRequestError')
|
|
1083
1157
|
}).label('AccountErrorEntry');
|
|
1084
1158
|
|
|
1085
1159
|
const templateSchemas = {
|
|
@@ -1266,17 +1340,24 @@ const accountSchemas = {
|
|
|
1266
1340
|
.description(
|
|
1267
1341
|
'Override global IMAP indexing strategy for this account. "full" tracks all changes including deletions, "fast" only detects new messages.'
|
|
1268
1342
|
)
|
|
1269
|
-
.label('
|
|
1343
|
+
.label('AccountImapIndexer')
|
|
1270
1344
|
};
|
|
1271
1345
|
|
|
1272
|
-
const googleProjectIdSchema = Joi.string()
|
|
1346
|
+
const googleProjectIdSchema = Joi.string()
|
|
1347
|
+
.trim()
|
|
1348
|
+
.allow('', false, null)
|
|
1349
|
+
.max(256)
|
|
1350
|
+
.example('project-name-425411')
|
|
1351
|
+
.description('Google Cloud Project ID')
|
|
1352
|
+
.label('GoogleProjectId');
|
|
1273
1353
|
const googleTopicNameSchema = Joi.string()
|
|
1274
1354
|
.trim()
|
|
1275
1355
|
.allow('', false, null)
|
|
1276
1356
|
.pattern(/^(?!goog)[A-Za-z][A-Za-z0-9\-_.~+%]{2,254}$/)
|
|
1277
1357
|
.max(256)
|
|
1278
1358
|
.example('ee-pub-12345')
|
|
1279
|
-
.description('Google Pub/Sub topic name for Gmail push notifications')
|
|
1359
|
+
.description('Google Pub/Sub topic name for Gmail push notifications')
|
|
1360
|
+
.label('GoogleTopicName');
|
|
1280
1361
|
|
|
1281
1362
|
const googleSubscriptionNameSchema = Joi.string()
|
|
1282
1363
|
.trim()
|
|
@@ -1284,7 +1365,8 @@ const googleSubscriptionNameSchema = Joi.string()
|
|
|
1284
1365
|
.pattern(/^(?!goog)[A-Za-z][A-Za-z0-9\-_.~+%]{2,254}$/)
|
|
1285
1366
|
.max(256)
|
|
1286
1367
|
.example('ee-sub-12345')
|
|
1287
|
-
.description('Google Pub/Sub subscription name')
|
|
1368
|
+
.description('Google Pub/Sub subscription name')
|
|
1369
|
+
.label('GoogleSubscriptionName');
|
|
1288
1370
|
|
|
1289
1371
|
const googleWorkspaceAccountsSchema = Joi.boolean()
|
|
1290
1372
|
.truthy('Y', 'true', '1', 'on')
|
|
@@ -1304,7 +1386,8 @@ const oauthCreateSchema = {
|
|
|
1304
1386
|
.valid(...Object.keys(OAUTH_PROVIDERS))
|
|
1305
1387
|
.example('gmail')
|
|
1306
1388
|
.required()
|
|
1307
|
-
.description('OAuth2 provider type')
|
|
1389
|
+
.description('OAuth2 provider type')
|
|
1390
|
+
.label('CreateOAuth2Provider'),
|
|
1308
1391
|
|
|
1309
1392
|
enabled: Joi.boolean()
|
|
1310
1393
|
.truthy('Y', 'true', '1', 'on')
|
|
@@ -1337,7 +1420,13 @@ const oauthCreateSchema = {
|
|
|
1337
1420
|
.example('boT7Q~dUljnfFdVuqpC11g8nGMjO8kpRAv-ZB')
|
|
1338
1421
|
.description('OAuth2 client secret from the provider'),
|
|
1339
1422
|
|
|
1340
|
-
baseScopes: Joi.string()
|
|
1423
|
+
baseScopes: Joi.string()
|
|
1424
|
+
.empty('')
|
|
1425
|
+
.trim()
|
|
1426
|
+
.valid('imap', 'api', 'pubsub')
|
|
1427
|
+
.example('imap')
|
|
1428
|
+
.description('Connection type (IMAP, API, or Pub/Sub)')
|
|
1429
|
+
.label('OAuth2BaseScopes'),
|
|
1341
1430
|
|
|
1342
1431
|
pubSubApp: Joi.string()
|
|
1343
1432
|
.empty('')
|
|
@@ -1345,7 +1434,8 @@ const oauthCreateSchema = {
|
|
|
1345
1434
|
.max(512)
|
|
1346
1435
|
.example('AAAAAQAACnA')
|
|
1347
1436
|
.allow(false, null)
|
|
1348
|
-
.description('Pub/Sub application ID for Gmail push notifications')
|
|
1437
|
+
.description('Pub/Sub application ID for Gmail push notifications')
|
|
1438
|
+
.label('PubSubAppId'),
|
|
1349
1439
|
|
|
1350
1440
|
extraScopes: Joi.any()
|
|
1351
1441
|
.alter({
|
|
@@ -1354,8 +1444,9 @@ const oauthCreateSchema = {
|
|
|
1354
1444
|
.allow('')
|
|
1355
1445
|
.trim()
|
|
1356
1446
|
.example('User.Read')
|
|
1357
|
-
.max(10 * 1024)
|
|
1358
|
-
|
|
1447
|
+
.max(10 * 1024)
|
|
1448
|
+
.label('OAuth2ExtraScopesWeb'),
|
|
1449
|
+
api: () => Joi.array().items(Joi.string().trim().max(255).example('User.Read').label('ExtraScopeEntry')).label('OAuth2ExtraScopesApi')
|
|
1359
1450
|
})
|
|
1360
1451
|
.description('Additional OAuth2 permission scopes'),
|
|
1361
1452
|
|
|
@@ -1366,8 +1457,9 @@ const oauthCreateSchema = {
|
|
|
1366
1457
|
.allow('')
|
|
1367
1458
|
.trim()
|
|
1368
1459
|
.example('SMTP.Send')
|
|
1369
|
-
.max(10 * 1024)
|
|
1370
|
-
|
|
1460
|
+
.max(10 * 1024)
|
|
1461
|
+
.label('OAuth2SkipScopesWeb'),
|
|
1462
|
+
api: () => Joi.array().items(Joi.string().trim().max(255).example('SMTP.Send').label('SkipScopeEntry')).label('OAuth2SkipScopesApi')
|
|
1371
1463
|
})
|
|
1372
1464
|
.description('OAuth2 scopes to exclude from the default set'),
|
|
1373
1465
|
|
|
@@ -1381,7 +1473,8 @@ const oauthCreateSchema = {
|
|
|
1381
1473
|
otherwise: Joi.optional().valid(false, null)
|
|
1382
1474
|
})
|
|
1383
1475
|
.example('7103296518315821565203')
|
|
1384
|
-
.description('Service account unique ID (for 2-legged OAuth2)')
|
|
1476
|
+
.description('Service account unique ID (for 2-legged OAuth2)')
|
|
1477
|
+
.label('ServiceClientId'),
|
|
1385
1478
|
|
|
1386
1479
|
googleProjectId: googleProjectIdSchema,
|
|
1387
1480
|
googleWorkspaceAccounts: googleWorkspaceAccountsSchema,
|
|
@@ -1459,15 +1552,16 @@ const oauthCreateSchema = {
|
|
|
1459
1552
|
})
|
|
1460
1553
|
.example('https://myservice.com/oauth')
|
|
1461
1554
|
.description('OAuth2 redirect URI configured in the provider')
|
|
1555
|
+
.label('OAuth2AppRedirectUrl')
|
|
1462
1556
|
};
|
|
1463
1557
|
|
|
1464
1558
|
const tokenRestrictionsSchema = Joi.object({
|
|
1465
1559
|
referrers: Joi.array()
|
|
1466
1560
|
.items(Joi.string())
|
|
1467
|
-
.empty('')
|
|
1561
|
+
.empty(Joi.valid('', false))
|
|
1468
1562
|
.single()
|
|
1469
|
-
.allow(
|
|
1470
|
-
.default(
|
|
1563
|
+
.allow(null)
|
|
1564
|
+
.default(null)
|
|
1471
1565
|
.example(['*web.domain.org/*', '*.domain.org/*', 'https://domain.org/*'])
|
|
1472
1566
|
.label('ReferrerAllowlist')
|
|
1473
1567
|
.description('HTTP referrer patterns that are allowed to use this token (wildcards supported)'),
|
|
@@ -1478,10 +1572,10 @@ const tokenRestrictionsSchema = Joi.object({
|
|
|
1478
1572
|
cidr: 'optional'
|
|
1479
1573
|
})
|
|
1480
1574
|
)
|
|
1481
|
-
.empty('')
|
|
1575
|
+
.empty(Joi.valid('', false))
|
|
1482
1576
|
.single()
|
|
1483
|
-
.allow(
|
|
1484
|
-
.default(
|
|
1577
|
+
.allow(null)
|
|
1578
|
+
.default(null)
|
|
1485
1579
|
.example(['1.2.3.4', '5.6.7.8', '127.0.0.0/8'])
|
|
1486
1580
|
.label('AddressAllowlist')
|
|
1487
1581
|
.description('IP addresses or CIDR ranges allowed to use this token'),
|
|
@@ -1489,14 +1583,15 @@ const tokenRestrictionsSchema = Joi.object({
|
|
|
1489
1583
|
maxRequests: Joi.number().integer().min(1).example(20).description('Maximum requests allowed in the time window'),
|
|
1490
1584
|
timeWindow: Joi.number().integer().min(1).example(2).description('Time window duration in seconds')
|
|
1491
1585
|
})
|
|
1492
|
-
.
|
|
1493
|
-
.
|
|
1586
|
+
.empty(Joi.valid('', false))
|
|
1587
|
+
.allow(null)
|
|
1588
|
+
.default(null)
|
|
1494
1589
|
.example({ maxRequests: 20, timeWindow: 2 })
|
|
1495
1590
|
.label('AddressRateLimit')
|
|
1496
1591
|
.description('Rate limiting configuration for this token')
|
|
1497
1592
|
})
|
|
1498
|
-
.empty('')
|
|
1499
|
-
.allow(
|
|
1593
|
+
.empty(Joi.valid('', false))
|
|
1594
|
+
.allow(null)
|
|
1500
1595
|
.label('TokenRestrictions')
|
|
1501
1596
|
.description('Security restrictions for API token usage');
|
|
1502
1597
|
|
|
@@ -1539,13 +1634,15 @@ const defaultAccountTypeSchema = Joi.string()
|
|
|
1539
1634
|
const outboxEntrySchema = Joi.object({
|
|
1540
1635
|
queueId: Joi.string().example('1869c5692565f756b33').description('Unique queue entry identifier'),
|
|
1541
1636
|
account: accountIdSchema.required(),
|
|
1542
|
-
source: Joi.string().example('smtp').valid('smtp', 'api').description('How this message entered the queue'),
|
|
1637
|
+
source: Joi.string().example('smtp').valid('smtp', 'api').description('How this message entered the queue').label('OutboxSource'),
|
|
1543
1638
|
|
|
1544
1639
|
messageId: Joi.string().max(996).example('<test123@example.com>').description('Message-ID header value'),
|
|
1545
1640
|
envelope: Joi.object({
|
|
1546
1641
|
from: Joi.string().email().allow('').example('sender@example.com'),
|
|
1547
|
-
to: Joi.array().items(Joi.string().email().required().example('recipient@example.com'))
|
|
1548
|
-
})
|
|
1642
|
+
to: Joi.array().items(Joi.string().email().required().example('recipient@example.com')).label('OutboxEnvelopeTo')
|
|
1643
|
+
})
|
|
1644
|
+
.description('SMTP envelope information')
|
|
1645
|
+
.label('OutboxEnvelope'),
|
|
1549
1646
|
|
|
1550
1647
|
subject: Joi.string()
|
|
1551
1648
|
.allow('')
|
|
@@ -1561,7 +1658,7 @@ const outboxEntrySchema = Joi.object({
|
|
|
1561
1658
|
attempts: Joi.number().integer().example(3).description('Maximum delivery attempts before marking as failed'),
|
|
1562
1659
|
|
|
1563
1660
|
progress: Joi.object({
|
|
1564
|
-
status: Joi.string().valid('queued', 'processing', 'submitted', 'error').example('queued').description('Current delivery status'),
|
|
1661
|
+
status: Joi.string().valid('queued', 'processing', 'submitted', 'error').example('queued').description('Current delivery status').label('OutboxStatus'),
|
|
1565
1662
|
response: Joi.string().example('250 Message Accepted').description('SMTP server response (when status is "processing")'),
|
|
1566
1663
|
error: Joi.object({
|
|
1567
1664
|
message: Joi.string().example('Authentication failed').description('Error description'),
|
|
@@ -1586,7 +1683,8 @@ const messageReferenceSchema = Joi.object({
|
|
|
1586
1683
|
.valid('forward', 'reply', 'reply-all')
|
|
1587
1684
|
.example('reply')
|
|
1588
1685
|
.default('reply')
|
|
1589
|
-
.description('Action type: "reply" (reply to sender), "reply-all" (reply to all recipients), or "forward" (forward to new recipients)')
|
|
1686
|
+
.description('Action type: "reply" (reply to sender), "reply-all" (reply to all recipients), or "forward" (forward to new recipients)')
|
|
1687
|
+
.label('MessageAction'),
|
|
1590
1688
|
|
|
1591
1689
|
inline: Joi.boolean()
|
|
1592
1690
|
.truthy('Y', 'true', '1')
|
|
@@ -1643,6 +1741,96 @@ const headerTimeoutSchema = Joi.number()
|
|
|
1643
1741
|
.description('Request timeout in milliseconds (overrides EENGINE_TIMEOUT environment variable)')
|
|
1644
1742
|
.label('X-EE-Timeout');
|
|
1645
1743
|
|
|
1744
|
+
// Export schemas
|
|
1745
|
+
const exportRequestSchema = Joi.object({
|
|
1746
|
+
folders: Joi.array()
|
|
1747
|
+
.items(Joi.string().max(1024).example('INBOX'))
|
|
1748
|
+
.single()
|
|
1749
|
+
.description(
|
|
1750
|
+
'Folder paths or special-use flags (e.g., \\Inbox, \\Sent, \\All) to export from. If empty/omitted, Gmail/Outlook API accounts export from All Mail folder; other accounts export all folders except Junk and Trash.'
|
|
1751
|
+
)
|
|
1752
|
+
.label('ExportFolders'),
|
|
1753
|
+
startDate: Joi.date().iso().required().example('2024-01-01T00:00:00Z').description('Export messages from this date'),
|
|
1754
|
+
endDate: Joi.date().iso().required().example('2024-12-31T23:59:59Z').description('Export messages until this date'),
|
|
1755
|
+
textType: Joi.string()
|
|
1756
|
+
.valid('plain', 'html', '*')
|
|
1757
|
+
.default('*')
|
|
1758
|
+
.example('*')
|
|
1759
|
+
.description('Text content to include: "plain", "html", "*" (both), or omit for metadata only')
|
|
1760
|
+
.label('ExportTextType'),
|
|
1761
|
+
maxBytes: Joi.number()
|
|
1762
|
+
.integer()
|
|
1763
|
+
.min(0)
|
|
1764
|
+
.default(5 * 1024 * 1024)
|
|
1765
|
+
.example(5242880)
|
|
1766
|
+
.description('Maximum bytes for text content (0 = unlimited)'),
|
|
1767
|
+
includeAttachments: Joi.boolean()
|
|
1768
|
+
.truthy('Y', 'true', '1')
|
|
1769
|
+
.falsy('N', 'false', 0)
|
|
1770
|
+
.default(false)
|
|
1771
|
+
.description('Include attachment content as base64 blob in attachments array')
|
|
1772
|
+
})
|
|
1773
|
+
.custom((value, helpers) => {
|
|
1774
|
+
if (value.startDate && value.endDate && value.startDate >= value.endDate) {
|
|
1775
|
+
return helpers.error('any.invalid');
|
|
1776
|
+
}
|
|
1777
|
+
return value;
|
|
1778
|
+
}, 'date range validation')
|
|
1779
|
+
.messages({ 'any.invalid': 'startDate must be before endDate' })
|
|
1780
|
+
.label('ExportRequest');
|
|
1781
|
+
|
|
1782
|
+
const exportProgressSchema = Joi.object({
|
|
1783
|
+
foldersScanned: Joi.number().integer().example(1).description('Number of folders scanned'),
|
|
1784
|
+
foldersTotal: Joi.number().integer().example(2).description('Total number of folders to scan'),
|
|
1785
|
+
messagesQueued: Joi.number().integer().example(1500).description('Number of messages queued for export'),
|
|
1786
|
+
messagesExported: Joi.number().integer().example(500).description('Number of messages exported'),
|
|
1787
|
+
messagesSkipped: Joi.number().integer().example(5).description('Number of messages skipped (deleted or inaccessible)'),
|
|
1788
|
+
bytesWritten: Joi.number().integer().example(52428800).description('Bytes written to export file')
|
|
1789
|
+
}).label('ExportProgress');
|
|
1790
|
+
|
|
1791
|
+
const exportStatusSchema = Joi.object({
|
|
1792
|
+
exportId: Joi.string().example('exp_abc123def456abc123def456').description('Export job identifier'),
|
|
1793
|
+
status: Joi.string()
|
|
1794
|
+
.valid('queued', 'processing', 'completed', 'failed', 'cancelled')
|
|
1795
|
+
.example('processing')
|
|
1796
|
+
.description('Export status')
|
|
1797
|
+
.label('ExportStatusValue'),
|
|
1798
|
+
phase: Joi.string().valid('indexing', 'exporting', 'complete').example('indexing').description('Current export phase').label('ExportPhase'),
|
|
1799
|
+
folders: Joi.array().items(Joi.string().label('ExportFolderItem')).description('Folders being exported').label('ExportStatusFolders'),
|
|
1800
|
+
startDate: Joi.date().iso().example('2024-01-01T00:00:00Z').description('Export start date filter'),
|
|
1801
|
+
endDate: Joi.date().iso().example('2024-12-31T23:59:59Z').description('Export end date filter'),
|
|
1802
|
+
isEncrypted: Joi.boolean().example(false).description('Whether the export file is encrypted'),
|
|
1803
|
+
progress: exportProgressSchema,
|
|
1804
|
+
created: Joi.date().iso().example('2024-01-15T10:30:00Z').description('When export was created'),
|
|
1805
|
+
expiresAt: Joi.date().iso().example('2024-01-16T10:30:00Z').description('When export file expires'),
|
|
1806
|
+
error: Joi.string().allow(null).description('Error message if export failed')
|
|
1807
|
+
}).label('ExportStatus');
|
|
1808
|
+
|
|
1809
|
+
const exportListEntrySchema = Joi.object({
|
|
1810
|
+
exportId: Joi.string().example('exp_abc123def456abc123def456').description('Export job identifier'),
|
|
1811
|
+
status: Joi.string()
|
|
1812
|
+
.valid('queued', 'processing', 'completed', 'failed', 'cancelled')
|
|
1813
|
+
.example('completed')
|
|
1814
|
+
.description('Export status')
|
|
1815
|
+
.label('ExportListStatusValue'),
|
|
1816
|
+
created: Joi.date().iso().example('2024-01-15T10:30:00Z').description('When export was created'),
|
|
1817
|
+
expiresAt: Joi.date().iso().example('2024-01-16T10:30:00Z').description('When export file expires')
|
|
1818
|
+
}).label('ExportListEntry');
|
|
1819
|
+
|
|
1820
|
+
const exportListSchema = Joi.object({
|
|
1821
|
+
total: Joi.number().integer().example(5).description('Total number of exports'),
|
|
1822
|
+
page: Joi.number().integer().example(0).description('Current page number'),
|
|
1823
|
+
pages: Joi.number().integer().example(1).description('Total number of pages'),
|
|
1824
|
+
exports: Joi.array().items(exportListEntrySchema).description('Export entries').label('ExportEntries')
|
|
1825
|
+
}).label('ExportList');
|
|
1826
|
+
|
|
1827
|
+
const exportIdSchema = Joi.string()
|
|
1828
|
+
.pattern(/^exp_[a-f0-9]{24}$/)
|
|
1829
|
+
.required()
|
|
1830
|
+
.example('exp_abc123def456abc123def456')
|
|
1831
|
+
.description('Export job identifier')
|
|
1832
|
+
.label('ExportId');
|
|
1833
|
+
|
|
1646
1834
|
module.exports = {
|
|
1647
1835
|
ADDRESS_STRATEGIES,
|
|
1648
1836
|
|
|
@@ -1684,7 +1872,12 @@ module.exports = {
|
|
|
1684
1872
|
googleWorkspaceAccountsSchema,
|
|
1685
1873
|
messageReferenceSchema,
|
|
1686
1874
|
idempotencyKeySchema,
|
|
1687
|
-
headerTimeoutSchema
|
|
1875
|
+
headerTimeoutSchema,
|
|
1876
|
+
exportRequestSchema,
|
|
1877
|
+
exportStatusSchema,
|
|
1878
|
+
exportListSchema,
|
|
1879
|
+
exportProgressSchema,
|
|
1880
|
+
exportIdSchema
|
|
1688
1881
|
};
|
|
1689
1882
|
|
|
1690
1883
|
/*
|