finprim 0.1.1 → 0.1.2
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/README.md +73 -4
- package/dist/{card-D3WC2rzV.d.mts → card-D2-7wbam.d.mts} +8 -1
- package/dist/{card-D3WC2rzV.d.ts → card-D2-7wbam.d.ts} +8 -1
- package/dist/index.d.mts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +207 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +200 -30
- package/dist/index.mjs.map +1 -1
- package/dist/nest/index.d.mts +18 -0
- package/dist/nest/index.d.ts +18 -0
- package/dist/nest/index.js +448 -0
- package/dist/nest/index.js.map +1 -0
- package/dist/nest/index.mjs +438 -0
- package/dist/nest/index.mjs.map +1 -0
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +36 -20
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +36 -20
- package/dist/react/index.mjs.map +1 -1
- package/dist/zod/index.d.mts +3 -1
- package/dist/zod/index.d.ts +3 -1
- package/dist/zod/index.js +124 -25
- package/dist/zod/index.js.map +1 -1
- package/dist/zod/index.mjs +123 -26
- package/dist/zod/index.mjs.map +1 -1
- package/package.json +13 -3
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { Injectable, BadRequestException } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
7
|
+
var __typeError = (msg) => {
|
|
8
|
+
throw TypeError(msg);
|
|
9
|
+
};
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
12
|
+
var __decoratorStart = (base) => [, , , __create(null)];
|
|
13
|
+
var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
|
|
14
|
+
var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
|
|
15
|
+
var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
|
|
16
|
+
var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
|
|
17
|
+
var __runInitializers = (array, flags, self, value) => {
|
|
18
|
+
for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) fns[i].call(self) ;
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
22
|
+
var it, done, ctx, k = flags & 7, p = false;
|
|
23
|
+
var j = 0;
|
|
24
|
+
var extraInitializers = array[j] || (array[j] = []);
|
|
25
|
+
var desc = k && ((target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(target , name));
|
|
26
|
+
__name(target, name);
|
|
27
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
28
|
+
ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
|
|
29
|
+
it = (0, decorators[i])(target, ctx), done._ = 1;
|
|
30
|
+
__expectFn(it) && (target = it);
|
|
31
|
+
}
|
|
32
|
+
return __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/_guard.ts
|
|
36
|
+
var MAX_SAFE_INPUT_LENGTH = 256;
|
|
37
|
+
function guardStringInput(input, label = "Input") {
|
|
38
|
+
if (input == null || typeof input !== "string") {
|
|
39
|
+
return { ok: false, error: `${label} must be a non-empty string` };
|
|
40
|
+
}
|
|
41
|
+
if (input.length === 0) {
|
|
42
|
+
return { ok: false, error: `${label} must be a non-empty string` };
|
|
43
|
+
}
|
|
44
|
+
if (input.length > MAX_SAFE_INPUT_LENGTH) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: `${label} must not exceed ${MAX_SAFE_INPUT_LENGTH} characters`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return { ok: true, value: input };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/iban.ts
|
|
54
|
+
var IBAN_LENGTHS = {
|
|
55
|
+
AL: 28,
|
|
56
|
+
AD: 24,
|
|
57
|
+
AT: 20,
|
|
58
|
+
AZ: 28,
|
|
59
|
+
BH: 22,
|
|
60
|
+
BE: 16,
|
|
61
|
+
BA: 20,
|
|
62
|
+
BR: 29,
|
|
63
|
+
BG: 22,
|
|
64
|
+
CR: 22,
|
|
65
|
+
HR: 21,
|
|
66
|
+
CY: 28,
|
|
67
|
+
CZ: 24,
|
|
68
|
+
DK: 18,
|
|
69
|
+
DO: 28,
|
|
70
|
+
EE: 20,
|
|
71
|
+
FI: 18,
|
|
72
|
+
FR: 27,
|
|
73
|
+
GE: 22,
|
|
74
|
+
DE: 22,
|
|
75
|
+
GI: 23,
|
|
76
|
+
GR: 27,
|
|
77
|
+
GT: 28,
|
|
78
|
+
HU: 28,
|
|
79
|
+
IS: 26,
|
|
80
|
+
IE: 22,
|
|
81
|
+
IL: 23,
|
|
82
|
+
IT: 27,
|
|
83
|
+
JO: 30,
|
|
84
|
+
KZ: 20,
|
|
85
|
+
KW: 30,
|
|
86
|
+
LV: 21,
|
|
87
|
+
LB: 28,
|
|
88
|
+
LI: 21,
|
|
89
|
+
LT: 20,
|
|
90
|
+
LU: 20,
|
|
91
|
+
MK: 19,
|
|
92
|
+
MT: 31,
|
|
93
|
+
MR: 27,
|
|
94
|
+
MU: 30,
|
|
95
|
+
MC: 27,
|
|
96
|
+
MD: 24,
|
|
97
|
+
ME: 22,
|
|
98
|
+
NL: 18,
|
|
99
|
+
NO: 15,
|
|
100
|
+
PK: 24,
|
|
101
|
+
PS: 29,
|
|
102
|
+
PL: 28,
|
|
103
|
+
PT: 25,
|
|
104
|
+
QA: 29,
|
|
105
|
+
RO: 24,
|
|
106
|
+
SM: 27,
|
|
107
|
+
SA: 24,
|
|
108
|
+
RS: 22,
|
|
109
|
+
SK: 24,
|
|
110
|
+
SI: 19,
|
|
111
|
+
ES: 24,
|
|
112
|
+
SE: 24,
|
|
113
|
+
CH: 21,
|
|
114
|
+
TN: 24,
|
|
115
|
+
TR: 26,
|
|
116
|
+
AE: 23,
|
|
117
|
+
GB: 22,
|
|
118
|
+
VG: 24
|
|
119
|
+
};
|
|
120
|
+
var LETTER_A = "A".codePointAt(0);
|
|
121
|
+
var LETTER_Z = "Z".codePointAt(0);
|
|
122
|
+
var LETTER_TO_DIGIT_OFFSET = 55;
|
|
123
|
+
function mod97(value) {
|
|
124
|
+
return [...value].reduce(
|
|
125
|
+
(remainder, char) => (remainder * 10 + Number.parseInt(char, 10)) % 97,
|
|
126
|
+
0
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
function ibanToDigits(iban) {
|
|
130
|
+
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
|
131
|
+
return [...rearranged].map((char) => {
|
|
132
|
+
const code = char.codePointAt(0) ?? 0;
|
|
133
|
+
return code >= LETTER_A && code <= LETTER_Z ? (code - LETTER_TO_DIGIT_OFFSET).toString() : char;
|
|
134
|
+
}).join("");
|
|
135
|
+
}
|
|
136
|
+
function formatIBANString(iban) {
|
|
137
|
+
return iban.replace(/(.{4})/g, "$1 ").trim();
|
|
138
|
+
}
|
|
139
|
+
function validateIBAN(input) {
|
|
140
|
+
const guarded = guardStringInput(input);
|
|
141
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
142
|
+
const cleaned = guarded.value.replace(/\s/g, "").toUpperCase();
|
|
143
|
+
if (cleaned.length < 4) {
|
|
144
|
+
return { valid: false, error: "IBAN is too short" };
|
|
145
|
+
}
|
|
146
|
+
const countryCode = cleaned.slice(0, 2);
|
|
147
|
+
if (!/^[A-Z]{2}$/.test(countryCode)) {
|
|
148
|
+
return { valid: false, error: "IBAN must start with a 2-letter country code" };
|
|
149
|
+
}
|
|
150
|
+
const expectedLength = IBAN_LENGTHS[countryCode];
|
|
151
|
+
if (!expectedLength) {
|
|
152
|
+
return { valid: false, error: `Unsupported country code: ${countryCode}` };
|
|
153
|
+
}
|
|
154
|
+
if (cleaned.length !== expectedLength) {
|
|
155
|
+
return {
|
|
156
|
+
valid: false,
|
|
157
|
+
error: `Invalid length for ${countryCode} IBAN. Expected ${expectedLength} characters, got ${cleaned.length}`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (!/^[A-Z0-9]+$/.test(cleaned)) {
|
|
161
|
+
return { valid: false, error: "IBAN contains invalid characters" };
|
|
162
|
+
}
|
|
163
|
+
const digits = ibanToDigits(cleaned);
|
|
164
|
+
if (mod97(digits) !== 1) {
|
|
165
|
+
return { valid: false, error: "IBAN checksum is invalid" };
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
valid: true,
|
|
169
|
+
value: cleaned,
|
|
170
|
+
formatted: formatIBANString(cleaned),
|
|
171
|
+
countryCode
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/sortcode.ts
|
|
176
|
+
function validateUKSortCode(input) {
|
|
177
|
+
const guarded = guardStringInput(input);
|
|
178
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
179
|
+
const cleaned = guarded.value.replace(/[-\s]/g, "");
|
|
180
|
+
if (!/^\d{6}$/.test(cleaned)) {
|
|
181
|
+
return {
|
|
182
|
+
valid: false,
|
|
183
|
+
error: "Sort code must be exactly 6 digits. Accepted formats: 60-16-13, 601613, 60 16 13"
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const formatted = `${cleaned.slice(0, 2)}-${cleaned.slice(2, 4)}-${cleaned.slice(4, 6)}`;
|
|
187
|
+
return {
|
|
188
|
+
valid: true,
|
|
189
|
+
value: cleaned,
|
|
190
|
+
formatted
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function validateUKAccountNumber(input) {
|
|
194
|
+
const guarded = guardStringInput(input);
|
|
195
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
196
|
+
const cleaned = guarded.value.replace(/\s/g, "");
|
|
197
|
+
if (!/^\d{8}$/.test(cleaned)) {
|
|
198
|
+
return {
|
|
199
|
+
valid: false,
|
|
200
|
+
error: "UK account number must be exactly 8 digits"
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const formatted = `${cleaned.slice(0, 4)} ${cleaned.slice(4, 8)}`;
|
|
204
|
+
return {
|
|
205
|
+
valid: true,
|
|
206
|
+
value: cleaned,
|
|
207
|
+
formatted
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/bic.ts
|
|
212
|
+
var BIC_REGEX = /^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/;
|
|
213
|
+
function validateBIC(input) {
|
|
214
|
+
const guarded = guardStringInput(input);
|
|
215
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
216
|
+
const cleaned = guarded.value.replace(/\s/g, "").toUpperCase();
|
|
217
|
+
if (cleaned.length !== 8 && cleaned.length !== 11) {
|
|
218
|
+
return {
|
|
219
|
+
valid: false,
|
|
220
|
+
error: `BIC must be 8 or 11 characters. Got ${cleaned.length}`
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
if (!BIC_REGEX.test(cleaned)) {
|
|
224
|
+
return {
|
|
225
|
+
valid: false,
|
|
226
|
+
error: "Invalid BIC format. Expected: 4 letters + 2 letters + 2 alphanumeric + optional 3 alphanumeric"
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const bankCode = cleaned.slice(0, 4);
|
|
230
|
+
const countryCode = cleaned.slice(4, 6);
|
|
231
|
+
const location = cleaned.slice(6, 8);
|
|
232
|
+
const branch = cleaned.length === 11 ? cleaned.slice(8, 11) : "XXX";
|
|
233
|
+
return {
|
|
234
|
+
valid: true,
|
|
235
|
+
value: cleaned,
|
|
236
|
+
formatted: `${bankCode} ${countryCode} ${location} ${branch}`
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/card.ts
|
|
241
|
+
function detectNetwork(digits) {
|
|
242
|
+
if (/^4/.test(digits)) return "Visa";
|
|
243
|
+
if (/^5[1-5]/.test(digits) || /^2[2-7]/.test(digits)) return "Mastercard";
|
|
244
|
+
if (/^3[47]/.test(digits)) return "Amex";
|
|
245
|
+
if (/^6(?:011|5)/.test(digits)) return "Discover";
|
|
246
|
+
return "Unknown";
|
|
247
|
+
}
|
|
248
|
+
function formatCardNumber(digits, network) {
|
|
249
|
+
if (network === "Amex") {
|
|
250
|
+
return `${digits.slice(0, 4)} ${digits.slice(4, 10)} ${digits.slice(10, 15)}`;
|
|
251
|
+
}
|
|
252
|
+
return digits.replace(/(.{4})/g, "$1 ").trim();
|
|
253
|
+
}
|
|
254
|
+
function validateCardNumber(input) {
|
|
255
|
+
const guarded = guardStringInput(input);
|
|
256
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
257
|
+
const digits = guarded.value.replace(/[\s-]/g, "");
|
|
258
|
+
if (!/^\d+$/.test(digits)) {
|
|
259
|
+
return { valid: false, error: "Card number must contain only digits" };
|
|
260
|
+
}
|
|
261
|
+
if (digits.length < 13 || digits.length > 19) {
|
|
262
|
+
return {
|
|
263
|
+
valid: false,
|
|
264
|
+
error: `Card number length invalid. Expected 13-19 digits, got ${digits.length}`
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
let sum = 0;
|
|
268
|
+
let shouldDouble = false;
|
|
269
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
270
|
+
let digit = Number.parseInt(digits[i], 10);
|
|
271
|
+
if (shouldDouble) {
|
|
272
|
+
digit *= 2;
|
|
273
|
+
if (digit > 9) digit -= 9;
|
|
274
|
+
}
|
|
275
|
+
sum += digit;
|
|
276
|
+
shouldDouble = !shouldDouble;
|
|
277
|
+
}
|
|
278
|
+
if (sum % 10 !== 0) {
|
|
279
|
+
return { valid: false, error: "Card number failed Luhn check \u2014 this is not a valid card number" };
|
|
280
|
+
}
|
|
281
|
+
const network = detectNetwork(digits);
|
|
282
|
+
return {
|
|
283
|
+
valid: true,
|
|
284
|
+
value: digits,
|
|
285
|
+
formatted: formatCardNumber(digits, network),
|
|
286
|
+
network,
|
|
287
|
+
last4: digits.slice(-4)
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/vat.ts
|
|
292
|
+
var EU_VAT_PATTERNS = {
|
|
293
|
+
AT: /^ATU\d{8}$/,
|
|
294
|
+
BE: /^BE0?\d{9}$/,
|
|
295
|
+
BG: /^BG\d{9,10}$/,
|
|
296
|
+
CY: /^CY\d{8}[A-Z]$/,
|
|
297
|
+
CZ: /^CZ\d{8,10}$/,
|
|
298
|
+
DE: /^DE\d{9}$/,
|
|
299
|
+
DK: /^DK\d{8}$/,
|
|
300
|
+
EE: /^EE\d{9}$/,
|
|
301
|
+
EL: /^EL\d{9}$/,
|
|
302
|
+
ES: /^ES[A-Z0-9]\d{7}[A-Z0-9]$/,
|
|
303
|
+
FI: /^FI\d{8}$/,
|
|
304
|
+
FR: /^FR[A-HJ-NP-Z0-9]{2}\d{9}$/,
|
|
305
|
+
GR: /^GR\d{9}$/,
|
|
306
|
+
HR: /^HR\d{11}$/,
|
|
307
|
+
HU: /^HU\d{8}$/,
|
|
308
|
+
IE: /^IE\d[A-Z0-9]\d{5}[A-Z]$|^IE\d{7}[A-W][A-I0-9]?$/,
|
|
309
|
+
IT: /^IT\d{11}$/,
|
|
310
|
+
LT: /^LT\d{9}$|^LT\d{12}$/,
|
|
311
|
+
LU: /^LU\d{8}$/,
|
|
312
|
+
LV: /^LV\d{11}$/,
|
|
313
|
+
MT: /^MT\d{8}$/,
|
|
314
|
+
NL: /^NL\d{9}B\d{2}$/,
|
|
315
|
+
PL: /^PL\d{10}$/,
|
|
316
|
+
PT: /^PT\d{9}$/,
|
|
317
|
+
RO: /^RO\d{2,10}$/,
|
|
318
|
+
SE: /^SE\d{12}$/,
|
|
319
|
+
SI: /^SI\d{8}$/,
|
|
320
|
+
SK: /^SK\d{10}$/
|
|
321
|
+
};
|
|
322
|
+
function validateEUVAT(input) {
|
|
323
|
+
const guarded = guardStringInput(input);
|
|
324
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
325
|
+
const cleaned = guarded.value.replace(/\s/g, "").toUpperCase();
|
|
326
|
+
if (cleaned.length < 4) {
|
|
327
|
+
return { valid: false, error: "VAT number is too short" };
|
|
328
|
+
}
|
|
329
|
+
const countryCode = cleaned.slice(0, 2);
|
|
330
|
+
const pattern = EU_VAT_PATTERNS[countryCode];
|
|
331
|
+
if (!pattern) {
|
|
332
|
+
return { valid: false, error: `Unsupported EU VAT country code: ${countryCode}` };
|
|
333
|
+
}
|
|
334
|
+
if (!pattern.test(cleaned)) {
|
|
335
|
+
return { valid: false, error: `Invalid VAT format for ${countryCode}` };
|
|
336
|
+
}
|
|
337
|
+
const formatted = `${countryCode} ${cleaned.slice(2)}`;
|
|
338
|
+
return {
|
|
339
|
+
valid: true,
|
|
340
|
+
value: cleaned,
|
|
341
|
+
formatted,
|
|
342
|
+
countryCode
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/routing.ts
|
|
347
|
+
function routingChecksum(digits) {
|
|
348
|
+
if (digits.length !== 9) return false;
|
|
349
|
+
const sum = 3 * (Number(digits[0]) + Number(digits[3]) + Number(digits[6])) + 7 * (Number(digits[1]) + Number(digits[4]) + Number(digits[7])) + Number(digits[2]) + Number(digits[5]) + Number(digits[8]);
|
|
350
|
+
return sum % 10 === 0;
|
|
351
|
+
}
|
|
352
|
+
function validateUSRoutingNumber(input) {
|
|
353
|
+
const guarded = guardStringInput(input);
|
|
354
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
355
|
+
const cleaned = guarded.value.replace(/\s/g, "");
|
|
356
|
+
if (!/^\d{9}$/.test(cleaned)) {
|
|
357
|
+
return {
|
|
358
|
+
valid: false,
|
|
359
|
+
error: "US routing number must be exactly 9 digits"
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (!routingChecksum(cleaned)) {
|
|
363
|
+
return { valid: false, error: "US routing number checksum is invalid" };
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
valid: true,
|
|
367
|
+
value: cleaned,
|
|
368
|
+
formatted: cleaned
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/currency.ts
|
|
373
|
+
var SUPPORTED_CURRENCIES = [
|
|
374
|
+
"GBP",
|
|
375
|
+
"EUR",
|
|
376
|
+
"USD",
|
|
377
|
+
"JPY",
|
|
378
|
+
"CHF",
|
|
379
|
+
"CAD",
|
|
380
|
+
"AUD",
|
|
381
|
+
"NZD"
|
|
382
|
+
];
|
|
383
|
+
function validateCurrencyCode(input) {
|
|
384
|
+
const guarded = guardStringInput(input);
|
|
385
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
386
|
+
const upper = guarded.value.toUpperCase();
|
|
387
|
+
if (!SUPPORTED_CURRENCIES.includes(upper)) {
|
|
388
|
+
return {
|
|
389
|
+
valid: false,
|
|
390
|
+
error: `Unsupported currency code: ${upper}. Supported: ${SUPPORTED_CURRENCIES.join(", ")}`
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
valid: true,
|
|
395
|
+
value: upper,
|
|
396
|
+
formatted: upper
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/nest/index.ts
|
|
401
|
+
function createFinprimPipe(validator) {
|
|
402
|
+
var _FinprimValidationPipe_decorators, _init;
|
|
403
|
+
_FinprimValidationPipe_decorators = [Injectable()];
|
|
404
|
+
class FinprimValidationPipe {
|
|
405
|
+
transform(value) {
|
|
406
|
+
if (value == null || typeof value !== "string") {
|
|
407
|
+
throw new BadRequestException("Input must be a non-empty string");
|
|
408
|
+
}
|
|
409
|
+
if (value.length === 0) {
|
|
410
|
+
throw new BadRequestException("Input must be a non-empty string");
|
|
411
|
+
}
|
|
412
|
+
const result = validator(value);
|
|
413
|
+
if (!result.valid) {
|
|
414
|
+
throw new BadRequestException(result.error ?? "Validation failed");
|
|
415
|
+
}
|
|
416
|
+
return result.value ?? value;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
_init = __decoratorStart();
|
|
420
|
+
FinprimValidationPipe = __decorateElement(_init, 0, "FinprimValidationPipe", _FinprimValidationPipe_decorators, FinprimValidationPipe);
|
|
421
|
+
__runInitializers(_init, 1, FinprimValidationPipe);
|
|
422
|
+
return FinprimValidationPipe;
|
|
423
|
+
}
|
|
424
|
+
var IbanValidationPipe = createFinprimPipe(validateIBAN);
|
|
425
|
+
var SortCodeValidationPipe = createFinprimPipe(validateUKSortCode);
|
|
426
|
+
var AccountNumberValidationPipe = createFinprimPipe(validateUKAccountNumber);
|
|
427
|
+
var BicValidationPipe = createFinprimPipe(validateBIC);
|
|
428
|
+
var CardNumberValidationPipe = createFinprimPipe(validateCardNumber);
|
|
429
|
+
var VatValidationPipe = createFinprimPipe(validateEUVAT);
|
|
430
|
+
var RoutingNumberValidationPipe = createFinprimPipe(validateUSRoutingNumber);
|
|
431
|
+
var CurrencyCodeValidationPipe = createFinprimPipe(validateCurrencyCode);
|
|
432
|
+
function createValidationPipe(validator) {
|
|
433
|
+
return createFinprimPipe(validator);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export { AccountNumberValidationPipe, BicValidationPipe, CardNumberValidationPipe, CurrencyCodeValidationPipe, IbanValidationPipe, RoutingNumberValidationPipe, SortCodeValidationPipe, VatValidationPipe, createValidationPipe };
|
|
437
|
+
//# sourceMappingURL=index.mjs.map
|
|
438
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/_guard.ts","../../src/iban.ts","../../src/sortcode.ts","../../src/bic.ts","../../src/card.ts","../../src/vat.ts","../../src/routing.ts","../../src/currency.ts","../../src/nest/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["export const MAX_SAFE_INPUT_LENGTH = 256\n\nexport function guardStringInput(\n input: unknown,\n label = 'Input'\n): { ok: true; value: string } | { ok: false; error: string } {\n if (input == null || typeof input !== 'string') {\n return { ok: false, error: `${label} must be a non-empty string` }\n }\n if (input.length === 0) {\n return { ok: false, error: `${label} must be a non-empty string` }\n }\n if (input.length > MAX_SAFE_INPUT_LENGTH) {\n return {\n ok: false,\n error: `${label} must not exceed ${MAX_SAFE_INPUT_LENGTH} characters`,\n }\n }\n return { ok: true, value: input }\n}\n\nexport function guardNumber(\n value: unknown,\n options: { min?: number; max?: number; integer?: boolean; label?: string }\n): { ok: true; value: number } | { ok: false; error: string } {\n const label = options.label ?? 'Value'\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return { ok: false, error: `${label} must be a finite number` }\n }\n if (Number.isNaN(value)) {\n return { ok: false, error: `${label} must not be NaN` }\n }\n if (options.integer && !Number.isInteger(value)) {\n return { ok: false, error: `${label} must be an integer` }\n }\n if (options.min !== undefined && value < options.min) {\n return { ok: false, error: `${label} must be at least ${options.min}` }\n }\n if (options.max !== undefined && value > options.max) {\n return { ok: false, error: `${label} must be at most ${options.max}` }\n }\n return { ok: true, value }\n}\n","import type { IBAN, IBANValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nconst IBAN_LENGTHS: Record<string, number> = {\n AL: 28, AD: 24, AT: 20, AZ: 28, BH: 22, BE: 16, BA: 20, BR: 29,\n BG: 22, CR: 22, HR: 21, CY: 28, CZ: 24, DK: 18, DO: 28, EE: 20,\n FI: 18, FR: 27, GE: 22, DE: 22, GI: 23, GR: 27, GT: 28, HU: 28,\n IS: 26, IE: 22, IL: 23, IT: 27, JO: 30, KZ: 20, KW: 30, LV: 21,\n LB: 28, LI: 21, LT: 20, LU: 20, MK: 19, MT: 31, MR: 27, MU: 30,\n MC: 27, MD: 24, ME: 22, NL: 18, NO: 15, PK: 24, PS: 29, PL: 28,\n PT: 25, QA: 29, RO: 24, SM: 27, SA: 24, RS: 22, SK: 24, SI: 19,\n ES: 24, SE: 24, CH: 21, TN: 24, TR: 26, AE: 23, GB: 22, VG: 24,\n}\n\nconst LETTER_A = 'A'.codePointAt(0)!\nconst LETTER_Z = 'Z'.codePointAt(0)!\nconst LETTER_TO_DIGIT_OFFSET = 55\n\nfunction mod97(value: string): number {\n return [...value].reduce(\n (remainder, char) => (remainder * 10 + Number.parseInt(char, 10)) % 97,\n 0\n )\n}\n\nfunction ibanToDigits(iban: string): string {\n const rearranged = iban.slice(4) + iban.slice(0, 4)\n return [...rearranged]\n .map((char) => {\n const code = char.codePointAt(0) ?? 0\n return code >= LETTER_A && code <= LETTER_Z\n ? (code - LETTER_TO_DIGIT_OFFSET).toString()\n : char\n })\n .join('')\n}\n\nfunction formatIBANString(iban: string): string {\n return iban.replace(/(.{4})/g, '$1 ').trim()\n}\n\nexport function formatIBAN(input: string): string {\n if (typeof input !== 'string') return ''\n const cleaned = input.replace(/\\s/g, '').toUpperCase().slice(0, 34)\n return formatIBANString(cleaned)\n}\n\nexport function validateIBAN(input: string): IBANValidationResult {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/\\s/g, '').toUpperCase()\n\n if (cleaned.length < 4) {\n return { valid: false, error: 'IBAN is too short' }\n }\n\n const countryCode = cleaned.slice(0, 2)\n\n if (!/^[A-Z]{2}$/.test(countryCode)) {\n return { valid: false, error: 'IBAN must start with a 2-letter country code' }\n }\n\n const expectedLength = IBAN_LENGTHS[countryCode]\n\n if (!expectedLength) {\n return { valid: false, error: `Unsupported country code: ${countryCode}` }\n }\n\n if (cleaned.length !== expectedLength) {\n return {\n valid: false,\n error: `Invalid length for ${countryCode} IBAN. Expected ${expectedLength} characters, got ${cleaned.length}`,\n }\n }\n\n if (!/^[A-Z0-9]+$/.test(cleaned)) {\n return { valid: false, error: 'IBAN contains invalid characters' }\n }\n\n const digits = ibanToDigits(cleaned)\n\n if (mod97(digits) !== 1) {\n return { valid: false, error: 'IBAN checksum is invalid' }\n }\n\n return {\n valid: true,\n value: cleaned as IBAN,\n formatted: formatIBANString(cleaned),\n countryCode,\n }\n}\n","import type { SortCode, AccountNumber, ValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nexport function formatSortCode(input: string): string {\n if (typeof input !== 'string') return ''\n const digits = input.replace(/[-\\s]/g, '').slice(0, 6)\n if (digits.length < 6) return digits\n return `${digits.slice(0, 2)}-${digits.slice(2, 4)}-${digits.slice(4, 6)}`\n}\n\nexport function formatUKAccountNumber(input: string): string {\n if (typeof input !== 'string') return ''\n const digits = input.replace(/\\s/g, '').slice(0, 8)\n if (digits.length < 8) return digits\n return `${digits.slice(0, 4)} ${digits.slice(4, 8)}`\n}\n\nexport function validateUKSortCode(input: string): ValidationResult<SortCode> {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/[-\\s]/g, '')\n\n if (!/^\\d{6}$/.test(cleaned)) {\n return {\n valid: false,\n error: 'Sort code must be exactly 6 digits. Accepted formats: 60-16-13, 601613, 60 16 13',\n }\n }\n\n const formatted = `${cleaned.slice(0, 2)}-${cleaned.slice(2, 4)}-${cleaned.slice(4, 6)}`\n\n return {\n valid: true,\n value: cleaned as SortCode,\n formatted,\n }\n}\n\nexport function validateUKAccountNumber(input: string): ValidationResult<AccountNumber> {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/\\s/g, '')\n\n if (!/^\\d{8}$/.test(cleaned)) {\n return {\n valid: false,\n error: 'UK account number must be exactly 8 digits',\n }\n }\n\n const formatted = `${cleaned.slice(0, 4)} ${cleaned.slice(4, 8)}`\n\n return {\n valid: true,\n value: cleaned as AccountNumber,\n formatted,\n }\n}\n","import type { BIC, ValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nconst BIC_REGEX = /^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/\n\nexport function validateBIC(input: string): ValidationResult<BIC> {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/\\s/g, '').toUpperCase()\n\n if (cleaned.length !== 8 && cleaned.length !== 11) {\n return {\n valid: false,\n error: `BIC must be 8 or 11 characters. Got ${cleaned.length}`,\n }\n }\n\n if (!BIC_REGEX.test(cleaned)) {\n return {\n valid: false,\n error: 'Invalid BIC format. Expected: 4 letters + 2 letters + 2 alphanumeric + optional 3 alphanumeric',\n }\n }\n\n const bankCode = cleaned.slice(0, 4)\n const countryCode = cleaned.slice(4, 6)\n const location = cleaned.slice(6, 8)\n const branch = cleaned.length === 11 ? cleaned.slice(8, 11) : 'XXX'\n\n return {\n valid: true,\n value: cleaned as BIC,\n formatted: `${bankCode} ${countryCode} ${location} ${branch}`,\n }\n}\n","import type { CardNumber, ValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nexport type CardNetwork = 'Visa' | 'Mastercard' | 'Amex' | 'Discover' | 'Unknown'\n\nexport type CardValidationResult =\n | { valid: true; value: CardNumber; formatted: string; network: CardNetwork; last4: string }\n | { valid: false; error: string }\n\nfunction detectNetwork(digits: string): CardNetwork {\n if (/^4/.test(digits)) return 'Visa'\n if (/^5[1-5]/.test(digits) || /^2[2-7]/.test(digits)) return 'Mastercard'\n if (/^3[47]/.test(digits)) return 'Amex'\n if (/^6(?:011|5)/.test(digits)) return 'Discover'\n return 'Unknown'\n}\n\nfunction formatCardNumber(digits: string, network: CardNetwork): string {\n if (network === 'Amex') {\n return `${digits.slice(0, 4)} ${digits.slice(4, 10)} ${digits.slice(10, 15)}`\n }\n return digits.replace(/(.{4})/g, '$1 ').trim()\n}\n\nexport function validateCardNumber(input: string): CardValidationResult {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const digits = guarded.value.replace(/[\\s-]/g, '')\n\n if (!/^\\d+$/.test(digits)) {\n return { valid: false, error: 'Card number must contain only digits' }\n }\n\n if (digits.length < 13 || digits.length > 19) {\n return {\n valid: false,\n error: `Card number length invalid. Expected 13-19 digits, got ${digits.length}`,\n }\n }\n\n let sum = 0\n let shouldDouble = false\n\n for (let i = digits.length - 1; i >= 0; i--) {\n let digit = Number.parseInt(digits[i]!, 10)\n if (shouldDouble) {\n digit *= 2\n if (digit > 9) digit -= 9\n }\n sum += digit\n shouldDouble = !shouldDouble\n }\n\n if (sum % 10 !== 0) {\n return { valid: false, error: 'Card number failed Luhn check — this is not a valid card number' }\n }\n\n const network = detectNetwork(digits)\n\n return {\n valid: true,\n value: digits as CardNumber,\n formatted: formatCardNumber(digits, network),\n network,\n last4: digits.slice(-4),\n }\n}\n","import type { VATNumber, VATValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nconst EU_VAT_PATTERNS: Record<string, RegExp> = {\n AT: /^ATU\\d{8}$/,\n BE: /^BE0?\\d{9}$/,\n BG: /^BG\\d{9,10}$/,\n CY: /^CY\\d{8}[A-Z]$/,\n CZ: /^CZ\\d{8,10}$/,\n DE: /^DE\\d{9}$/,\n DK: /^DK\\d{8}$/,\n EE: /^EE\\d{9}$/,\n EL: /^EL\\d{9}$/,\n ES: /^ES[A-Z0-9]\\d{7}[A-Z0-9]$/,\n FI: /^FI\\d{8}$/,\n FR: /^FR[A-HJ-NP-Z0-9]{2}\\d{9}$/,\n GR: /^GR\\d{9}$/,\n HR: /^HR\\d{11}$/,\n HU: /^HU\\d{8}$/,\n IE: /^IE\\d[A-Z0-9]\\d{5}[A-Z]$|^IE\\d{7}[A-W][A-I0-9]?$/,\n IT: /^IT\\d{11}$/,\n LT: /^LT\\d{9}$|^LT\\d{12}$/,\n LU: /^LU\\d{8}$/,\n LV: /^LV\\d{11}$/,\n MT: /^MT\\d{8}$/,\n NL: /^NL\\d{9}B\\d{2}$/,\n PL: /^PL\\d{10}$/,\n PT: /^PT\\d{9}$/,\n RO: /^RO\\d{2,10}$/,\n SE: /^SE\\d{12}$/,\n SI: /^SI\\d{8}$/,\n SK: /^SK\\d{10}$/,\n}\n\nexport function validateEUVAT(input: string): VATValidationResult {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/\\s/g, '').toUpperCase()\n\n if (cleaned.length < 4) {\n return { valid: false, error: 'VAT number is too short' }\n }\n\n const countryCode = cleaned.slice(0, 2)\n\n const pattern = EU_VAT_PATTERNS[countryCode]\n if (!pattern) {\n return { valid: false, error: `Unsupported EU VAT country code: ${countryCode}` }\n }\n\n if (!pattern.test(cleaned)) {\n return { valid: false, error: `Invalid VAT format for ${countryCode}` }\n }\n\n const formatted = `${countryCode} ${cleaned.slice(2)}`\n\n return {\n valid: true,\n value: cleaned as VATNumber,\n formatted,\n countryCode,\n }\n}\n","import type { RoutingNumber, ValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nfunction routingChecksum(digits: string): boolean {\n if (digits.length !== 9) return false\n const sum =\n 3 * (Number(digits[0]) + Number(digits[3]) + Number(digits[6])) +\n 7 * (Number(digits[1]) + Number(digits[4]) + Number(digits[7])) +\n Number(digits[2]) + Number(digits[5]) + Number(digits[8])\n return sum % 10 === 0\n}\n\nexport function validateUSRoutingNumber(input: string): ValidationResult<RoutingNumber> {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const cleaned = guarded.value.replace(/\\s/g, '')\n\n if (!/^\\d{9}$/.test(cleaned)) {\n return {\n valid: false,\n error: 'US routing number must be exactly 9 digits',\n }\n }\n\n if (!routingChecksum(cleaned)) {\n return { valid: false, error: 'US routing number checksum is invalid' }\n }\n\n return {\n valid: true,\n value: cleaned as RoutingNumber,\n formatted: cleaned,\n }\n}\n","import type { CurrencyCode, SupportedCurrency, MoneyResult, ValidationResult } from './types'\nimport { guardStringInput } from './_guard'\n\nexport const SUPPORTED_CURRENCIES: SupportedCurrency[] = [\n 'GBP', 'EUR', 'USD', 'JPY', 'CHF', 'CAD', 'AUD', 'NZD',\n]\n\nconst CURRENCY_LOCALES: Record<SupportedCurrency, string> = {\n GBP: 'en-GB',\n EUR: 'de-DE',\n USD: 'en-US',\n JPY: 'ja-JP',\n CHF: 'de-CH',\n CAD: 'en-CA',\n AUD: 'en-AU',\n NZD: 'en-NZ',\n}\n\nconst SYMBOL_MAP: Record<string, SupportedCurrency> = {\n '£': 'GBP',\n '€': 'EUR',\n '$': 'USD',\n '¥': 'JPY',\n 'CHF': 'CHF',\n}\n\nexport function validateCurrencyCode(input: string): ValidationResult<CurrencyCode> {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n const upper = guarded.value.toUpperCase() as SupportedCurrency\n\n if (!SUPPORTED_CURRENCIES.includes(upper)) {\n return {\n valid: false,\n error: `Unsupported currency code: ${upper}. Supported: ${SUPPORTED_CURRENCIES.join(', ')}`,\n }\n }\n\n return {\n valid: true,\n value: upper as CurrencyCode,\n formatted: upper,\n }\n}\n\nexport function formatCurrency(\n amount: number,\n currency: SupportedCurrency,\n locale?: string\n): string {\n if (typeof amount !== 'number' || !Number.isFinite(amount)) {\n return ''\n }\n const resolvedLocale = locale ?? CURRENCY_LOCALES[currency] ?? 'en-GB'\n return new Intl.NumberFormat(resolvedLocale, {\n style: 'currency',\n currency,\n minimumFractionDigits: currency === 'JPY' ? 0 : 2,\n maximumFractionDigits: currency === 'JPY' ? 0 : 2,\n }).format(amount)\n}\n\nexport function parseMoney(input: string): MoneyResult {\n const guarded = guardStringInput(input)\n if (!guarded.ok) return { valid: false, error: guarded.error }\n\n let currency: SupportedCurrency | undefined\n let cleaned = guarded.value.trim()\n\n for (const [symbol, code] of Object.entries(SYMBOL_MAP)) {\n if (cleaned.startsWith(symbol) || cleaned.endsWith(symbol)) {\n currency = code\n cleaned = cleaned.replace(symbol, '').trim()\n break\n }\n }\n\n if (!currency) {\n return { valid: false, error: 'Could not detect currency from input. Expected a symbol like £, €, $, ¥' }\n }\n\n const normalised = cleaned.replace(/,/g, '')\n const amount = Number.parseFloat(normalised)\n\n if (Number.isNaN(amount)) {\n return { valid: false, error: `Could not parse amount from: \"${cleaned}\"` }\n }\n\n return {\n valid: true,\n amount,\n currency,\n formatted: formatCurrency(amount, currency),\n }\n}\n","import type { PipeTransform } from '@nestjs/common'\nimport { Injectable, BadRequestException } from '@nestjs/common'\nimport { validateIBAN } from '../iban'\nimport { validateUKSortCode, validateUKAccountNumber } from '../sortcode'\nimport { validateBIC } from '../bic'\nimport { validateCardNumber } from '../card'\nimport { validateEUVAT } from '../vat'\nimport { validateUSRoutingNumber } from '../routing'\nimport { validateCurrencyCode } from '../currency'\n\ntype StringValidator = (val: string) => { valid: boolean; value?: string; error?: string }\n\nfunction createFinprimPipe(validator: StringValidator): new () => PipeTransform<string, string> {\n @Injectable()\n class FinprimValidationPipe implements PipeTransform<string, string> {\n transform(value: unknown): string {\n if (value == null || typeof value !== 'string') {\n throw new BadRequestException('Input must be a non-empty string')\n }\n if (value.length === 0) {\n throw new BadRequestException('Input must be a non-empty string')\n }\n const result = validator(value)\n if (!result.valid) {\n throw new BadRequestException(result.error ?? 'Validation failed')\n }\n return result.value ?? value\n }\n }\n return FinprimValidationPipe\n}\n\nexport const IbanValidationPipe = createFinprimPipe(validateIBAN)\nexport const SortCodeValidationPipe = createFinprimPipe(validateUKSortCode)\nexport const AccountNumberValidationPipe = createFinprimPipe(validateUKAccountNumber)\nexport const BicValidationPipe = createFinprimPipe(validateBIC)\nexport const CardNumberValidationPipe = createFinprimPipe(validateCardNumber)\nexport const VatValidationPipe = createFinprimPipe(validateEUVAT)\nexport const RoutingNumberValidationPipe = createFinprimPipe(validateUSRoutingNumber)\nexport const CurrencyCodeValidationPipe = createFinprimPipe(validateCurrencyCode)\n\nexport function createValidationPipe(validator: StringValidator): new () => PipeTransform<string, string> {\n return createFinprimPipe(validator)\n}\n"]}
|
package/dist/react/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as ValidationResult, A as AccountNumber, B as BIC,
|
|
1
|
+
import { V as ValidationResult, A as AccountNumber, B as BIC, d as CardNumber, e as CardValidationResult, a as SupportedCurrency, f as IBAN, S as SortCode } from '../card-D2-7wbam.mjs';
|
|
2
2
|
|
|
3
3
|
type HookResult<T, R = ValidationResult<T>> = {
|
|
4
4
|
value: string;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as ValidationResult, A as AccountNumber, B as BIC,
|
|
1
|
+
import { V as ValidationResult, A as AccountNumber, B as BIC, d as CardNumber, e as CardValidationResult, a as SupportedCurrency, f as IBAN, S as SortCode } from '../card-D2-7wbam.js';
|
|
2
2
|
|
|
3
3
|
type HookResult<T, R = ValidationResult<T>> = {
|
|
4
4
|
value: string;
|
package/dist/react/index.js
CHANGED
|
@@ -4,6 +4,24 @@ var react = require('react');
|
|
|
4
4
|
|
|
5
5
|
// src/react/index.ts
|
|
6
6
|
|
|
7
|
+
// src/_guard.ts
|
|
8
|
+
var MAX_SAFE_INPUT_LENGTH = 256;
|
|
9
|
+
function guardStringInput(input, label = "Input") {
|
|
10
|
+
if (input == null || typeof input !== "string") {
|
|
11
|
+
return { ok: false, error: `${label} must be a non-empty string` };
|
|
12
|
+
}
|
|
13
|
+
if (input.length === 0) {
|
|
14
|
+
return { ok: false, error: `${label} must be a non-empty string` };
|
|
15
|
+
}
|
|
16
|
+
if (input.length > MAX_SAFE_INPUT_LENGTH) {
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
error: `${label} must not exceed ${MAX_SAFE_INPUT_LENGTH} characters`
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return { ok: true, value: input };
|
|
23
|
+
}
|
|
24
|
+
|
|
7
25
|
// src/iban.ts
|
|
8
26
|
var IBAN_LENGTHS = {
|
|
9
27
|
AL: 28,
|
|
@@ -91,10 +109,9 @@ function formatIBANString(iban) {
|
|
|
91
109
|
return iban.replace(/(.{4})/g, "$1 ").trim();
|
|
92
110
|
}
|
|
93
111
|
function validateIBAN(input) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const cleaned = input.replace(/\s/g, "").toUpperCase();
|
|
112
|
+
const guarded = guardStringInput(input);
|
|
113
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
114
|
+
const cleaned = guarded.value.replace(/\s/g, "").toUpperCase();
|
|
98
115
|
if (cleaned.length < 4) {
|
|
99
116
|
return { valid: false, error: "IBAN is too short" };
|
|
100
117
|
}
|
|
@@ -129,10 +146,9 @@ function validateIBAN(input) {
|
|
|
129
146
|
|
|
130
147
|
// src/sortcode.ts
|
|
131
148
|
function validateUKSortCode(input) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const cleaned = input.replace(/[-\s]/g, "");
|
|
149
|
+
const guarded = guardStringInput(input);
|
|
150
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
151
|
+
const cleaned = guarded.value.replace(/[-\s]/g, "");
|
|
136
152
|
if (!/^\d{6}$/.test(cleaned)) {
|
|
137
153
|
return {
|
|
138
154
|
valid: false,
|
|
@@ -147,10 +163,9 @@ function validateUKSortCode(input) {
|
|
|
147
163
|
};
|
|
148
164
|
}
|
|
149
165
|
function validateUKAccountNumber(input) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const cleaned = input.replace(/\s/g, "");
|
|
166
|
+
const guarded = guardStringInput(input);
|
|
167
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
168
|
+
const cleaned = guarded.value.replace(/\s/g, "");
|
|
154
169
|
if (!/^\d{8}$/.test(cleaned)) {
|
|
155
170
|
return {
|
|
156
171
|
valid: false,
|
|
@@ -177,6 +192,9 @@ var CURRENCY_LOCALES = {
|
|
|
177
192
|
NZD: "en-NZ"
|
|
178
193
|
};
|
|
179
194
|
function formatCurrency(amount, currency, locale) {
|
|
195
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
196
|
+
return "";
|
|
197
|
+
}
|
|
180
198
|
const resolvedLocale = locale ?? CURRENCY_LOCALES[currency] ?? "en-GB";
|
|
181
199
|
return new Intl.NumberFormat(resolvedLocale, {
|
|
182
200
|
style: "currency",
|
|
@@ -189,10 +207,9 @@ function formatCurrency(amount, currency, locale) {
|
|
|
189
207
|
// src/bic.ts
|
|
190
208
|
var BIC_REGEX = /^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/;
|
|
191
209
|
function validateBIC(input) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const cleaned = input.replace(/\s/g, "").toUpperCase();
|
|
210
|
+
const guarded = guardStringInput(input);
|
|
211
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
212
|
+
const cleaned = guarded.value.replace(/\s/g, "").toUpperCase();
|
|
196
213
|
if (cleaned.length !== 8 && cleaned.length !== 11) {
|
|
197
214
|
return {
|
|
198
215
|
valid: false,
|
|
@@ -231,10 +248,9 @@ function formatCardNumber(digits, network) {
|
|
|
231
248
|
return digits.replace(/(.{4})/g, "$1 ").trim();
|
|
232
249
|
}
|
|
233
250
|
function validateCardNumber(input) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const digits = input.replace(/[\s-]/g, "");
|
|
251
|
+
const guarded = guardStringInput(input);
|
|
252
|
+
if (!guarded.ok) return { valid: false, error: guarded.error };
|
|
253
|
+
const digits = guarded.value.replace(/[\s-]/g, "");
|
|
238
254
|
if (!/^\d+$/.test(digits)) {
|
|
239
255
|
return { valid: false, error: "Card number must contain only digits" };
|
|
240
256
|
}
|