@defra/fcp-sfd-frontend-engine 0.6.1 → 0.8.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/dist/index.cjs +155 -78
- package/dist/index.js +152 -76
- package/package.json +1 -1
- package/src/constants/index.js +56 -5
- package/src/constants/patterns.js +9 -1
- package/src/constants/status-codes.js +9 -0
- package/src/index.js +1 -0
- package/src/schemas/business/business-email-schema.js +3 -2
- package/src/schemas/business/business-name-schema.js +4 -2
- package/src/schemas/business/business-phone-schema.js +7 -3
- package/src/schemas/business/business-sbi-schema.js +3 -2
- package/src/schemas/business/business-schemas.js +1 -1
- package/src/schemas/business/business-vat-schema.js +3 -2
- package/src/schemas/customer/customer-crn-schema.js +3 -2
- package/src/schemas/personal/personal-dob-schema.js +16 -6
- package/src/schemas/personal/personal-email-schema.js +3 -2
- package/src/schemas/personal/personal-name-schema.js +10 -4
- package/src/schemas/personal/personal-phone-schema.js +9 -8
- package/src/schemas/personal/personal-schemas.js +1 -1
- package/src/schemas/{address-schema.js → shared/address-schema.js} +23 -9
- package/src/utils/joi.js +21 -0
- package/src/constants/validation-fields-export.js +0 -17
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
// src/index.js
|
|
30
30
|
var index_exports = {};
|
|
31
31
|
__export(index_exports, {
|
|
32
|
+
constants: () => constants,
|
|
32
33
|
mappers: () => mappers,
|
|
33
34
|
presenters: () => presenters,
|
|
34
35
|
schemas: () => schemas,
|
|
@@ -129,17 +130,36 @@ var mappers = {
|
|
|
129
130
|
businessDetails: mapBusinessDetails
|
|
130
131
|
};
|
|
131
132
|
|
|
132
|
-
// src/
|
|
133
|
+
// src/utils/joi.js
|
|
133
134
|
var import_joi = __toESM(require("joi"), 1);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
|
|
136
|
+
// src/constants/patterns.js
|
|
137
|
+
var PHONE_NUMBER_PATTERN = /^\+?(?=[\d ()]*\d)[\d ()]*$/;
|
|
138
|
+
var NO_CONTROL_CHARS_PATTERN = /^[^\x00-\x1f\x7f-\x9f]*$/;
|
|
139
|
+
|
|
140
|
+
// src/utils/joi.js
|
|
141
|
+
var Joi = import_joi.default.extend((joi) => ({
|
|
142
|
+
type: "string",
|
|
143
|
+
base: joi.string(),
|
|
144
|
+
messages: {
|
|
145
|
+
"string.noControlChars": "Field must not contain invalid characters"
|
|
146
|
+
},
|
|
147
|
+
validate(value, helpers) {
|
|
148
|
+
if (typeof value === "string" && !NO_CONTROL_CHARS_PATTERN.test(value)) {
|
|
149
|
+
return { value, errors: helpers.error("string.noControlChars") };
|
|
150
|
+
}
|
|
151
|
+
return { value };
|
|
152
|
+
}
|
|
153
|
+
}));
|
|
154
|
+
|
|
155
|
+
// src/schemas/business/business-sbi-schema.js
|
|
156
|
+
var businessSbiSchema = Joi.object({
|
|
157
|
+
sbi: Joi.string().pattern(/^\d{9}$/).allow("").optional().messages({
|
|
158
|
+
"string.pattern.base": "Enter the full SBI",
|
|
159
|
+
"string.noControlChars": "SBI must not contain invalid characters"
|
|
137
160
|
})
|
|
138
161
|
});
|
|
139
162
|
|
|
140
|
-
// src/schemas/address-schema.js
|
|
141
|
-
var import_joi2 = __toESM(require("joi"), 1);
|
|
142
|
-
|
|
143
163
|
// src/constants/validation-fields.js
|
|
144
164
|
var FIRST_NAME_MAX = 100;
|
|
145
165
|
var LAST_NAME_MAX = 100;
|
|
@@ -155,53 +175,59 @@ var COUNTY_MAX = 60;
|
|
|
155
175
|
var COUNTRY_MAX = 60;
|
|
156
176
|
var POSTCODE_MAX = 8;
|
|
157
177
|
|
|
158
|
-
// src/schemas/address-schema.js
|
|
159
|
-
var addressSchema =
|
|
160
|
-
address1:
|
|
178
|
+
// src/schemas/shared/address-schema.js
|
|
179
|
+
var addressSchema = Joi.object({
|
|
180
|
+
address1: Joi.string().trim().required().max(ADDRESS_LINE_MAX).messages({
|
|
161
181
|
"string.empty": "Enter address line 1, typically the building and street",
|
|
162
182
|
"string.max": `Address line 1 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
163
|
-
"any.required": "Enter address line 1, typically the building and street"
|
|
183
|
+
"any.required": "Enter address line 1, typically the building and street",
|
|
184
|
+
"string.noControlChars": "Address line 1 must not contain invalid characters"
|
|
164
185
|
}),
|
|
165
|
-
address2:
|
|
166
|
-
"string.max": `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less
|
|
186
|
+
address2: Joi.string().trim().allow("").max(ADDRESS_LINE_MAX).messages({
|
|
187
|
+
"string.max": `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
188
|
+
"string.noControlChars": "Address line 2 must not contain invalid characters"
|
|
167
189
|
}),
|
|
168
|
-
address3:
|
|
169
|
-
"string.max": `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less
|
|
190
|
+
address3: Joi.string().trim().allow("").max(ADDRESS_LINE_MAX).messages({
|
|
191
|
+
"string.max": `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
192
|
+
"string.noControlChars": "Address line 3 must not contain invalid characters"
|
|
170
193
|
}),
|
|
171
|
-
city:
|
|
194
|
+
city: Joi.string().trim().required().max(TOWN_CITY_MAX).messages({
|
|
172
195
|
"string.empty": "Enter town or city",
|
|
173
196
|
"string.max": `Town or city must be ${TOWN_CITY_MAX} characters or less`,
|
|
174
|
-
"any.required": "Enter town or city"
|
|
197
|
+
"any.required": "Enter town or city",
|
|
198
|
+
"string.noControlChars": "Town or city must not contain invalid characters"
|
|
175
199
|
}),
|
|
176
|
-
county:
|
|
177
|
-
"string.max": `County must be ${COUNTY_MAX} characters or less
|
|
200
|
+
county: Joi.string().trim().allow("").max(COUNTY_MAX).messages({
|
|
201
|
+
"string.max": `County must be ${COUNTY_MAX} characters or less`,
|
|
202
|
+
"string.noControlChars": "County must not contain invalid characters"
|
|
178
203
|
}),
|
|
179
|
-
postcode:
|
|
204
|
+
postcode: Joi.string().trim().required().max(POSTCODE_MAX).messages({
|
|
180
205
|
"any.required": "Enter a postal code or zip code",
|
|
181
206
|
"string.empty": "Enter a postal code or zip code",
|
|
182
|
-
"string.max": `Postal code or zip code must be ${POSTCODE_MAX} characters or less
|
|
207
|
+
"string.max": `Postal code or zip code must be ${POSTCODE_MAX} characters or less`,
|
|
208
|
+
"string.noControlChars": "Postal code or zip code must not contain invalid characters"
|
|
183
209
|
}),
|
|
184
|
-
country:
|
|
210
|
+
country: Joi.string().trim().required().max(COUNTRY_MAX).messages({
|
|
185
211
|
"string.empty": "Enter a country",
|
|
186
212
|
"string.max": `Country must be ${COUNTRY_MAX} characters or less`,
|
|
187
|
-
"any.required": "Enter a country"
|
|
213
|
+
"any.required": "Enter a country",
|
|
214
|
+
"string.noControlChars": "Country must not contain invalid characters"
|
|
188
215
|
})
|
|
189
216
|
});
|
|
190
217
|
|
|
191
218
|
// src/schemas/business/business-name-schema.js
|
|
192
|
-
var
|
|
193
|
-
|
|
194
|
-
businessName: import_joi3.default.string().required().max(BUSINESS_NAME_MAX).messages({
|
|
219
|
+
var businessNameSchema = Joi.object({
|
|
220
|
+
businessName: Joi.string().trim().required().max(BUSINESS_NAME_MAX).messages({
|
|
195
221
|
"string.empty": "Enter business name",
|
|
196
222
|
"string.max": `Business name must be ${BUSINESS_NAME_MAX} characters or less`,
|
|
197
|
-
"any.required": "Enter business name"
|
|
223
|
+
"any.required": "Enter business name",
|
|
224
|
+
"string.noControlChars": "Business name must not contain invalid characters"
|
|
198
225
|
})
|
|
199
226
|
});
|
|
200
227
|
|
|
201
228
|
// src/schemas/business/business-email-schema.js
|
|
202
|
-
var
|
|
203
|
-
|
|
204
|
-
businessEmail: import_joi4.default.string().required().max(EMAIL_MAX).email({
|
|
229
|
+
var businessEmailSchema = Joi.object({
|
|
230
|
+
businessEmail: Joi.string().required().max(EMAIL_MAX).email({
|
|
205
231
|
minDomainSegments: 2,
|
|
206
232
|
tlds: {
|
|
207
233
|
allow: true
|
|
@@ -209,37 +235,34 @@ var businessEmailSchema = import_joi4.default.object({
|
|
|
209
235
|
}).messages({
|
|
210
236
|
"string.max": `Business email address must be ${EMAIL_MAX} characters or less`,
|
|
211
237
|
"string.empty": "Enter business email address",
|
|
212
|
-
"string.email": "Enter an email address, like name@example.com"
|
|
238
|
+
"string.email": "Enter an email address, like name@example.com",
|
|
239
|
+
"string.noControlChars": "Business email address must not contain invalid characters"
|
|
213
240
|
})
|
|
214
241
|
});
|
|
215
242
|
|
|
216
243
|
// src/schemas/business/business-phone-schema.js
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
// src/constants/patterns.js
|
|
220
|
-
var PHONE_NUMBER_PATTERN = /^\+?[0-9 ()]+$/;
|
|
221
|
-
|
|
222
|
-
// src/schemas/business/business-phone-schema.js
|
|
223
|
-
var businessPhoneSchema = import_joi5.default.object({
|
|
224
|
-
businessTelephone: import_joi5.default.string().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
244
|
+
var businessPhoneSchema = Joi.object({
|
|
245
|
+
businessTelephone: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
225
246
|
"string.min": `Business telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
226
247
|
"string.max": `Business telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
227
|
-
"string.pattern.base": "Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
248
|
+
"string.pattern.base": "Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
249
|
+
"string.noControlChars": "Business telephone number must not contain invalid characters"
|
|
228
250
|
}),
|
|
229
|
-
businessMobile:
|
|
251
|
+
businessMobile: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
230
252
|
"string.min": `Business mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
231
253
|
"string.max": `Business mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
232
|
-
"string.pattern.base": "Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
254
|
+
"string.pattern.base": "Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
255
|
+
"string.noControlChars": "Business mobile phone number must not contain invalid characters"
|
|
233
256
|
})
|
|
234
257
|
}).or("businessTelephone", "businessMobile").messages({
|
|
235
258
|
"object.missing": "Enter at least one phone number"
|
|
236
259
|
});
|
|
237
260
|
|
|
238
261
|
// src/schemas/business/business-vat-schema.js
|
|
239
|
-
var
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"string.
|
|
262
|
+
var businessVatSchema = Joi.object({
|
|
263
|
+
vatNumber: Joi.string().pattern(/^\d{9}$/).allow("").optional().messages({
|
|
264
|
+
"string.pattern.base": "Enter a VAT registration number, like 123456789",
|
|
265
|
+
"string.noControlChars": "VAT registration number must not contain invalid characters"
|
|
243
266
|
})
|
|
244
267
|
});
|
|
245
268
|
|
|
@@ -256,10 +279,10 @@ var businessSchemas = {
|
|
|
256
279
|
};
|
|
257
280
|
|
|
258
281
|
// src/schemas/customer/customer-crn-schema.js
|
|
259
|
-
var
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
"string.
|
|
282
|
+
var customerCrnSchema = Joi.object({
|
|
283
|
+
crn: Joi.string().pattern(/^\d{10}$/).allow("").optional().messages({
|
|
284
|
+
"string.pattern.base": "Enter the full CRN",
|
|
285
|
+
"string.noControlChars": "CRN must not contain invalid characters"
|
|
263
286
|
})
|
|
264
287
|
});
|
|
265
288
|
|
|
@@ -269,26 +292,25 @@ var customerSchemas = {
|
|
|
269
292
|
};
|
|
270
293
|
|
|
271
294
|
// src/schemas/personal/personal-name-schema.js
|
|
272
|
-
var
|
|
273
|
-
|
|
274
|
-
first: import_joi8.default.string().required().max(FIRST_NAME_MAX).messages({
|
|
295
|
+
var personalNameSchema = Joi.object({
|
|
296
|
+
first: Joi.string().trim().required().max(FIRST_NAME_MAX).messages({
|
|
275
297
|
"string.empty": "Enter first name",
|
|
276
298
|
"string.max": `First name must be ${FIRST_NAME_MAX} characters or less`,
|
|
277
|
-
"any.required": "Enter first name"
|
|
299
|
+
"any.required": "Enter first name",
|
|
300
|
+
"string.noControlChars": "First name must not contain invalid characters"
|
|
278
301
|
}),
|
|
279
|
-
last:
|
|
302
|
+
last: Joi.string().trim().required().max(LAST_NAME_MAX).messages({
|
|
280
303
|
"string.empty": "Enter last name",
|
|
281
304
|
"string.max": `Last name must be ${LAST_NAME_MAX} characters or less`,
|
|
282
|
-
"any.required": "Enter last name"
|
|
305
|
+
"any.required": "Enter last name",
|
|
306
|
+
"string.noControlChars": "Last name must not contain invalid characters"
|
|
283
307
|
}),
|
|
284
|
-
middle:
|
|
285
|
-
"string.max": `Middle names must be ${MIDDLE_NAMES_MAX} characters or less
|
|
308
|
+
middle: Joi.string().trim().allow("").max(MIDDLE_NAMES_MAX).messages({
|
|
309
|
+
"string.max": `Middle names must be ${MIDDLE_NAMES_MAX} characters or less`,
|
|
310
|
+
"string.noControlChars": "Middle names must not contain invalid characters"
|
|
286
311
|
})
|
|
287
312
|
});
|
|
288
313
|
|
|
289
|
-
// src/schemas/personal/personal-dob-schema.js
|
|
290
|
-
var import_joi9 = __toESM(require("joi"), 1);
|
|
291
|
-
|
|
292
314
|
// src/constants/month-map.js
|
|
293
315
|
var MONTH_MAP = {
|
|
294
316
|
january: 1,
|
|
@@ -318,10 +340,10 @@ var MONTH_MAP = {
|
|
|
318
340
|
};
|
|
319
341
|
|
|
320
342
|
// src/schemas/personal/personal-dob-schema.js
|
|
321
|
-
var personalDobSchema =
|
|
322
|
-
day:
|
|
323
|
-
month:
|
|
324
|
-
year:
|
|
343
|
+
var personalDobSchema = Joi.object({
|
|
344
|
+
day: Joi.string().allow(""),
|
|
345
|
+
month: Joi.string().allow(""),
|
|
346
|
+
year: Joi.string().allow("")
|
|
325
347
|
}).custom((value, helpers) => {
|
|
326
348
|
const { day, month, year } = value;
|
|
327
349
|
const missingFieldsError = checkMissingFields(day, month, year, helpers);
|
|
@@ -339,7 +361,9 @@ var personalDobSchema = import_joi9.default.object({
|
|
|
339
361
|
if (fullDate.isJoiError) {
|
|
340
362
|
return fullDate;
|
|
341
363
|
}
|
|
342
|
-
|
|
364
|
+
const today = /* @__PURE__ */ new Date();
|
|
365
|
+
today.setUTCHours(0, 0, 0, 0);
|
|
366
|
+
if (fullDate >= today) {
|
|
343
367
|
return makeError(helpers, "dob.future", ["day", "month", "year"]);
|
|
344
368
|
}
|
|
345
369
|
const tooOldError = checkNotTooOld(fullDate, helpers);
|
|
@@ -358,7 +382,8 @@ var personalDobSchema = import_joi9.default.object({
|
|
|
358
382
|
"dob.yearLength": "Enter a year with 4 numbers, like 1975",
|
|
359
383
|
"dob.invalid": "Date of birth must be a real date",
|
|
360
384
|
"dob.future": "Date of birth must be in the past",
|
|
361
|
-
"dob.tooOld": "Date of birth must be on or after {{#oldest}}"
|
|
385
|
+
"dob.tooOld": "Date of birth must be on or after {{#oldest}}",
|
|
386
|
+
"string.noControlChars": "Date of birth must not contain invalid characters"
|
|
362
387
|
});
|
|
363
388
|
var checkNotTooOld = (fullDate, helpers) => {
|
|
364
389
|
const oldestDateAllowed = getOldestAllowedDate();
|
|
@@ -398,7 +423,11 @@ var getMonthNumber = (month, helpers) => {
|
|
|
398
423
|
}
|
|
399
424
|
return mapped;
|
|
400
425
|
}
|
|
401
|
-
|
|
426
|
+
const parsedMonth = Number.parseInt(month, 10);
|
|
427
|
+
if (parsedMonth < 1 || parsedMonth > 12) {
|
|
428
|
+
return makeError(helpers, "dob.invalid", ["month"]);
|
|
429
|
+
}
|
|
430
|
+
return parsedMonth;
|
|
402
431
|
};
|
|
403
432
|
var checkMissingFields = (day, month, year, helpers) => {
|
|
404
433
|
if (!day && !month && !year) {
|
|
@@ -432,9 +461,8 @@ var makeError = (helpers, code, fields) => {
|
|
|
432
461
|
};
|
|
433
462
|
|
|
434
463
|
// src/schemas/personal/personal-email-schema.js
|
|
435
|
-
var
|
|
436
|
-
|
|
437
|
-
personalEmail: import_joi10.default.string().required().max(EMAIL_MAX).email({
|
|
464
|
+
var personalEmailSchema = Joi.object({
|
|
465
|
+
personalEmail: Joi.string().required().max(EMAIL_MAX).email({
|
|
438
466
|
minDomainSegments: 2,
|
|
439
467
|
tlds: {
|
|
440
468
|
allow: true,
|
|
@@ -443,22 +471,24 @@ var personalEmailSchema = import_joi10.default.object({
|
|
|
443
471
|
}).messages({
|
|
444
472
|
"string.max": `Email address must be ${EMAIL_MAX} characters or less`,
|
|
445
473
|
"string.empty": "Enter a personal email address",
|
|
446
|
-
"string.email": "Enter an email address, like name@example.com"
|
|
474
|
+
"string.email": "Enter an email address, like name@example.com",
|
|
475
|
+
"string.noControlChars": "Personal email address must not contain invalid characters"
|
|
447
476
|
})
|
|
448
477
|
});
|
|
449
478
|
|
|
450
479
|
// src/schemas/personal/personal-phone-schema.js
|
|
451
|
-
var
|
|
452
|
-
|
|
453
|
-
personalTelephone: import_joi11.default.string().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
480
|
+
var personalPhoneSchema = Joi.object({
|
|
481
|
+
personalTelephone: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
454
482
|
"string.min": `Personal telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
455
483
|
"string.max": `Personal telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
456
|
-
"string.pattern.base": "Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
484
|
+
"string.pattern.base": "Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
485
|
+
"string.noControlChars": "Personal telephone number must not contain invalid characters"
|
|
457
486
|
}),
|
|
458
|
-
personalMobile:
|
|
487
|
+
personalMobile: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
459
488
|
"string.min": `Personal mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
460
489
|
"string.max": `Personal mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
461
|
-
"string.pattern.base": "Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
490
|
+
"string.pattern.base": "Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
491
|
+
"string.noControlChars": "Personal mobile phone number must not contain invalid characters"
|
|
462
492
|
})
|
|
463
493
|
}).or("personalTelephone", "personalMobile").messages({
|
|
464
494
|
"object.missing": "Enter at least one phone number"
|
|
@@ -681,8 +711,55 @@ var presenters = {
|
|
|
681
711
|
formatCphText,
|
|
682
712
|
formatBusinessAddress
|
|
683
713
|
};
|
|
714
|
+
|
|
715
|
+
// src/constants/status-codes.js
|
|
716
|
+
var OK = 200;
|
|
717
|
+
var BAD_REQUEST = 400;
|
|
718
|
+
var UNAUTHORIZED = 401;
|
|
719
|
+
var FORBIDDEN = 403;
|
|
720
|
+
var NOT_FOUND = 404;
|
|
721
|
+
var NO_CONTENT = 204;
|
|
722
|
+
var FOUND = 302;
|
|
723
|
+
var INTERNAL_SERVER_ERROR = 500;
|
|
724
|
+
var SERVICE_UNAVAILABLE = 503;
|
|
725
|
+
|
|
726
|
+
// src/constants/index.js
|
|
727
|
+
var constants = {
|
|
728
|
+
statusCodes: {
|
|
729
|
+
BAD_REQUEST,
|
|
730
|
+
UNAUTHORIZED,
|
|
731
|
+
FORBIDDEN,
|
|
732
|
+
NOT_FOUND,
|
|
733
|
+
OK,
|
|
734
|
+
NO_CONTENT,
|
|
735
|
+
FOUND,
|
|
736
|
+
INTERNAL_SERVER_ERROR,
|
|
737
|
+
SERVICE_UNAVAILABLE
|
|
738
|
+
},
|
|
739
|
+
validationFields: {
|
|
740
|
+
FIRST_NAME_MAX,
|
|
741
|
+
LAST_NAME_MAX,
|
|
742
|
+
MIDDLE_NAMES_MAX,
|
|
743
|
+
BUSINESS_NAME_MAX,
|
|
744
|
+
EMAIL_MAX,
|
|
745
|
+
PHONE_NUMBER_MIN,
|
|
746
|
+
PHONE_NUMBER_MAX,
|
|
747
|
+
MAX_AGE_YEARS,
|
|
748
|
+
ADDRESS_LINE_MAX,
|
|
749
|
+
TOWN_CITY_MAX,
|
|
750
|
+
COUNTY_MAX,
|
|
751
|
+
COUNTRY_MAX,
|
|
752
|
+
POSTCODE_MAX
|
|
753
|
+
},
|
|
754
|
+
patterns: {
|
|
755
|
+
PHONE_NUMBER_PATTERN,
|
|
756
|
+
NO_CONTROL_CHARS_PATTERN
|
|
757
|
+
},
|
|
758
|
+
monthMap: MONTH_MAP
|
|
759
|
+
};
|
|
684
760
|
// Annotate the CommonJS export names for ESM import in node:
|
|
685
761
|
0 && (module.exports = {
|
|
762
|
+
constants,
|
|
686
763
|
mappers,
|
|
687
764
|
presenters,
|
|
688
765
|
schemas,
|
package/dist/index.js
CHANGED
|
@@ -91,17 +91,36 @@ var mappers = {
|
|
|
91
91
|
businessDetails: mapBusinessDetails
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
// src/utils/joi.js
|
|
95
|
+
import BaseJoi from "joi";
|
|
96
|
+
|
|
97
|
+
// src/constants/patterns.js
|
|
98
|
+
var PHONE_NUMBER_PATTERN = /^\+?(?=[\d ()]*\d)[\d ()]*$/;
|
|
99
|
+
var NO_CONTROL_CHARS_PATTERN = /^[^\x00-\x1f\x7f-\x9f]*$/;
|
|
100
|
+
|
|
101
|
+
// src/utils/joi.js
|
|
102
|
+
var Joi = BaseJoi.extend((joi) => ({
|
|
103
|
+
type: "string",
|
|
104
|
+
base: joi.string(),
|
|
105
|
+
messages: {
|
|
106
|
+
"string.noControlChars": "Field must not contain invalid characters"
|
|
107
|
+
},
|
|
108
|
+
validate(value, helpers) {
|
|
109
|
+
if (typeof value === "string" && !NO_CONTROL_CHARS_PATTERN.test(value)) {
|
|
110
|
+
return { value, errors: helpers.error("string.noControlChars") };
|
|
111
|
+
}
|
|
112
|
+
return { value };
|
|
113
|
+
}
|
|
114
|
+
}));
|
|
115
|
+
|
|
94
116
|
// src/schemas/business/business-sbi-schema.js
|
|
95
|
-
import Joi from "joi";
|
|
96
117
|
var businessSbiSchema = Joi.object({
|
|
97
118
|
sbi: Joi.string().pattern(/^\d{9}$/).allow("").optional().messages({
|
|
98
|
-
"string.pattern.base": "Enter the full SBI"
|
|
119
|
+
"string.pattern.base": "Enter the full SBI",
|
|
120
|
+
"string.noControlChars": "SBI must not contain invalid characters"
|
|
99
121
|
})
|
|
100
122
|
});
|
|
101
123
|
|
|
102
|
-
// src/schemas/address-schema.js
|
|
103
|
-
import Joi2 from "joi";
|
|
104
|
-
|
|
105
124
|
// src/constants/validation-fields.js
|
|
106
125
|
var FIRST_NAME_MAX = 100;
|
|
107
126
|
var LAST_NAME_MAX = 100;
|
|
@@ -117,53 +136,59 @@ var COUNTY_MAX = 60;
|
|
|
117
136
|
var COUNTRY_MAX = 60;
|
|
118
137
|
var POSTCODE_MAX = 8;
|
|
119
138
|
|
|
120
|
-
// src/schemas/address-schema.js
|
|
121
|
-
var addressSchema =
|
|
122
|
-
address1:
|
|
139
|
+
// src/schemas/shared/address-schema.js
|
|
140
|
+
var addressSchema = Joi.object({
|
|
141
|
+
address1: Joi.string().trim().required().max(ADDRESS_LINE_MAX).messages({
|
|
123
142
|
"string.empty": "Enter address line 1, typically the building and street",
|
|
124
143
|
"string.max": `Address line 1 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
125
|
-
"any.required": "Enter address line 1, typically the building and street"
|
|
144
|
+
"any.required": "Enter address line 1, typically the building and street",
|
|
145
|
+
"string.noControlChars": "Address line 1 must not contain invalid characters"
|
|
126
146
|
}),
|
|
127
|
-
address2:
|
|
128
|
-
"string.max": `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less
|
|
147
|
+
address2: Joi.string().trim().allow("").max(ADDRESS_LINE_MAX).messages({
|
|
148
|
+
"string.max": `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
149
|
+
"string.noControlChars": "Address line 2 must not contain invalid characters"
|
|
129
150
|
}),
|
|
130
|
-
address3:
|
|
131
|
-
"string.max": `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less
|
|
151
|
+
address3: Joi.string().trim().allow("").max(ADDRESS_LINE_MAX).messages({
|
|
152
|
+
"string.max": `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
153
|
+
"string.noControlChars": "Address line 3 must not contain invalid characters"
|
|
132
154
|
}),
|
|
133
|
-
city:
|
|
155
|
+
city: Joi.string().trim().required().max(TOWN_CITY_MAX).messages({
|
|
134
156
|
"string.empty": "Enter town or city",
|
|
135
157
|
"string.max": `Town or city must be ${TOWN_CITY_MAX} characters or less`,
|
|
136
|
-
"any.required": "Enter town or city"
|
|
158
|
+
"any.required": "Enter town or city",
|
|
159
|
+
"string.noControlChars": "Town or city must not contain invalid characters"
|
|
137
160
|
}),
|
|
138
|
-
county:
|
|
139
|
-
"string.max": `County must be ${COUNTY_MAX} characters or less
|
|
161
|
+
county: Joi.string().trim().allow("").max(COUNTY_MAX).messages({
|
|
162
|
+
"string.max": `County must be ${COUNTY_MAX} characters or less`,
|
|
163
|
+
"string.noControlChars": "County must not contain invalid characters"
|
|
140
164
|
}),
|
|
141
|
-
postcode:
|
|
165
|
+
postcode: Joi.string().trim().required().max(POSTCODE_MAX).messages({
|
|
142
166
|
"any.required": "Enter a postal code or zip code",
|
|
143
167
|
"string.empty": "Enter a postal code or zip code",
|
|
144
|
-
"string.max": `Postal code or zip code must be ${POSTCODE_MAX} characters or less
|
|
168
|
+
"string.max": `Postal code or zip code must be ${POSTCODE_MAX} characters or less`,
|
|
169
|
+
"string.noControlChars": "Postal code or zip code must not contain invalid characters"
|
|
145
170
|
}),
|
|
146
|
-
country:
|
|
171
|
+
country: Joi.string().trim().required().max(COUNTRY_MAX).messages({
|
|
147
172
|
"string.empty": "Enter a country",
|
|
148
173
|
"string.max": `Country must be ${COUNTRY_MAX} characters or less`,
|
|
149
|
-
"any.required": "Enter a country"
|
|
174
|
+
"any.required": "Enter a country",
|
|
175
|
+
"string.noControlChars": "Country must not contain invalid characters"
|
|
150
176
|
})
|
|
151
177
|
});
|
|
152
178
|
|
|
153
179
|
// src/schemas/business/business-name-schema.js
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
businessName: Joi3.string().required().max(BUSINESS_NAME_MAX).messages({
|
|
180
|
+
var businessNameSchema = Joi.object({
|
|
181
|
+
businessName: Joi.string().trim().required().max(BUSINESS_NAME_MAX).messages({
|
|
157
182
|
"string.empty": "Enter business name",
|
|
158
183
|
"string.max": `Business name must be ${BUSINESS_NAME_MAX} characters or less`,
|
|
159
|
-
"any.required": "Enter business name"
|
|
184
|
+
"any.required": "Enter business name",
|
|
185
|
+
"string.noControlChars": "Business name must not contain invalid characters"
|
|
160
186
|
})
|
|
161
187
|
});
|
|
162
188
|
|
|
163
189
|
// src/schemas/business/business-email-schema.js
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
businessEmail: Joi4.string().required().max(EMAIL_MAX).email({
|
|
190
|
+
var businessEmailSchema = Joi.object({
|
|
191
|
+
businessEmail: Joi.string().required().max(EMAIL_MAX).email({
|
|
167
192
|
minDomainSegments: 2,
|
|
168
193
|
tlds: {
|
|
169
194
|
allow: true
|
|
@@ -171,37 +196,34 @@ var businessEmailSchema = Joi4.object({
|
|
|
171
196
|
}).messages({
|
|
172
197
|
"string.max": `Business email address must be ${EMAIL_MAX} characters or less`,
|
|
173
198
|
"string.empty": "Enter business email address",
|
|
174
|
-
"string.email": "Enter an email address, like name@example.com"
|
|
199
|
+
"string.email": "Enter an email address, like name@example.com",
|
|
200
|
+
"string.noControlChars": "Business email address must not contain invalid characters"
|
|
175
201
|
})
|
|
176
202
|
});
|
|
177
203
|
|
|
178
204
|
// src/schemas/business/business-phone-schema.js
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// src/constants/patterns.js
|
|
182
|
-
var PHONE_NUMBER_PATTERN = /^\+?[0-9 ()]+$/;
|
|
183
|
-
|
|
184
|
-
// src/schemas/business/business-phone-schema.js
|
|
185
|
-
var businessPhoneSchema = Joi5.object({
|
|
186
|
-
businessTelephone: Joi5.string().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
205
|
+
var businessPhoneSchema = Joi.object({
|
|
206
|
+
businessTelephone: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
187
207
|
"string.min": `Business telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
188
208
|
"string.max": `Business telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
189
|
-
"string.pattern.base": "Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
209
|
+
"string.pattern.base": "Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
210
|
+
"string.noControlChars": "Business telephone number must not contain invalid characters"
|
|
190
211
|
}),
|
|
191
|
-
businessMobile:
|
|
212
|
+
businessMobile: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
192
213
|
"string.min": `Business mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
193
214
|
"string.max": `Business mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
194
|
-
"string.pattern.base": "Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
215
|
+
"string.pattern.base": "Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
216
|
+
"string.noControlChars": "Business mobile phone number must not contain invalid characters"
|
|
195
217
|
})
|
|
196
218
|
}).or("businessTelephone", "businessMobile").messages({
|
|
197
219
|
"object.missing": "Enter at least one phone number"
|
|
198
220
|
});
|
|
199
221
|
|
|
200
222
|
// src/schemas/business/business-vat-schema.js
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"string.
|
|
223
|
+
var businessVatSchema = Joi.object({
|
|
224
|
+
vatNumber: Joi.string().pattern(/^\d{9}$/).allow("").optional().messages({
|
|
225
|
+
"string.pattern.base": "Enter a VAT registration number, like 123456789",
|
|
226
|
+
"string.noControlChars": "VAT registration number must not contain invalid characters"
|
|
205
227
|
})
|
|
206
228
|
});
|
|
207
229
|
|
|
@@ -218,10 +240,10 @@ var businessSchemas = {
|
|
|
218
240
|
};
|
|
219
241
|
|
|
220
242
|
// src/schemas/customer/customer-crn-schema.js
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
"string.
|
|
243
|
+
var customerCrnSchema = Joi.object({
|
|
244
|
+
crn: Joi.string().pattern(/^\d{10}$/).allow("").optional().messages({
|
|
245
|
+
"string.pattern.base": "Enter the full CRN",
|
|
246
|
+
"string.noControlChars": "CRN must not contain invalid characters"
|
|
225
247
|
})
|
|
226
248
|
});
|
|
227
249
|
|
|
@@ -231,26 +253,25 @@ var customerSchemas = {
|
|
|
231
253
|
};
|
|
232
254
|
|
|
233
255
|
// src/schemas/personal/personal-name-schema.js
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
first: Joi8.string().required().max(FIRST_NAME_MAX).messages({
|
|
256
|
+
var personalNameSchema = Joi.object({
|
|
257
|
+
first: Joi.string().trim().required().max(FIRST_NAME_MAX).messages({
|
|
237
258
|
"string.empty": "Enter first name",
|
|
238
259
|
"string.max": `First name must be ${FIRST_NAME_MAX} characters or less`,
|
|
239
|
-
"any.required": "Enter first name"
|
|
260
|
+
"any.required": "Enter first name",
|
|
261
|
+
"string.noControlChars": "First name must not contain invalid characters"
|
|
240
262
|
}),
|
|
241
|
-
last:
|
|
263
|
+
last: Joi.string().trim().required().max(LAST_NAME_MAX).messages({
|
|
242
264
|
"string.empty": "Enter last name",
|
|
243
265
|
"string.max": `Last name must be ${LAST_NAME_MAX} characters or less`,
|
|
244
|
-
"any.required": "Enter last name"
|
|
266
|
+
"any.required": "Enter last name",
|
|
267
|
+
"string.noControlChars": "Last name must not contain invalid characters"
|
|
245
268
|
}),
|
|
246
|
-
middle:
|
|
247
|
-
"string.max": `Middle names must be ${MIDDLE_NAMES_MAX} characters or less
|
|
269
|
+
middle: Joi.string().trim().allow("").max(MIDDLE_NAMES_MAX).messages({
|
|
270
|
+
"string.max": `Middle names must be ${MIDDLE_NAMES_MAX} characters or less`,
|
|
271
|
+
"string.noControlChars": "Middle names must not contain invalid characters"
|
|
248
272
|
})
|
|
249
273
|
});
|
|
250
274
|
|
|
251
|
-
// src/schemas/personal/personal-dob-schema.js
|
|
252
|
-
import Joi9 from "joi";
|
|
253
|
-
|
|
254
275
|
// src/constants/month-map.js
|
|
255
276
|
var MONTH_MAP = {
|
|
256
277
|
january: 1,
|
|
@@ -280,10 +301,10 @@ var MONTH_MAP = {
|
|
|
280
301
|
};
|
|
281
302
|
|
|
282
303
|
// src/schemas/personal/personal-dob-schema.js
|
|
283
|
-
var personalDobSchema =
|
|
284
|
-
day:
|
|
285
|
-
month:
|
|
286
|
-
year:
|
|
304
|
+
var personalDobSchema = Joi.object({
|
|
305
|
+
day: Joi.string().allow(""),
|
|
306
|
+
month: Joi.string().allow(""),
|
|
307
|
+
year: Joi.string().allow("")
|
|
287
308
|
}).custom((value, helpers) => {
|
|
288
309
|
const { day, month, year } = value;
|
|
289
310
|
const missingFieldsError = checkMissingFields(day, month, year, helpers);
|
|
@@ -301,7 +322,9 @@ var personalDobSchema = Joi9.object({
|
|
|
301
322
|
if (fullDate.isJoiError) {
|
|
302
323
|
return fullDate;
|
|
303
324
|
}
|
|
304
|
-
|
|
325
|
+
const today = /* @__PURE__ */ new Date();
|
|
326
|
+
today.setUTCHours(0, 0, 0, 0);
|
|
327
|
+
if (fullDate >= today) {
|
|
305
328
|
return makeError(helpers, "dob.future", ["day", "month", "year"]);
|
|
306
329
|
}
|
|
307
330
|
const tooOldError = checkNotTooOld(fullDate, helpers);
|
|
@@ -320,7 +343,8 @@ var personalDobSchema = Joi9.object({
|
|
|
320
343
|
"dob.yearLength": "Enter a year with 4 numbers, like 1975",
|
|
321
344
|
"dob.invalid": "Date of birth must be a real date",
|
|
322
345
|
"dob.future": "Date of birth must be in the past",
|
|
323
|
-
"dob.tooOld": "Date of birth must be on or after {{#oldest}}"
|
|
346
|
+
"dob.tooOld": "Date of birth must be on or after {{#oldest}}",
|
|
347
|
+
"string.noControlChars": "Date of birth must not contain invalid characters"
|
|
324
348
|
});
|
|
325
349
|
var checkNotTooOld = (fullDate, helpers) => {
|
|
326
350
|
const oldestDateAllowed = getOldestAllowedDate();
|
|
@@ -360,7 +384,11 @@ var getMonthNumber = (month, helpers) => {
|
|
|
360
384
|
}
|
|
361
385
|
return mapped;
|
|
362
386
|
}
|
|
363
|
-
|
|
387
|
+
const parsedMonth = Number.parseInt(month, 10);
|
|
388
|
+
if (parsedMonth < 1 || parsedMonth > 12) {
|
|
389
|
+
return makeError(helpers, "dob.invalid", ["month"]);
|
|
390
|
+
}
|
|
391
|
+
return parsedMonth;
|
|
364
392
|
};
|
|
365
393
|
var checkMissingFields = (day, month, year, helpers) => {
|
|
366
394
|
if (!day && !month && !year) {
|
|
@@ -394,9 +422,8 @@ var makeError = (helpers, code, fields) => {
|
|
|
394
422
|
};
|
|
395
423
|
|
|
396
424
|
// src/schemas/personal/personal-email-schema.js
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
personalEmail: Joi10.string().required().max(EMAIL_MAX).email({
|
|
425
|
+
var personalEmailSchema = Joi.object({
|
|
426
|
+
personalEmail: Joi.string().required().max(EMAIL_MAX).email({
|
|
400
427
|
minDomainSegments: 2,
|
|
401
428
|
tlds: {
|
|
402
429
|
allow: true,
|
|
@@ -405,22 +432,24 @@ var personalEmailSchema = Joi10.object({
|
|
|
405
432
|
}).messages({
|
|
406
433
|
"string.max": `Email address must be ${EMAIL_MAX} characters or less`,
|
|
407
434
|
"string.empty": "Enter a personal email address",
|
|
408
|
-
"string.email": "Enter an email address, like name@example.com"
|
|
435
|
+
"string.email": "Enter an email address, like name@example.com",
|
|
436
|
+
"string.noControlChars": "Personal email address must not contain invalid characters"
|
|
409
437
|
})
|
|
410
438
|
});
|
|
411
439
|
|
|
412
440
|
// src/schemas/personal/personal-phone-schema.js
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
personalTelephone: Joi11.string().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
441
|
+
var personalPhoneSchema = Joi.object({
|
|
442
|
+
personalTelephone: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
416
443
|
"string.min": `Personal telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
417
444
|
"string.max": `Personal telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
418
|
-
"string.pattern.base": "Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
445
|
+
"string.pattern.base": "Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
446
|
+
"string.noControlChars": "Personal telephone number must not contain invalid characters"
|
|
419
447
|
}),
|
|
420
|
-
personalMobile:
|
|
448
|
+
personalMobile: Joi.string().trim().empty("").min(PHONE_NUMBER_MIN).max(PHONE_NUMBER_MAX).pattern(PHONE_NUMBER_PATTERN).messages({
|
|
421
449
|
"string.min": `Personal mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
422
450
|
"string.max": `Personal mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
423
|
-
"string.pattern.base": "Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +"
|
|
451
|
+
"string.pattern.base": "Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +",
|
|
452
|
+
"string.noControlChars": "Personal mobile phone number must not contain invalid characters"
|
|
424
453
|
})
|
|
425
454
|
}).or("personalTelephone", "personalMobile").messages({
|
|
426
455
|
"object.missing": "Enter at least one phone number"
|
|
@@ -643,7 +672,54 @@ var presenters = {
|
|
|
643
672
|
formatCphText,
|
|
644
673
|
formatBusinessAddress
|
|
645
674
|
};
|
|
675
|
+
|
|
676
|
+
// src/constants/status-codes.js
|
|
677
|
+
var OK = 200;
|
|
678
|
+
var BAD_REQUEST = 400;
|
|
679
|
+
var UNAUTHORIZED = 401;
|
|
680
|
+
var FORBIDDEN = 403;
|
|
681
|
+
var NOT_FOUND = 404;
|
|
682
|
+
var NO_CONTENT = 204;
|
|
683
|
+
var FOUND = 302;
|
|
684
|
+
var INTERNAL_SERVER_ERROR = 500;
|
|
685
|
+
var SERVICE_UNAVAILABLE = 503;
|
|
686
|
+
|
|
687
|
+
// src/constants/index.js
|
|
688
|
+
var constants = {
|
|
689
|
+
statusCodes: {
|
|
690
|
+
BAD_REQUEST,
|
|
691
|
+
UNAUTHORIZED,
|
|
692
|
+
FORBIDDEN,
|
|
693
|
+
NOT_FOUND,
|
|
694
|
+
OK,
|
|
695
|
+
NO_CONTENT,
|
|
696
|
+
FOUND,
|
|
697
|
+
INTERNAL_SERVER_ERROR,
|
|
698
|
+
SERVICE_UNAVAILABLE
|
|
699
|
+
},
|
|
700
|
+
validationFields: {
|
|
701
|
+
FIRST_NAME_MAX,
|
|
702
|
+
LAST_NAME_MAX,
|
|
703
|
+
MIDDLE_NAMES_MAX,
|
|
704
|
+
BUSINESS_NAME_MAX,
|
|
705
|
+
EMAIL_MAX,
|
|
706
|
+
PHONE_NUMBER_MIN,
|
|
707
|
+
PHONE_NUMBER_MAX,
|
|
708
|
+
MAX_AGE_YEARS,
|
|
709
|
+
ADDRESS_LINE_MAX,
|
|
710
|
+
TOWN_CITY_MAX,
|
|
711
|
+
COUNTY_MAX,
|
|
712
|
+
COUNTRY_MAX,
|
|
713
|
+
POSTCODE_MAX
|
|
714
|
+
},
|
|
715
|
+
patterns: {
|
|
716
|
+
PHONE_NUMBER_PATTERN,
|
|
717
|
+
NO_CONTROL_CHARS_PATTERN
|
|
718
|
+
},
|
|
719
|
+
monthMap: MONTH_MAP
|
|
720
|
+
};
|
|
646
721
|
export {
|
|
722
|
+
constants,
|
|
647
723
|
mappers,
|
|
648
724
|
presenters,
|
|
649
725
|
schemas,
|
package/package.json
CHANGED
package/src/constants/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// Validation constraints
|
|
2
|
+
import {
|
|
2
3
|
FIRST_NAME_MAX,
|
|
3
4
|
LAST_NAME_MAX,
|
|
4
5
|
MIDDLE_NAMES_MAX,
|
|
6
|
+
BUSINESS_NAME_MAX,
|
|
5
7
|
EMAIL_MAX,
|
|
6
8
|
PHONE_NUMBER_MIN,
|
|
7
9
|
PHONE_NUMBER_MAX,
|
|
@@ -10,7 +12,56 @@ export {
|
|
|
10
12
|
TOWN_CITY_MAX,
|
|
11
13
|
COUNTY_MAX,
|
|
12
14
|
COUNTRY_MAX,
|
|
13
|
-
POSTCODE_MAX
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
POSTCODE_MAX
|
|
16
|
+
} from './validation-fields.js'
|
|
17
|
+
|
|
18
|
+
// HTTP status codes
|
|
19
|
+
import {
|
|
20
|
+
BAD_REQUEST,
|
|
21
|
+
UNAUTHORIZED,
|
|
22
|
+
FORBIDDEN,
|
|
23
|
+
NOT_FOUND,
|
|
24
|
+
OK,
|
|
25
|
+
NO_CONTENT,
|
|
26
|
+
FOUND,
|
|
27
|
+
INTERNAL_SERVER_ERROR,
|
|
28
|
+
SERVICE_UNAVAILABLE
|
|
29
|
+
} from './status-codes.js'
|
|
30
|
+
|
|
31
|
+
// Format patterns and mappings
|
|
32
|
+
import { PHONE_NUMBER_PATTERN, NO_CONTROL_CHARS_PATTERN } from './patterns.js'
|
|
33
|
+
import { MONTH_MAP } from './month-map.js'
|
|
34
|
+
|
|
35
|
+
export const constants = {
|
|
36
|
+
statusCodes: {
|
|
37
|
+
BAD_REQUEST,
|
|
38
|
+
UNAUTHORIZED,
|
|
39
|
+
FORBIDDEN,
|
|
40
|
+
NOT_FOUND,
|
|
41
|
+
OK,
|
|
42
|
+
NO_CONTENT,
|
|
43
|
+
FOUND,
|
|
44
|
+
INTERNAL_SERVER_ERROR,
|
|
45
|
+
SERVICE_UNAVAILABLE
|
|
46
|
+
},
|
|
47
|
+
validationFields: {
|
|
48
|
+
FIRST_NAME_MAX,
|
|
49
|
+
LAST_NAME_MAX,
|
|
50
|
+
MIDDLE_NAMES_MAX,
|
|
51
|
+
BUSINESS_NAME_MAX,
|
|
52
|
+
EMAIL_MAX,
|
|
53
|
+
PHONE_NUMBER_MIN,
|
|
54
|
+
PHONE_NUMBER_MAX,
|
|
55
|
+
MAX_AGE_YEARS,
|
|
56
|
+
ADDRESS_LINE_MAX,
|
|
57
|
+
TOWN_CITY_MAX,
|
|
58
|
+
COUNTY_MAX,
|
|
59
|
+
COUNTRY_MAX,
|
|
60
|
+
POSTCODE_MAX
|
|
61
|
+
},
|
|
62
|
+
patterns: {
|
|
63
|
+
PHONE_NUMBER_PATTERN,
|
|
64
|
+
NO_CONTROL_CHARS_PATTERN
|
|
65
|
+
},
|
|
66
|
+
monthMap: MONTH_MAP
|
|
67
|
+
}
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// Allows digits, spaces, brackets, and an optional leading +, but requires at least one digit.
|
|
2
|
+
// The (?=...) part checks a digit exists first for efficiency and time complexity.
|
|
3
|
+
export const PHONE_NUMBER_PATTERN = /^\+?(?=[\d ()]*\d)[\d ()]*$/
|
|
4
|
+
|
|
5
|
+
// Rejects control characters — C0 (0x00–0x1f), DEL (0x7f) and C1 (0x80–0x9f) — which have no valid
|
|
6
|
+
// use in text input fields. The Unicode C1 block contains only control characters, so this does not
|
|
7
|
+
// reject legitimate input — accented letters, symbols and NBSP all sit at U+00A0 and above.
|
|
8
|
+
// eslint-disable-next-line no-control-regex
|
|
9
|
+
export const NO_CONTROL_CHARS_PATTERN = /^[^\x00-\x1f\x7f-\x9f]*$/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const OK = 200
|
|
2
|
+
export const BAD_REQUEST = 400
|
|
3
|
+
export const UNAUTHORIZED = 401
|
|
4
|
+
export const FORBIDDEN = 403
|
|
5
|
+
export const NOT_FOUND = 404
|
|
6
|
+
export const NO_CONTENT = 204
|
|
7
|
+
export const FOUND = 302
|
|
8
|
+
export const INTERNAL_SERVER_ERROR = 500
|
|
9
|
+
export const SERVICE_UNAVAILABLE = 503
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import { EMAIL_MAX } from '../../constants/validation-fields.js'
|
|
3
3
|
|
|
4
4
|
export const businessEmailSchema = Joi.object({
|
|
@@ -14,6 +14,7 @@ export const businessEmailSchema = Joi.object({
|
|
|
14
14
|
.messages({
|
|
15
15
|
'string.max': `Business email address must be ${EMAIL_MAX} characters or less`,
|
|
16
16
|
'string.empty': 'Enter business email address',
|
|
17
|
-
'string.email': 'Enter an email address, like name@example.com'
|
|
17
|
+
'string.email': 'Enter an email address, like name@example.com',
|
|
18
|
+
'string.noControlChars': 'Business email address must not contain invalid characters'
|
|
18
19
|
})
|
|
19
20
|
})
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import { BUSINESS_NAME_MAX } from '../../constants/validation-fields.js'
|
|
3
3
|
|
|
4
4
|
export const businessNameSchema = Joi.object({
|
|
5
5
|
businessName: Joi.string()
|
|
6
|
+
.trim()
|
|
6
7
|
.required()
|
|
7
8
|
.max(BUSINESS_NAME_MAX)
|
|
8
9
|
.messages({
|
|
9
10
|
'string.empty': 'Enter business name',
|
|
10
11
|
'string.max': `Business name must be ${BUSINESS_NAME_MAX} characters or less`,
|
|
11
|
-
'any.required': 'Enter business name'
|
|
12
|
+
'any.required': 'Enter business name',
|
|
13
|
+
'string.noControlChars': 'Business name must not contain invalid characters'
|
|
12
14
|
})
|
|
13
15
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import {
|
|
3
3
|
PHONE_NUMBER_MIN,
|
|
4
4
|
PHONE_NUMBER_MAX
|
|
@@ -7,6 +7,7 @@ import { PHONE_NUMBER_PATTERN } from '../../constants/patterns.js'
|
|
|
7
7
|
|
|
8
8
|
export const businessPhoneSchema = Joi.object({
|
|
9
9
|
businessTelephone: Joi.string()
|
|
10
|
+
.trim()
|
|
10
11
|
.empty('')
|
|
11
12
|
.min(PHONE_NUMBER_MIN)
|
|
12
13
|
.max(PHONE_NUMBER_MAX)
|
|
@@ -14,9 +15,11 @@ export const businessPhoneSchema = Joi.object({
|
|
|
14
15
|
.messages({
|
|
15
16
|
'string.min': `Business telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
16
17
|
'string.max': `Business telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
17
|
-
'string.pattern.base': 'Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +'
|
|
18
|
+
'string.pattern.base': 'Business telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +',
|
|
19
|
+
'string.noControlChars': 'Business telephone number must not contain invalid characters'
|
|
18
20
|
}),
|
|
19
21
|
businessMobile: Joi.string()
|
|
22
|
+
.trim()
|
|
20
23
|
.empty('')
|
|
21
24
|
.min(PHONE_NUMBER_MIN)
|
|
22
25
|
.max(PHONE_NUMBER_MAX)
|
|
@@ -24,7 +27,8 @@ export const businessPhoneSchema = Joi.object({
|
|
|
24
27
|
.messages({
|
|
25
28
|
'string.min': `Business mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
26
29
|
'string.max': `Business mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
27
|
-
'string.pattern.base': 'Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +'
|
|
30
|
+
'string.pattern.base': 'Business mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +',
|
|
31
|
+
'string.noControlChars': 'Business mobile phone number must not contain invalid characters'
|
|
28
32
|
})
|
|
29
33
|
})
|
|
30
34
|
.or('businessTelephone', 'businessMobile')
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
|
|
3
3
|
export const businessSbiSchema = Joi.object({
|
|
4
4
|
sbi: Joi.string()
|
|
@@ -6,6 +6,7 @@ export const businessSbiSchema = Joi.object({
|
|
|
6
6
|
.allow('')
|
|
7
7
|
.optional()
|
|
8
8
|
.messages({
|
|
9
|
-
'string.pattern.base': 'Enter the full SBI'
|
|
9
|
+
'string.pattern.base': 'Enter the full SBI',
|
|
10
|
+
'string.noControlChars': 'SBI must not contain invalid characters'
|
|
10
11
|
})
|
|
11
12
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { businessSbiSchema } from './business-sbi-schema.js'
|
|
2
|
-
import { addressSchema } from '../address-schema.js'
|
|
2
|
+
import { addressSchema } from '../shared/address-schema.js'
|
|
3
3
|
import { businessNameSchema } from './business-name-schema.js'
|
|
4
4
|
import { businessEmailSchema } from './business-email-schema.js'
|
|
5
5
|
import { businessPhoneSchema } from './business-phone-schema.js'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
|
|
3
3
|
export const businessVatSchema = Joi.object({
|
|
4
4
|
vatNumber: Joi.string()
|
|
@@ -6,6 +6,7 @@ export const businessVatSchema = Joi.object({
|
|
|
6
6
|
.allow('')
|
|
7
7
|
.optional()
|
|
8
8
|
.messages({
|
|
9
|
-
'string.pattern.base': 'Enter a VAT registration number, like 123456789'
|
|
9
|
+
'string.pattern.base': 'Enter a VAT registration number, like 123456789',
|
|
10
|
+
'string.noControlChars': 'VAT registration number must not contain invalid characters'
|
|
10
11
|
})
|
|
11
12
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
|
|
3
3
|
export const customerCrnSchema = Joi.object({
|
|
4
4
|
crn: Joi.string()
|
|
@@ -6,6 +6,7 @@ export const customerCrnSchema = Joi.object({
|
|
|
6
6
|
.allow('')
|
|
7
7
|
.optional()
|
|
8
8
|
.messages({
|
|
9
|
-
'string.pattern.base': 'Enter the full CRN'
|
|
9
|
+
'string.pattern.base': 'Enter the full CRN',
|
|
10
|
+
'string.noControlChars': 'CRN must not contain invalid characters'
|
|
10
11
|
})
|
|
11
12
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
2
|
-
import {
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
|
+
import { MAX_AGE_YEARS } from '../../constants/validation-fields.js'
|
|
3
|
+
import { MONTH_MAP } from '../../constants/month-map.js'
|
|
3
4
|
|
|
4
5
|
export const personalDobSchema = Joi.object({
|
|
5
6
|
day: Joi.string().allow(''),
|
|
@@ -32,7 +33,9 @@ export const personalDobSchema = Joi.object({
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
// Date must be in the past
|
|
35
|
-
|
|
36
|
+
const today = new Date()
|
|
37
|
+
today.setUTCHours(0, 0, 0, 0)
|
|
38
|
+
if (fullDate >= today) {
|
|
36
39
|
return makeError(helpers, 'dob.future', ['day', 'month', 'year'])
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -54,7 +57,8 @@ export const personalDobSchema = Joi.object({
|
|
|
54
57
|
'dob.yearLength': 'Enter a year with 4 numbers, like 1975',
|
|
55
58
|
'dob.invalid': 'Date of birth must be a real date',
|
|
56
59
|
'dob.future': 'Date of birth must be in the past',
|
|
57
|
-
'dob.tooOld': 'Date of birth must be on or after {{#oldest}}'
|
|
60
|
+
'dob.tooOld': 'Date of birth must be on or after {{#oldest}}',
|
|
61
|
+
'string.noControlChars': 'Date of birth must not contain invalid characters'
|
|
58
62
|
})
|
|
59
63
|
|
|
60
64
|
const checkNotTooOld = (fullDate, helpers) => {
|
|
@@ -119,7 +123,7 @@ const getFullDate = (day, monthValue, year, helpers) => {
|
|
|
119
123
|
*
|
|
120
124
|
* If a valid mapping is found, the mapped number is returned.
|
|
121
125
|
* If no mapping exists, an error is returned via `makeError`, as the input is likely invalid.
|
|
122
|
-
* If the month is already numeric, it is
|
|
126
|
+
* If the month is already numeric, it is parsed and validated to be within the range 1–12.
|
|
123
127
|
*/
|
|
124
128
|
const getMonthNumber = (month, helpers) => {
|
|
125
129
|
if (Number.isNaN(Number(month))) {
|
|
@@ -133,7 +137,13 @@ const getMonthNumber = (month, helpers) => {
|
|
|
133
137
|
return mapped
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
const parsedMonth = Number.parseInt(month, 10)
|
|
141
|
+
|
|
142
|
+
if (parsedMonth < 1 || parsedMonth > 12) {
|
|
143
|
+
return makeError(helpers, 'dob.invalid', ['month'])
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return parsedMonth
|
|
137
147
|
}
|
|
138
148
|
|
|
139
149
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import { EMAIL_MAX } from '../../constants/validation-fields.js'
|
|
3
3
|
|
|
4
4
|
export const personalEmailSchema = Joi.object({
|
|
@@ -15,6 +15,7 @@ export const personalEmailSchema = Joi.object({
|
|
|
15
15
|
.messages({
|
|
16
16
|
'string.max': `Email address must be ${EMAIL_MAX} characters or less`,
|
|
17
17
|
'string.empty': 'Enter a personal email address',
|
|
18
|
-
'string.email': 'Enter an email address, like name@example.com'
|
|
18
|
+
'string.email': 'Enter an email address, like name@example.com',
|
|
19
|
+
'string.noControlChars': 'Personal email address must not contain invalid characters'
|
|
19
20
|
})
|
|
20
21
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import {
|
|
3
3
|
FIRST_NAME_MAX,
|
|
4
4
|
LAST_NAME_MAX,
|
|
@@ -7,25 +7,31 @@ import {
|
|
|
7
7
|
|
|
8
8
|
export const personalNameSchema = Joi.object({
|
|
9
9
|
first: Joi.string()
|
|
10
|
+
.trim()
|
|
10
11
|
.required()
|
|
11
12
|
.max(FIRST_NAME_MAX)
|
|
12
13
|
.messages({
|
|
13
14
|
'string.empty': 'Enter first name',
|
|
14
15
|
'string.max': `First name must be ${FIRST_NAME_MAX} characters or less`,
|
|
15
|
-
'any.required': 'Enter first name'
|
|
16
|
+
'any.required': 'Enter first name',
|
|
17
|
+
'string.noControlChars': 'First name must not contain invalid characters'
|
|
16
18
|
}),
|
|
17
19
|
last: Joi.string()
|
|
20
|
+
.trim()
|
|
18
21
|
.required()
|
|
19
22
|
.max(LAST_NAME_MAX)
|
|
20
23
|
.messages({
|
|
21
24
|
'string.empty': 'Enter last name',
|
|
22
25
|
'string.max': `Last name must be ${LAST_NAME_MAX} characters or less`,
|
|
23
|
-
'any.required': 'Enter last name'
|
|
26
|
+
'any.required': 'Enter last name',
|
|
27
|
+
'string.noControlChars': 'Last name must not contain invalid characters'
|
|
24
28
|
}),
|
|
25
29
|
middle: Joi.string()
|
|
30
|
+
.trim()
|
|
26
31
|
.allow('')
|
|
27
32
|
.max(MIDDLE_NAMES_MAX)
|
|
28
33
|
.messages({
|
|
29
|
-
'string.max': `Middle names must be ${MIDDLE_NAMES_MAX} characters or less
|
|
34
|
+
'string.max': `Middle names must be ${MIDDLE_NAMES_MAX} characters or less`,
|
|
35
|
+
'string.noControlChars': 'Middle names must not contain invalid characters'
|
|
30
36
|
})
|
|
31
37
|
})
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
PHONE_NUMBER_MAX,
|
|
5
|
-
PHONE_NUMBER_PATTERN
|
|
6
|
-
} from '../../constants/validation-fields-export.js'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
|
+
import { PHONE_NUMBER_MIN, PHONE_NUMBER_MAX } from '../../constants/validation-fields.js'
|
|
3
|
+
import { PHONE_NUMBER_PATTERN } from '../../constants/patterns.js'
|
|
7
4
|
|
|
8
5
|
export const personalPhoneSchema = Joi.object({
|
|
9
6
|
personalTelephone: Joi.string()
|
|
7
|
+
.trim()
|
|
10
8
|
.empty('')
|
|
11
9
|
.min(PHONE_NUMBER_MIN)
|
|
12
10
|
.max(PHONE_NUMBER_MAX)
|
|
@@ -14,9 +12,11 @@ export const personalPhoneSchema = Joi.object({
|
|
|
14
12
|
.messages({
|
|
15
13
|
'string.min': `Personal telephone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
16
14
|
'string.max': `Personal telephone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
17
|
-
'string.pattern.base': 'Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +'
|
|
15
|
+
'string.pattern.base': 'Personal telephone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +',
|
|
16
|
+
'string.noControlChars': 'Personal telephone number must not contain invalid characters'
|
|
18
17
|
}),
|
|
19
18
|
personalMobile: Joi.string()
|
|
19
|
+
.trim()
|
|
20
20
|
.empty('')
|
|
21
21
|
.min(PHONE_NUMBER_MIN)
|
|
22
22
|
.max(PHONE_NUMBER_MAX)
|
|
@@ -24,7 +24,8 @@ export const personalPhoneSchema = Joi.object({
|
|
|
24
24
|
.messages({
|
|
25
25
|
'string.min': `Personal mobile phone number must be ${PHONE_NUMBER_MIN} characters or more`,
|
|
26
26
|
'string.max': `Personal mobile phone number must be ${PHONE_NUMBER_MAX} characters or less`,
|
|
27
|
-
'string.pattern.base': 'Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +'
|
|
27
|
+
'string.pattern.base': 'Personal mobile phone number must only include numbers 0 to 9 and special characters such as spaces, brackets and +',
|
|
28
|
+
'string.noControlChars': 'Personal mobile phone number must not contain invalid characters'
|
|
28
29
|
})
|
|
29
30
|
})
|
|
30
31
|
.or('personalTelephone', 'personalMobile')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { personalNameSchema } from './personal-name-schema.js'
|
|
2
2
|
import { personalDobSchema } from './personal-dob-schema.js'
|
|
3
|
-
import { addressSchema } from '../address-schema.js'
|
|
3
|
+
import { addressSchema } from '../shared/address-schema.js'
|
|
4
4
|
import { personalEmailSchema } from './personal-email-schema.js'
|
|
5
5
|
import { personalPhoneSchema } from './personal-phone-schema.js'
|
|
6
6
|
|
|
@@ -1,61 +1,75 @@
|
|
|
1
|
-
import Joi from 'joi'
|
|
1
|
+
import { Joi } from '../../utils/joi.js'
|
|
2
2
|
import {
|
|
3
3
|
ADDRESS_LINE_MAX,
|
|
4
4
|
TOWN_CITY_MAX,
|
|
5
5
|
COUNTY_MAX,
|
|
6
6
|
POSTCODE_MAX,
|
|
7
7
|
COUNTRY_MAX
|
|
8
|
-
} from '
|
|
8
|
+
} from '../../constants/validation-fields.js'
|
|
9
9
|
|
|
10
10
|
export const addressSchema = Joi.object({
|
|
11
11
|
address1: Joi.string()
|
|
12
|
+
.trim()
|
|
12
13
|
.required()
|
|
13
14
|
.max(ADDRESS_LINE_MAX)
|
|
14
15
|
.messages({
|
|
15
16
|
'string.empty': 'Enter address line 1, typically the building and street',
|
|
16
17
|
'string.max': `Address line 1 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
17
|
-
'any.required': 'Enter address line 1, typically the building and street'
|
|
18
|
+
'any.required': 'Enter address line 1, typically the building and street',
|
|
19
|
+
'string.noControlChars': 'Address line 1 must not contain invalid characters'
|
|
18
20
|
}),
|
|
19
21
|
address2: Joi.string()
|
|
22
|
+
.trim()
|
|
20
23
|
.allow('')
|
|
21
24
|
.max(ADDRESS_LINE_MAX)
|
|
22
25
|
.messages({
|
|
23
|
-
'string.max': `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less
|
|
26
|
+
'string.max': `Address line 2 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
27
|
+
'string.noControlChars': 'Address line 2 must not contain invalid characters'
|
|
24
28
|
}),
|
|
25
29
|
address3: Joi.string()
|
|
30
|
+
.trim()
|
|
26
31
|
.allow('')
|
|
27
32
|
.max(ADDRESS_LINE_MAX)
|
|
28
33
|
.messages({
|
|
29
|
-
'string.max': `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less
|
|
34
|
+
'string.max': `Address line 3 must be ${ADDRESS_LINE_MAX} characters or less`,
|
|
35
|
+
'string.noControlChars': 'Address line 3 must not contain invalid characters'
|
|
30
36
|
}),
|
|
31
37
|
city: Joi.string()
|
|
38
|
+
.trim()
|
|
32
39
|
.required()
|
|
33
40
|
.max(TOWN_CITY_MAX)
|
|
34
41
|
.messages({
|
|
35
42
|
'string.empty': 'Enter town or city',
|
|
36
43
|
'string.max': `Town or city must be ${TOWN_CITY_MAX} characters or less`,
|
|
37
|
-
'any.required': 'Enter town or city'
|
|
44
|
+
'any.required': 'Enter town or city',
|
|
45
|
+
'string.noControlChars': 'Town or city must not contain invalid characters'
|
|
38
46
|
}),
|
|
39
47
|
county: Joi.string()
|
|
48
|
+
.trim()
|
|
40
49
|
.allow('')
|
|
41
50
|
.max(COUNTY_MAX)
|
|
42
51
|
.messages({
|
|
43
|
-
'string.max': `County must be ${COUNTY_MAX} characters or less
|
|
52
|
+
'string.max': `County must be ${COUNTY_MAX} characters or less`,
|
|
53
|
+
'string.noControlChars': 'County must not contain invalid characters'
|
|
44
54
|
}),
|
|
45
55
|
postcode: Joi.string()
|
|
56
|
+
.trim()
|
|
46
57
|
.required()
|
|
47
58
|
.max(POSTCODE_MAX)
|
|
48
59
|
.messages({
|
|
49
60
|
'any.required': 'Enter a postal code or zip code',
|
|
50
61
|
'string.empty': 'Enter a postal code or zip code',
|
|
51
|
-
'string.max': `Postal code or zip code must be ${POSTCODE_MAX} characters or less
|
|
62
|
+
'string.max': `Postal code or zip code must be ${POSTCODE_MAX} characters or less`,
|
|
63
|
+
'string.noControlChars': 'Postal code or zip code must not contain invalid characters'
|
|
52
64
|
}),
|
|
53
65
|
country: Joi.string()
|
|
66
|
+
.trim()
|
|
54
67
|
.required()
|
|
55
68
|
.max(COUNTRY_MAX)
|
|
56
69
|
.messages({
|
|
57
70
|
'string.empty': 'Enter a country',
|
|
58
71
|
'string.max': `Country must be ${COUNTRY_MAX} characters or less`,
|
|
59
|
-
'any.required': 'Enter a country'
|
|
72
|
+
'any.required': 'Enter a country',
|
|
73
|
+
'string.noControlChars': 'Country must not contain invalid characters'
|
|
60
74
|
})
|
|
61
75
|
})
|
package/src/utils/joi.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import BaseJoi from 'joi'
|
|
2
|
+
import { NO_CONTROL_CHARS_PATTERN } from '../constants/patterns.js'
|
|
3
|
+
|
|
4
|
+
// Extends Joi's string type so every Joi.string() automatically rejects ASCII control
|
|
5
|
+
// characters (0x00–0x1f and 0x7f), which have no valid use in text input fields. Using a
|
|
6
|
+
// dedicated 'string.noControlChars' error keeps it distinct from the generic pattern rule
|
|
7
|
+
// used by numeric and phone fields. Fields may override the message via their own .messages().
|
|
8
|
+
export const Joi = BaseJoi.extend((joi) => ({
|
|
9
|
+
type: 'string',
|
|
10
|
+
base: joi.string(),
|
|
11
|
+
messages: {
|
|
12
|
+
'string.noControlChars': 'Field must not contain invalid characters'
|
|
13
|
+
},
|
|
14
|
+
validate (value, helpers) {
|
|
15
|
+
if (typeof value === 'string' && !NO_CONTROL_CHARS_PATTERN.test(value)) {
|
|
16
|
+
return { value, errors: helpers.error('string.noControlChars') }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return { value }
|
|
20
|
+
}
|
|
21
|
+
}))
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
FIRST_NAME_MAX,
|
|
3
|
-
LAST_NAME_MAX,
|
|
4
|
-
MIDDLE_NAMES_MAX,
|
|
5
|
-
EMAIL_MAX,
|
|
6
|
-
PHONE_NUMBER_MIN,
|
|
7
|
-
PHONE_NUMBER_MAX,
|
|
8
|
-
MAX_AGE_YEARS,
|
|
9
|
-
ADDRESS_LINE_MAX,
|
|
10
|
-
TOWN_CITY_MAX,
|
|
11
|
-
COUNTY_MAX,
|
|
12
|
-
COUNTRY_MAX,
|
|
13
|
-
POSTCODE_MAX
|
|
14
|
-
} from './validation-fields.js'
|
|
15
|
-
|
|
16
|
-
export { PHONE_NUMBER_PATTERN } from './patterns.js'
|
|
17
|
-
export { MONTH_MAP } from './month-map.js'
|