emailengine-app 2.68.1 → 2.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/deploy.yml +8 -3
- package/.github/workflows/release.yaml +6 -0
- package/CHANGELOG.md +59 -0
- package/Gruntfile.js +3 -1
- package/config/default.toml +2 -0
- package/data/google-crawlers.json +7 -1
- package/getswagger.sh +40 -4
- package/gettext-extract.js +163 -0
- package/lib/account.js +135 -72
- package/lib/api-routes/account-routes.js +684 -106
- package/lib/api-routes/blocklist-routes.js +344 -0
- package/lib/api-routes/chat-routes.js +32 -14
- package/lib/api-routes/delivery-test-routes.js +346 -0
- package/lib/api-routes/export-routes.js +28 -14
- package/lib/api-routes/gateway-routes.js +427 -0
- package/lib/api-routes/license-routes.js +156 -0
- package/lib/api-routes/mailbox-routes.js +344 -0
- package/lib/api-routes/message-routes.js +221 -187
- package/lib/api-routes/oauth2-app-routes.js +697 -0
- package/lib/api-routes/outbox-routes.js +185 -0
- package/lib/api-routes/pubsub-routes.js +102 -0
- package/lib/api-routes/route-helpers.js +58 -0
- package/lib/api-routes/settings-routes.js +357 -0
- package/lib/api-routes/stats-routes.js +111 -0
- package/lib/api-routes/submit-routes.js +461 -0
- package/lib/api-routes/template-routes.js +60 -75
- package/lib/api-routes/token-routes.js +297 -0
- package/lib/api-routes/webhook-route-routes.js +181 -0
- package/lib/autodetect-imap-settings.js +0 -2
- package/lib/consts.js +5 -0
- package/lib/email-client/base-client.js +28 -6
- package/lib/email-client/gmail-client.js +133 -112
- package/lib/email-client/imap/mailbox.js +34 -11
- package/lib/email-client/imap/subconnection.js +20 -13
- package/lib/email-client/imap/sync-operations.js +131 -3
- package/lib/email-client/imap-client.js +152 -75
- package/lib/email-client/notification-handler.js +1 -4
- package/lib/email-client/outlook-client.js +134 -75
- package/lib/export.js +97 -20
- package/lib/feature-flags.js +2 -2
- package/lib/gateway.js +4 -9
- package/lib/get-raw-email.js +5 -5
- package/lib/imapproxy/imap-core/lib/commands/starttls.js +18 -0
- package/lib/imapproxy/imap-core/lib/imap-command.js +6 -1
- package/lib/imapproxy/imap-core/lib/imap-connection.js +106 -24
- package/lib/imapproxy/imap-core/lib/imap-server.js +24 -0
- package/lib/imapproxy/imap-core/lib/imap-stream.js +26 -0
- package/lib/logger.js +24 -21
- package/lib/message-port-stream.js +113 -16
- package/lib/metrics-collector.js +0 -2
- package/lib/oauth2-apps.js +13 -4
- package/lib/outbox.js +24 -40
- package/lib/redis-operations.js +1 -1
- package/lib/reject-worker-calls.js +42 -0
- package/lib/routes-ui.js +37 -8778
- package/lib/schemas.js +429 -84
- package/lib/sentry.js +139 -0
- package/lib/settings.js +9 -3
- package/lib/stream-encrypt.js +1 -1
- package/lib/templates.js +1 -1
- package/lib/tokens.js +5 -3
- package/lib/tools.js +70 -4
- package/lib/ui-routes/account-routes.js +45 -212
- package/lib/ui-routes/admin-config-routes.js +928 -489
- package/lib/ui-routes/admin-entities-routes.js +1 -0
- package/lib/ui-routes/auth-routes.js +1339 -0
- package/lib/ui-routes/dashboard-routes.js +188 -0
- package/lib/ui-routes/document-store-routes.js +800 -0
- package/lib/ui-routes/export-routes.js +217 -0
- package/lib/ui-routes/internals-routes.js +354 -0
- package/lib/ui-routes/network-config-routes.js +759 -0
- package/lib/ui-routes/{oauth-routes.js → oauth-config-routes.js} +369 -91
- package/lib/ui-routes/route-helpers.js +314 -0
- package/lib/ui-routes/smtp-test-routes.js +236 -0
- package/lib/ui-routes/unsubscribe-routes.js +232 -0
- package/lib/webhook-request.js +36 -0
- package/lib/webhooks.js +8 -4
- package/package.json +13 -12
- package/sbom.json +1 -1
- package/server.js +222 -39
- package/static/licenses.html +160 -300
- package/translations/messages.pot +112 -132
- package/update-info.sh +19 -1
- package/views/config/logging.hbs +48 -0
- package/views/dashboard.hbs +7 -26
- package/views/internals/index.hbs +15 -0
- package/views/tokens/index.hbs +9 -0
- package/workers/api.js +200 -4424
- package/workers/documents.js +2 -22
- package/workers/export.js +103 -104
- package/workers/imap-proxy.js +3 -23
- package/workers/imap.js +32 -36
- package/workers/smtp.js +2 -22
- package/workers/submit.js +26 -35
- package/workers/webhooks.js +9 -43
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Boom = require('@hapi/boom');
|
|
4
|
+
const Joi = require('joi');
|
|
5
|
+
const { fetch: fetchCmd } = require('undici');
|
|
6
|
+
const { redis } = require('../db');
|
|
7
|
+
const { Account } = require('../account');
|
|
8
|
+
const { Gateway } = require('../gateway');
|
|
9
|
+
const getSecret = require('../get-secret');
|
|
10
|
+
const { failAction, httpAgent } = require('../tools');
|
|
11
|
+
const { accountIdSchema, errorResponses } = require('../schemas');
|
|
12
|
+
const { REDIS_PREFIX } = require('../consts');
|
|
13
|
+
const packageData = require('../../package.json');
|
|
14
|
+
|
|
15
|
+
async function init(args) {
|
|
16
|
+
const { server, call, CORS_CONFIG, SMTP_TEST_HOST } = args;
|
|
17
|
+
|
|
18
|
+
server.route({
|
|
19
|
+
method: 'POST',
|
|
20
|
+
path: '/v1/delivery-test/account/{account}',
|
|
21
|
+
async handler(request) {
|
|
22
|
+
let accountObject = new Account({
|
|
23
|
+
redis,
|
|
24
|
+
account: request.params.account,
|
|
25
|
+
call,
|
|
26
|
+
secret: await getSecret(),
|
|
27
|
+
timeout: request.headers['x-ee-timeout']
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// throws if account does not exist
|
|
32
|
+
let accountData = await accountObject.loadAccountData();
|
|
33
|
+
|
|
34
|
+
request.logger.info({ msg: 'Requested SMTP delivery test', account: request.params.account });
|
|
35
|
+
|
|
36
|
+
let headers = {
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
'User-Agent': `${packageData.name}/${packageData.version} (+${packageData.homepage})`
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let res = await fetchCmd(`${SMTP_TEST_HOST}/test-address`, {
|
|
42
|
+
method: 'post',
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
version: packageData.version,
|
|
45
|
+
requestor: '@postalsys/emailengine-app'
|
|
46
|
+
}),
|
|
47
|
+
headers,
|
|
48
|
+
dispatcher: httpAgent.retry
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
let err = new Error(`Invalid response: ${res.status} ${res.statusText}`);
|
|
53
|
+
err.statusCode = res.status;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
err.details = await res.json();
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// ignore
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let testAccount = await res.json();
|
|
65
|
+
if (!testAccount || !testAccount.user) {
|
|
66
|
+
let err = new Error(`Invalid test account`);
|
|
67
|
+
err.statusCode = 500;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
err.details = testAccount;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
// ignore
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (request.payload.gateway) {
|
|
79
|
+
// try to load the gateway, throws if not set
|
|
80
|
+
let gatewayObject = new Gateway({ redis, gateway: request.payload.gateway, call, secret: await getSecret() });
|
|
81
|
+
await gatewayObject.loadGatewayData();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
let now = new Date().toISOString();
|
|
86
|
+
let queueResponse = await accountObject.queueMessage(
|
|
87
|
+
{
|
|
88
|
+
account: accountData.account,
|
|
89
|
+
subject: `Delivery test ${now}`,
|
|
90
|
+
text: `Hello
|
|
91
|
+
|
|
92
|
+
This is an automated email to test deliverability settings. If you see this email, you can safely delete it.
|
|
93
|
+
|
|
94
|
+
${now}`,
|
|
95
|
+
html: `<p>Hello</p>
|
|
96
|
+
<p>This is an automated email to test deliverability settings. If you see this email, you can safely delete it.</p>
|
|
97
|
+
<p>${now}</p>`,
|
|
98
|
+
from: {
|
|
99
|
+
name: accountData.name,
|
|
100
|
+
address: accountData.email
|
|
101
|
+
},
|
|
102
|
+
to: [{ name: 'Delivery Test Server', address: testAccount.address }],
|
|
103
|
+
copy: false,
|
|
104
|
+
gateway: request.payload.gateway,
|
|
105
|
+
feedbackKey: `${REDIS_PREFIX}test-send:${testAccount.user}`,
|
|
106
|
+
deliveryAttempts: 1
|
|
107
|
+
},
|
|
108
|
+
{ source: 'test' }
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
success: !!queueResponse.queueId,
|
|
113
|
+
deliveryTest: testAccount.user
|
|
114
|
+
};
|
|
115
|
+
} catch (err) {
|
|
116
|
+
return {
|
|
117
|
+
error: err.message
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
request.logger.error({ msg: 'API request failed', err });
|
|
122
|
+
if (Boom.isBoom(err)) {
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
let error = Boom.boomify(err, { statusCode: err.statusCode || 500 });
|
|
126
|
+
if (err.code) {
|
|
127
|
+
error.output.payload.code = err.code;
|
|
128
|
+
}
|
|
129
|
+
if (err.details) {
|
|
130
|
+
error.output.payload.details = err.details;
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
options: {
|
|
136
|
+
description: 'Create delivery test',
|
|
137
|
+
notes: 'Initiate a delivery test',
|
|
138
|
+
tags: ['api', 'Delivery Test'],
|
|
139
|
+
|
|
140
|
+
plugins: {
|
|
141
|
+
'hapi-swagger': {
|
|
142
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500)
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
auth: {
|
|
147
|
+
strategy: 'api-token',
|
|
148
|
+
mode: 'required'
|
|
149
|
+
},
|
|
150
|
+
cors: CORS_CONFIG,
|
|
151
|
+
|
|
152
|
+
validate: {
|
|
153
|
+
options: {
|
|
154
|
+
stripUnknown: false,
|
|
155
|
+
abortEarly: false,
|
|
156
|
+
convert: true
|
|
157
|
+
},
|
|
158
|
+
failAction,
|
|
159
|
+
|
|
160
|
+
params: Joi.object({
|
|
161
|
+
account: accountIdSchema.required()
|
|
162
|
+
}),
|
|
163
|
+
|
|
164
|
+
payload: Joi.object({
|
|
165
|
+
gateway: Joi.string().allow(false, null).empty('').max(256).example(false).description('Optional gateway ID').label('DeliveryTestGateway')
|
|
166
|
+
}).label('DeliveryStartRequest')
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
response: {
|
|
170
|
+
schema: Joi.object({
|
|
171
|
+
success: Joi.boolean()
|
|
172
|
+
.example(true)
|
|
173
|
+
.description('Was the test started. Not present if queueing the test message failed')
|
|
174
|
+
.label('ResponseDeliveryStartSuccess'),
|
|
175
|
+
deliveryTest: Joi.string()
|
|
176
|
+
.guid({
|
|
177
|
+
version: ['uuidv4', 'uuidv5']
|
|
178
|
+
})
|
|
179
|
+
.example('6420a6ad-7f82-4e4f-8112-82a9dad1f34d')
|
|
180
|
+
.description('Test ID. Not present if queueing the test message failed'),
|
|
181
|
+
error: Joi.string()
|
|
182
|
+
.example('Oops, something went wrong')
|
|
183
|
+
.description('Error message. Only present if queueing the test message failed - in that case success and deliveryTest are not set')
|
|
184
|
+
.label('ResponseDeliveryStartError')
|
|
185
|
+
}).label('DeliveryStartResponse'),
|
|
186
|
+
failAction: 'log'
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
server.route({
|
|
192
|
+
method: 'GET',
|
|
193
|
+
path: '/v1/delivery-test/check/{deliveryTest}',
|
|
194
|
+
async handler(request) {
|
|
195
|
+
try {
|
|
196
|
+
request.logger.info({ msg: 'Requested SMTP delivery test check', deliveryTest: request.params.deliveryTest });
|
|
197
|
+
|
|
198
|
+
let deliveryStatus = (await redis.hgetall(`${REDIS_PREFIX}test-send:${request.params.deliveryTest}`)) || {};
|
|
199
|
+
if (deliveryStatus.success === 'false') {
|
|
200
|
+
let err = new Error(`Failed to deliver email`);
|
|
201
|
+
err.statusCode = 500;
|
|
202
|
+
err.details = deliveryStatus;
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let headers = {
|
|
207
|
+
'Content-Type': 'application/json',
|
|
208
|
+
'User-Agent': `${packageData.name}/${packageData.version} (+${packageData.homepage})`
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
let res = await fetchCmd(`${SMTP_TEST_HOST}/test-address/${request.params.deliveryTest}`, {
|
|
212
|
+
method: 'get',
|
|
213
|
+
headers,
|
|
214
|
+
dispatcher: httpAgent.retry
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (!res.ok) {
|
|
218
|
+
let err = new Error(`Invalid response: ${res.status} ${res.statusText}`);
|
|
219
|
+
err.statusCode = res.status;
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
err.details = await res.json();
|
|
223
|
+
} catch (err) {
|
|
224
|
+
// ignore
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let testResponse = await res.json();
|
|
231
|
+
|
|
232
|
+
let success = testResponse && testResponse.status === 'success'; //Default
|
|
233
|
+
|
|
234
|
+
if (testResponse && success) {
|
|
235
|
+
let mainSig =
|
|
236
|
+
testResponse.dkim &&
|
|
237
|
+
testResponse.dkim.results &&
|
|
238
|
+
testResponse.dkim.results.find(entry => entry && entry.status && entry.status.result === 'pass' && entry.status.aligned);
|
|
239
|
+
|
|
240
|
+
if (!mainSig) {
|
|
241
|
+
mainSig =
|
|
242
|
+
testResponse.dkim &&
|
|
243
|
+
testResponse.dkim.results &&
|
|
244
|
+
testResponse.dkim.results.find(entry => entry && entry.status && entry.status.result === 'pass');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!mainSig) {
|
|
248
|
+
mainSig = testResponse.dkim && testResponse.dkim.results && testResponse.dkim.results[0];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
testResponse.mainSig = mainSig || {
|
|
252
|
+
status: {
|
|
253
|
+
result: 'none'
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
if (testResponse.spf && testResponse.spf.status && testResponse.spf.status.comment) {
|
|
258
|
+
testResponse.spf.status.comment = testResponse.spf.status.comment.replace(/^[^:\s]+:\s*/, '');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (testResponse) {
|
|
263
|
+
if (testResponse.status === 'success') {
|
|
264
|
+
delete testResponse.status;
|
|
265
|
+
}
|
|
266
|
+
delete testResponse.user;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return Object.assign({ success }, testResponse || {});
|
|
270
|
+
} catch (err) {
|
|
271
|
+
request.logger.error({ msg: 'API request failed', err });
|
|
272
|
+
if (Boom.isBoom(err)) {
|
|
273
|
+
throw err;
|
|
274
|
+
}
|
|
275
|
+
let error = Boom.boomify(err, { statusCode: err.statusCode || 500 });
|
|
276
|
+
if (err.code) {
|
|
277
|
+
error.output.payload.code = err.code;
|
|
278
|
+
}
|
|
279
|
+
if (err.details) {
|
|
280
|
+
error.output.payload.details = err.details;
|
|
281
|
+
}
|
|
282
|
+
throw error;
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
options: {
|
|
286
|
+
description: 'Check test status',
|
|
287
|
+
notes: 'Check delivery test status',
|
|
288
|
+
tags: ['api', 'Delivery Test'],
|
|
289
|
+
|
|
290
|
+
plugins: {
|
|
291
|
+
'hapi-swagger': {
|
|
292
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500)
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
auth: {
|
|
297
|
+
strategy: 'api-token',
|
|
298
|
+
mode: 'required'
|
|
299
|
+
},
|
|
300
|
+
cors: CORS_CONFIG,
|
|
301
|
+
|
|
302
|
+
validate: {
|
|
303
|
+
options: {
|
|
304
|
+
stripUnknown: false,
|
|
305
|
+
abortEarly: false,
|
|
306
|
+
convert: true
|
|
307
|
+
},
|
|
308
|
+
failAction,
|
|
309
|
+
|
|
310
|
+
params: Joi.object({
|
|
311
|
+
deliveryTest: Joi.string()
|
|
312
|
+
.guid({
|
|
313
|
+
version: ['uuidv4', 'uuidv5']
|
|
314
|
+
})
|
|
315
|
+
.example('6420a6ad-7f82-4e4f-8112-82a9dad1f34d')
|
|
316
|
+
.required()
|
|
317
|
+
.description('Test ID')
|
|
318
|
+
}).label('DeliveryCheckParams')
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
response: {
|
|
322
|
+
schema: Joi.object({
|
|
323
|
+
success: Joi.boolean().example(true).description('Was the test completed').label('ResponseDeliveryCheckSuccess'),
|
|
324
|
+
status: Joi.string()
|
|
325
|
+
.example('pending')
|
|
326
|
+
.description('Test status. Only present while the test message has not yet been received (success=false)')
|
|
327
|
+
.label('ResponseDeliveryCheckStatus'),
|
|
328
|
+
dkim: Joi.object().unknown().description('DKIM results').label('DkimResults'),
|
|
329
|
+
spf: Joi.object().unknown().description('SPF results').label('SpfResults'),
|
|
330
|
+
dmarc: Joi.object().unknown().description('DMARC results').label('DmarcResults'),
|
|
331
|
+
bimi: Joi.object().unknown().description('BIMI results').label('BimiResults'),
|
|
332
|
+
arc: Joi.object().unknown().description('ARC results').label('ArcResults'),
|
|
333
|
+
mainSig: Joi.object()
|
|
334
|
+
.unknown()
|
|
335
|
+
.description('Primary DKIM signature. `status.aligned` should be set, otherwise DKIM check should not be considered as passed.')
|
|
336
|
+
.label('MainSignature')
|
|
337
|
+
})
|
|
338
|
+
.unknown()
|
|
339
|
+
.label('DeliveryCheckResponse'),
|
|
340
|
+
failAction: 'log'
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
module.exports = init;
|
|
@@ -5,21 +5,10 @@ const { Export } = require('../export');
|
|
|
5
5
|
const Boom = require('@hapi/boom');
|
|
6
6
|
const Joi = require('joi');
|
|
7
7
|
const { failAction } = require('../tools');
|
|
8
|
-
const { accountIdSchema, exportRequestSchema, exportStatusSchema, exportListSchema, exportIdSchema } = require('../schemas');
|
|
8
|
+
const { accountIdSchema, exportRequestSchema, exportStatusSchema, exportListSchema, exportIdSchema, errorResponses } = require('../schemas');
|
|
9
9
|
const getSecret = require('../get-secret');
|
|
10
10
|
const { createDecryptStream } = require('../stream-encrypt');
|
|
11
|
-
|
|
12
|
-
function handleError(request, err) {
|
|
13
|
-
request.logger.error({ msg: 'API request failed', err });
|
|
14
|
-
if (Boom.isBoom(err)) {
|
|
15
|
-
throw err;
|
|
16
|
-
}
|
|
17
|
-
const error = Boom.boomify(err, { statusCode: err.statusCode || 500 });
|
|
18
|
-
if (err.code) {
|
|
19
|
-
error.output.payload.code = err.code;
|
|
20
|
-
}
|
|
21
|
-
throw error;
|
|
22
|
-
}
|
|
11
|
+
const { handleError } = require('./route-helpers');
|
|
23
12
|
|
|
24
13
|
async function init(args) {
|
|
25
14
|
const { server, CORS_CONFIG } = args;
|
|
@@ -48,6 +37,12 @@ async function init(args) {
|
|
|
48
37
|
notes: 'Creates a new bulk message export job. The export runs asynchronously and notifies via webhook when complete.',
|
|
49
38
|
tags: ['api', 'Export (Beta)'],
|
|
50
39
|
|
|
40
|
+
plugins: {
|
|
41
|
+
'hapi-swagger': {
|
|
42
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
51
46
|
auth: {
|
|
52
47
|
strategy: 'api-token',
|
|
53
48
|
mode: 'required'
|
|
@@ -101,6 +96,12 @@ async function init(args) {
|
|
|
101
96
|
notes: 'Returns the status and progress of an export job.',
|
|
102
97
|
tags: ['api', 'Export (Beta)'],
|
|
103
98
|
|
|
99
|
+
plugins: {
|
|
100
|
+
'hapi-swagger': {
|
|
101
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500)
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
104
105
|
auth: {
|
|
105
106
|
strategy: 'api-token',
|
|
106
107
|
mode: 'required'
|
|
@@ -178,7 +179,8 @@ async function init(args) {
|
|
|
178
179
|
|
|
179
180
|
plugins: {
|
|
180
181
|
'hapi-swagger': {
|
|
181
|
-
produces: ['application/gzip']
|
|
182
|
+
produces: ['application/gzip'],
|
|
183
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500, 503)
|
|
182
184
|
}
|
|
183
185
|
},
|
|
184
186
|
|
|
@@ -225,6 +227,12 @@ async function init(args) {
|
|
|
225
227
|
notes: 'Cancels a pending export or deletes a completed export. Removes both Redis data and the export file.',
|
|
226
228
|
tags: ['api', 'Export (Beta)'],
|
|
227
229
|
|
|
230
|
+
plugins: {
|
|
231
|
+
'hapi-swagger': {
|
|
232
|
+
responses: errorResponses(400, 401, 403, 404, 429, 500)
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
|
|
228
236
|
auth: {
|
|
229
237
|
strategy: 'api-token',
|
|
230
238
|
mode: 'required'
|
|
@@ -274,6 +282,12 @@ async function init(args) {
|
|
|
274
282
|
notes: 'Lists all exports for an account with pagination.',
|
|
275
283
|
tags: ['api', 'Export (Beta)'],
|
|
276
284
|
|
|
285
|
+
plugins: {
|
|
286
|
+
'hapi-swagger': {
|
|
287
|
+
responses: errorResponses(400, 401, 403, 429, 500)
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
|
|
277
291
|
auth: {
|
|
278
292
|
strategy: 'api-token',
|
|
279
293
|
mode: 'required'
|