bysquare 2.9.0 → 2.11.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/README.md +18 -11
- package/dist/base32hex.d.ts +2 -0
- package/dist/base32hex.js +53 -0
- package/dist/cli.js +18 -1
- package/dist/crc32.d.ts +1 -0
- package/dist/crc32.js +63 -0
- package/dist/deburr.d.ts +1 -1
- package/dist/deburr.js +11 -5
- package/dist/decode.js +11 -16
- package/dist/encode.d.ts +7 -1
- package/dist/encode.js +29 -18
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +93 -63
- package/dist/types.js +51 -28
- package/dist/validations.d.ts +41 -0
- package/dist/validations.js +67 -0
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -22,9 +22,10 @@ transformed into images depends on how you implement it. See
|
|
|
22
22
|
|
|
23
23
|
## Installation
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
> [!NOTE]
|
|
26
|
+
> This package is native [ESM][mozzila-esm] and no longer provides a
|
|
27
|
+
> CommonJS export. If your project uses CommonJS, you will have to convert to ESM
|
|
28
|
+
> or use the dynamic [`import()`][mozzila-import] function.
|
|
28
29
|
|
|
29
30
|
[mozzila-esm]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
|
|
30
31
|
[mozzila-import]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
|
|
@@ -49,23 +50,17 @@ Since `v1.28+` import from npm registry using `npm:` prefix.
|
|
|
49
50
|
import {
|
|
50
51
|
decode,
|
|
51
52
|
encode,
|
|
52
|
-
} from "npm:bysquare@
|
|
53
|
+
} from "npm:bysquare@latest";
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
### Browser
|
|
56
57
|
|
|
57
58
|
```html
|
|
58
59
|
<script type="module">
|
|
59
|
-
import { encode, decode } from "https://esm.sh/bysquare@
|
|
60
|
+
import { encode, decode } from "https://esm.sh/bysquare@latest";
|
|
60
61
|
</script>
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
## How it works
|
|
64
|
-
|
|
65
|
-
### Encoding sequence
|
|
66
|
-
|
|
67
|
-

|
|
68
|
-
|
|
69
64
|
## Usage
|
|
70
65
|
|
|
71
66
|
### Encode
|
|
@@ -143,6 +138,12 @@ qrstring argument should be a valid QR code string.
|
|
|
143
138
|
npx bysquare --decode <qrstring>
|
|
144
139
|
```
|
|
145
140
|
|
|
141
|
+
## How it works
|
|
142
|
+
|
|
143
|
+
### Encoding sequence
|
|
144
|
+
|
|
145
|
+

|
|
146
|
+
|
|
146
147
|
## Platform support
|
|
147
148
|
|
|
148
149
|
I mainly focus on LTS versions of Node.js and try to use the most idiomatic
|
|
@@ -163,6 +164,12 @@ to use without additional setup, showing its improved maturity.
|
|
|
163
164
|
|
|
164
165
|
The latest version of Chrome, Firefox, and Safari.
|
|
165
166
|
|
|
167
|
+
## Troubleshooting & Recommendations
|
|
168
|
+
|
|
169
|
+
### Encoded data are without diacritics
|
|
170
|
+
|
|
171
|
+
The library removes all diacritics from the input data to ensure maximum compatibility, as not all banks support diacritics, which may lead to errors. If you need to retain diacritics, disable deburr option when encoding data - `encode(model, { deburr: false })`.
|
|
172
|
+
|
|
166
173
|
## Related
|
|
167
174
|
|
|
168
175
|
- <https://bysquare.com/>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const base32Hex = {
|
|
2
|
+
chars: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
3
|
+
bits: 5,
|
|
4
|
+
mask: 0b11111, // Mask to extract 5 bits
|
|
5
|
+
};
|
|
6
|
+
export function encode(input, addPadding = true) {
|
|
7
|
+
const output = Array();
|
|
8
|
+
let buffer = 0;
|
|
9
|
+
let bitsLeft = 0;
|
|
10
|
+
for (let i = 0; i < input.length; i++) {
|
|
11
|
+
buffer = (buffer << 8) | input[i];
|
|
12
|
+
bitsLeft += 8;
|
|
13
|
+
while (bitsLeft >= base32Hex.bits) {
|
|
14
|
+
bitsLeft -= base32Hex.bits;
|
|
15
|
+
const index = (buffer >> bitsLeft) & base32Hex.mask;
|
|
16
|
+
output.push(base32Hex.chars[index]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (bitsLeft > 0) {
|
|
20
|
+
const maskedValue = (buffer << (base32Hex.bits - bitsLeft)) & base32Hex.mask;
|
|
21
|
+
output.push(base32Hex.chars[maskedValue]);
|
|
22
|
+
}
|
|
23
|
+
let base32hex = output.join("");
|
|
24
|
+
if (addPadding) {
|
|
25
|
+
const paddedLength = Math.ceil(base32hex.length / 8) * 8;
|
|
26
|
+
base32hex = base32hex.padEnd(paddedLength, "=");
|
|
27
|
+
}
|
|
28
|
+
return base32hex;
|
|
29
|
+
}
|
|
30
|
+
export function decode(input, isLoose = false) {
|
|
31
|
+
if (isLoose) {
|
|
32
|
+
input = input.toUpperCase();
|
|
33
|
+
const paddingNeeded = (8 - (input.length % 8)) % 8;
|
|
34
|
+
input += "=".repeat(paddingNeeded);
|
|
35
|
+
}
|
|
36
|
+
input = input.replace(/=+$/, "");
|
|
37
|
+
const output = Array();
|
|
38
|
+
let buffer = 0;
|
|
39
|
+
let bitsLeft = 0;
|
|
40
|
+
for (let i = 0; i < input.length; i++) {
|
|
41
|
+
const index = base32Hex.chars.indexOf(input[i]);
|
|
42
|
+
if (index === -1) {
|
|
43
|
+
throw new Error("Invalid base32hex string");
|
|
44
|
+
}
|
|
45
|
+
buffer = (buffer << base32Hex.bits) | index;
|
|
46
|
+
bitsLeft += base32Hex.bits;
|
|
47
|
+
if (bitsLeft >= 8) {
|
|
48
|
+
bitsLeft -= 8;
|
|
49
|
+
output.push((buffer >> bitsLeft) & 0xFF);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return Uint8Array.from(output);
|
|
53
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -15,6 +15,14 @@ const args = parseArgs({
|
|
|
15
15
|
type: "boolean",
|
|
16
16
|
short: "e",
|
|
17
17
|
},
|
|
18
|
+
validate: {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
short: "v",
|
|
21
|
+
},
|
|
22
|
+
deburr: {
|
|
23
|
+
type: "boolean",
|
|
24
|
+
short: "b",
|
|
25
|
+
},
|
|
18
26
|
help: {
|
|
19
27
|
type: "boolean",
|
|
20
28
|
short: "h",
|
|
@@ -48,7 +56,10 @@ if (process.stdin.isTTY) {
|
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
if (file.endsWith(".json")) {
|
|
51
|
-
console.log(encode(JSON.parse(data)
|
|
59
|
+
console.log(encode(JSON.parse(data), {
|
|
60
|
+
validate: Boolean(args.values.validate),
|
|
61
|
+
deburr: Boolean(args.values.deburr),
|
|
62
|
+
}));
|
|
52
63
|
}
|
|
53
64
|
process.exit(0);
|
|
54
65
|
}
|
|
@@ -80,6 +91,12 @@ if (process.stdin.isTTY) {
|
|
|
80
91
|
" -e, --encode",
|
|
81
92
|
" Encode JSON data from one or more files and print the corresponding QR code.",
|
|
82
93
|
"",
|
|
94
|
+
" -v, --validate",
|
|
95
|
+
" Validate JSON data from one or more files before encoding.",
|
|
96
|
+
"",
|
|
97
|
+
" -b, --deburr",
|
|
98
|
+
" Deburr JSON data from one or more files before encoding.",
|
|
99
|
+
"",
|
|
83
100
|
" -h, --help",
|
|
84
101
|
" Display the help message and exit.",
|
|
85
102
|
"",
|
package/dist/crc32.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function crc32(data: string): number;
|
package/dist/crc32.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Computed CRC32 lookup table
|
|
2
|
+
// const CRC32_TABLE = new Uint32Array(256);
|
|
3
|
+
// for (let i = 0; i < CRC32_TABLE.length; i++) {
|
|
4
|
+
// let crc = i;
|
|
5
|
+
// for (let j = 0; j < 8; j++) {
|
|
6
|
+
// crc = (crc >>> 1) ^ (0xEDB88320 * (crc & 1));
|
|
7
|
+
// }
|
|
8
|
+
// CRC32_TABLE[i] = crc;
|
|
9
|
+
// }
|
|
10
|
+
// dprint-ignore
|
|
11
|
+
const CRC32_TABLE = [
|
|
12
|
+
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
|
13
|
+
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
14
|
+
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
|
15
|
+
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
16
|
+
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
|
17
|
+
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
18
|
+
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
|
19
|
+
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
20
|
+
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
|
21
|
+
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
22
|
+
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
|
23
|
+
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
24
|
+
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
|
25
|
+
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
26
|
+
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
|
27
|
+
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
28
|
+
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
|
29
|
+
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
30
|
+
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
|
31
|
+
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
32
|
+
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
|
33
|
+
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
34
|
+
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
|
35
|
+
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
36
|
+
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
|
37
|
+
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
38
|
+
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
|
39
|
+
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
40
|
+
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
|
41
|
+
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
42
|
+
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
|
43
|
+
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
44
|
+
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
|
45
|
+
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
46
|
+
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
|
47
|
+
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
48
|
+
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
|
49
|
+
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
50
|
+
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
|
51
|
+
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
52
|
+
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
|
53
|
+
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
54
|
+
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
55
|
+
];
|
|
56
|
+
export function crc32(data) {
|
|
57
|
+
let crc = 0 ^ (-1);
|
|
58
|
+
const encoded = new TextEncoder().encode(data);
|
|
59
|
+
for (let i = 0; i < encoded.length; i++) {
|
|
60
|
+
crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ encoded[i]) & 0xFF];
|
|
61
|
+
}
|
|
62
|
+
return (crc ^ (-1)) >>> 0;
|
|
63
|
+
}
|
package/dist/deburr.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare function deburrLetter(key: string): string;
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
|
|
4
4
|
*/
|
|
5
5
|
export declare function deburr(text: string): string;
|
package/dist/deburr.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Used to map Latin Unicode letters to basic Latin letters. */
|
|
2
1
|
/** dprint-ignore */
|
|
2
|
+
/** Used to map Latin Unicode letters to basic Latin letters. */
|
|
3
3
|
const deburredLettersMap = {
|
|
4
4
|
// Latin-1 Supplement block.
|
|
5
5
|
'\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
|
|
@@ -59,11 +59,17 @@ const deburredLettersMap = {
|
|
|
59
59
|
export function deburrLetter(key) {
|
|
60
60
|
return deburredLettersMap[key];
|
|
61
61
|
}
|
|
62
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Used to match Latin Unicode letters (excluding mathematical operators).
|
|
64
|
+
*/
|
|
63
65
|
const reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
|
|
64
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Used to compose unicode character classes.
|
|
68
|
+
*/
|
|
65
69
|
const rsComboMarksRange = "\\u0300-\\u036f\\ufe20-\\ufe23", rsComboSymbolsRange = "\\u20d0-\\u20f0";
|
|
66
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Used to compose unicode capture groups.
|
|
72
|
+
*/
|
|
67
73
|
const rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]";
|
|
68
74
|
/**
|
|
69
75
|
* Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
|
|
@@ -71,7 +77,7 @@ const rsCombo = "[" + rsComboMarksRange + rsComboSymbolsRange + "]";
|
|
|
71
77
|
*/
|
|
72
78
|
const reComboMark = RegExp(rsCombo, "g");
|
|
73
79
|
/**
|
|
74
|
-
*
|
|
80
|
+
* Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
|
|
75
81
|
*/
|
|
76
82
|
export function deburr(text) {
|
|
77
83
|
return text.replace(reLatin, deburrLetter).replace(reComboMark, "");
|
package/dist/decode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { decompress } from "lzma1";
|
|
2
|
-
import
|
|
2
|
+
import * as base32hex from "./base32hex.js";
|
|
3
3
|
import { CurrencyCode, PaymentOptions, Version, } from "./index.js";
|
|
4
4
|
function cleanUndefined(obj) {
|
|
5
5
|
Object.keys(obj).forEach((key) => {
|
|
@@ -133,7 +133,7 @@ export function deserialize(qr) {
|
|
|
133
133
|
* the input header array into four nibbles representing the bysquare header
|
|
134
134
|
* values.
|
|
135
135
|
*
|
|
136
|
-
* @param header 2-bytes
|
|
136
|
+
* @param header 2-bytes size
|
|
137
137
|
*/
|
|
138
138
|
function bysquareHeaderDecoder(header) {
|
|
139
139
|
const bytes = (header[0] << 8) | header[1];
|
|
@@ -164,16 +164,11 @@ export const parse = decode;
|
|
|
164
164
|
* @see 3.16.
|
|
165
165
|
*/
|
|
166
166
|
export function decode(qr) {
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
bytes = base32hex.parse(qr, { loose: true });
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
throw new DecodeError(error, "Unable to decode QR string base32hex encoding");
|
|
173
|
-
}
|
|
167
|
+
const bytes = base32hex.decode(qr);
|
|
174
168
|
const bysquareHeader = bytes.slice(0, 2);
|
|
175
|
-
|
|
176
|
-
|
|
169
|
+
const decodedBysquareHeader = bysquareHeaderDecoder(bysquareHeader);
|
|
170
|
+
if ((decodedBysquareHeader.version > Version["1.1.0"])) {
|
|
171
|
+
throw new Error(`Unsupported Bysquare version '${decodedBysquareHeader.version}' in header detected. Only '0' and '1' values are supported`);
|
|
177
172
|
}
|
|
178
173
|
/**
|
|
179
174
|
* The process of decompressing data requires the addition of an LZMA header
|
|
@@ -223,17 +218,17 @@ export function decode(qr) {
|
|
|
223
218
|
* not very reliable, there is room for improvement for the future.
|
|
224
219
|
*/
|
|
225
220
|
export function detect(qr) {
|
|
226
|
-
let
|
|
221
|
+
let decoded;
|
|
227
222
|
try {
|
|
228
|
-
|
|
223
|
+
decoded = base32hex.decode(qr, true);
|
|
229
224
|
}
|
|
230
|
-
catch {
|
|
225
|
+
catch (error) {
|
|
231
226
|
return false;
|
|
232
227
|
}
|
|
233
|
-
if (
|
|
228
|
+
if (decoded.byteLength < 2) {
|
|
234
229
|
return false;
|
|
235
230
|
}
|
|
236
|
-
const bysquareHeader =
|
|
231
|
+
const bysquareHeader = decoded.subarray(0, 2);
|
|
237
232
|
const header = bysquareHeaderDecoder(bysquareHeader);
|
|
238
233
|
const isValid = [
|
|
239
234
|
header.bysquareType,
|
package/dist/encode.d.ts
CHANGED
|
@@ -47,7 +47,13 @@ type Options = {
|
|
|
47
47
|
*
|
|
48
48
|
* @default true
|
|
49
49
|
*/
|
|
50
|
-
deburr
|
|
50
|
+
deburr?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* If true, validates the data model before encoding it.
|
|
53
|
+
*
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
validate?: boolean;
|
|
51
57
|
};
|
|
52
58
|
/** @deprecated */
|
|
53
59
|
export declare const generate: typeof encode;
|
package/dist/encode.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import crc32 from "crc-32";
|
|
2
1
|
import { compress } from "lzma1";
|
|
3
|
-
import
|
|
2
|
+
import * as base32hex from "./base32hex.js";
|
|
3
|
+
import { crc32 } from "./crc32.js";
|
|
4
4
|
import { deburr } from "./deburr.js";
|
|
5
|
-
import { PaymentOptions, } from "./types.js";
|
|
5
|
+
import { PaymentOptions, Version, } from "./types.js";
|
|
6
|
+
import { validateDataModel } from "./validations.js";
|
|
7
|
+
const MAX_COMPRESSED_SIZE = 131_072; // 2^17
|
|
6
8
|
/**
|
|
7
9
|
* Returns a 2 byte buffer that represents the header of the bysquare
|
|
8
10
|
* specification
|
|
@@ -24,9 +26,17 @@ header = [
|
|
|
24
26
|
0x00, 0x00,
|
|
25
27
|
0x00, 0x00
|
|
26
28
|
]) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
if (header[0] < 0 || header[0] > 15) {
|
|
30
|
+
throw new Error(`Invalid BySquareType value '${header[0]}' in header, valid range <0,15>`);
|
|
31
|
+
}
|
|
32
|
+
if (header[1] < 0 || header[1] > 15) {
|
|
33
|
+
throw new Error(`Invalid Version value '${header[1]}' in header, valid range <0,15>`);
|
|
34
|
+
}
|
|
35
|
+
if (header[2] < 0 || header[2] > 15) {
|
|
36
|
+
throw new Error(`Invalid DocumentType value '${header[2]}' in header, valid range <0,15>`);
|
|
37
|
+
}
|
|
38
|
+
if (header[3] < 0 || header[3] > 15) {
|
|
39
|
+
throw new Error(`Invalid Reserved value '${header[3]}' in header, valid range <0,15>`);
|
|
30
40
|
}
|
|
31
41
|
const [bySquareType, version, documentType, reserved,] = header;
|
|
32
42
|
// Combine 4-nibbles to 2-bytes
|
|
@@ -41,8 +51,8 @@ header = [
|
|
|
41
51
|
* combination with CRC32 in bytes.
|
|
42
52
|
*/
|
|
43
53
|
export function headerDataLength(length) {
|
|
44
|
-
if (length >=
|
|
45
|
-
throw new Error(
|
|
54
|
+
if (length >= MAX_COMPRESSED_SIZE) {
|
|
55
|
+
throw new Error(`Data size ${length} exceeds limit of ${MAX_COMPRESSED_SIZE} bytes`);
|
|
46
56
|
}
|
|
47
57
|
const header = new ArrayBuffer(2);
|
|
48
58
|
new DataView(header).setUint16(0, length, true);
|
|
@@ -55,7 +65,7 @@ export function headerDataLength(length) {
|
|
|
55
65
|
*/
|
|
56
66
|
export function addChecksum(serialized) {
|
|
57
67
|
const checksum = new ArrayBuffer(4);
|
|
58
|
-
new DataView(checksum).setUint32(0, crc32
|
|
68
|
+
new DataView(checksum).setUint32(0, crc32(serialized), true);
|
|
59
69
|
const byteArray = new TextEncoder().encode(serialized);
|
|
60
70
|
return Uint8Array.from([
|
|
61
71
|
...new Uint8Array(checksum),
|
|
@@ -142,25 +152,26 @@ export const generate = encode;
|
|
|
142
152
|
/**
|
|
143
153
|
* Generate QR string ready for encoding into text QR code
|
|
144
154
|
*/
|
|
145
|
-
export function encode(model, options
|
|
146
|
-
|
|
155
|
+
export function encode(model, options) {
|
|
156
|
+
const { deburr = true, validate = true } = options ?? {};
|
|
157
|
+
if (deburr) {
|
|
147
158
|
removeDiacritics(model);
|
|
148
159
|
}
|
|
160
|
+
if (validate) {
|
|
161
|
+
validateDataModel(model);
|
|
162
|
+
}
|
|
149
163
|
const payload = serialize(model);
|
|
150
164
|
const withChecksum = addChecksum(payload);
|
|
151
165
|
const compressed = Uint8Array.from(compress(withChecksum));
|
|
152
166
|
const _lzmaHeader = Uint8Array.from(compressed.subarray(0, 13));
|
|
153
167
|
const lzmaBody = Uint8Array.from(compressed.subarray(13));
|
|
154
168
|
const output = Uint8Array.from([
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
// version is specified like TatraBanka
|
|
169
|
+
// NOTE: Newer version 1.1.0 is not supported by all apps (e.g., TatraBanka).
|
|
170
|
+
// We recommend using version "1.0.0" for better compatibility.
|
|
158
171
|
// ...headerBysquare([0x00, Version["1.1.0"], 0x00, 0x00]),
|
|
159
|
-
...headerBysquare([0x00,
|
|
172
|
+
...headerBysquare([0x00, Version["1.0.0"], 0x00, 0x00]),
|
|
160
173
|
...headerDataLength(withChecksum.byteLength),
|
|
161
174
|
...lzmaBody,
|
|
162
175
|
]);
|
|
163
|
-
return base32hex.
|
|
164
|
-
pad: false,
|
|
165
|
-
});
|
|
176
|
+
return base32hex.encode(output, false);
|
|
166
177
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -6,20 +6,22 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare enum Version {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Created this document from original by square specifications.
|
|
10
|
+
*
|
|
11
|
+
* **Released Date:** 2013-02-22
|
|
11
12
|
*/
|
|
12
13
|
"1.0.0" = 0,
|
|
13
14
|
/**
|
|
14
|
-
* 2015-06-24
|
|
15
15
|
* Added fields for beneficiary name and address
|
|
16
|
+
*
|
|
17
|
+
* **Released Date:** 2015-06-24
|
|
16
18
|
*/
|
|
17
19
|
"1.1.0" = 1
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Kalendárny mesiac.
|
|
21
23
|
*/
|
|
22
|
-
export declare enum
|
|
24
|
+
export declare enum Month {
|
|
23
25
|
January = 1,
|
|
24
26
|
February = 2,
|
|
25
27
|
March = 4,
|
|
@@ -60,13 +62,22 @@ export type Day = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 1
|
|
|
60
62
|
* Možnosti platby sa dajú kombinovať. Oddeľujú sa medzerou a treba uviesť vždy
|
|
61
63
|
* aspoň jednu z možností:
|
|
62
64
|
*
|
|
63
|
-
* -
|
|
64
|
-
* -
|
|
65
|
-
* -
|
|
65
|
+
* - `PaymentOrder`: platobný príkaz
|
|
66
|
+
* - `StandingOrder`: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
|
|
67
|
+
* - `DirectDebit`: inkaso, údaje sa vyplnia do DirectDebitExt
|
|
66
68
|
*/
|
|
67
69
|
export declare enum PaymentOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Platobný príkaz
|
|
72
|
+
*/
|
|
68
73
|
PaymentOrder = 1,
|
|
74
|
+
/**
|
|
75
|
+
* Trvalý príkaz, údaje sa vyplnia do StandingOrderExt
|
|
76
|
+
*/
|
|
69
77
|
StandingOrder = 2,
|
|
78
|
+
/**
|
|
79
|
+
* Inkaso, údaje sa vyplnia do DirectDebitExt
|
|
80
|
+
*/
|
|
70
81
|
DirectDebit = 4
|
|
71
82
|
}
|
|
72
83
|
/**
|
|
@@ -74,121 +85,140 @@ export declare enum PaymentOptions {
|
|
|
74
85
|
*/
|
|
75
86
|
export type BankAccount = {
|
|
76
87
|
/**
|
|
88
|
+
* Medzinárodné číslo bankového účtu vo formáte IBAN. Príklad:
|
|
89
|
+
*
|
|
77
90
|
* Maximálna dĺžka 34
|
|
78
|
-
* Pattern: [A-Z]{2}[0-9]{2}[A-Z0-9]{0,30}
|
|
79
91
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
92
|
+
* Pattern: `[A-Z]{2}[0-9]{2}[A-Z0-9]{0,30}`
|
|
93
|
+
*
|
|
94
|
+
* @example `"SK8209000000000011424060"`
|
|
83
95
|
*/
|
|
84
96
|
iban: string;
|
|
85
97
|
/**
|
|
86
|
-
* Formát ISO 9362 (swift) 8 or 11 characters long
|
|
87
|
-
* Pattern: [A-Z]{4}[A-Z]{2}[A-Z\d]{2}([A-Z\d]{3})?
|
|
88
|
-
*
|
|
89
98
|
* Medzinárodný bankový identifikačný kód (z ang. Bank Identification Code).
|
|
90
|
-
*
|
|
99
|
+
*
|
|
100
|
+
* Formát [ISO 9362](https://en.wikipedia.org/wiki/ISO_9362) (swift) 8 or 11 characters long
|
|
101
|
+
*
|
|
102
|
+
* Pattern: `[A-Z]{4}[A-Z]{2}[A-Z\d]{2}([A-Z\d]{3})?`
|
|
103
|
+
*
|
|
104
|
+
* @example "TATRSKBX"
|
|
91
105
|
*/
|
|
92
106
|
bic?: string;
|
|
93
107
|
};
|
|
94
108
|
/**
|
|
95
109
|
* Inksaná schéma. Uvádza ja jedna z možností:
|
|
96
110
|
*
|
|
97
|
-
* SEPA - Inkaso zodpovedá schéme
|
|
98
|
-
* SEPA. other - iné
|
|
111
|
+
* - SEPA - Inkaso zodpovedá schéme
|
|
112
|
+
* - SEPA. other - iné
|
|
99
113
|
*/
|
|
100
114
|
export declare enum DirectDebitScheme {
|
|
115
|
+
/**
|
|
116
|
+
* other - iné
|
|
117
|
+
*/
|
|
101
118
|
Other = 0,
|
|
119
|
+
/**
|
|
120
|
+
* SEPA - Inkaso zodpovedá schéme
|
|
121
|
+
*/
|
|
102
122
|
Sepa = 1
|
|
103
123
|
}
|
|
104
124
|
/**
|
|
105
|
-
* Maximálna dĺžka 1
|
|
106
|
-
*
|
|
107
125
|
* Typ inkasa. Uvádza ja jedna z možností:
|
|
108
126
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
127
|
+
* Maximálna dĺžka 1
|
|
128
|
+
*
|
|
129
|
+
* - one-off - jednorázové inkaso
|
|
130
|
+
* - recurrent - opakované inkaso
|
|
111
131
|
*/
|
|
112
132
|
export declare enum DirectDebitType {
|
|
133
|
+
/**
|
|
134
|
+
* Jednorázové inkaso
|
|
135
|
+
*/
|
|
113
136
|
OneOff = 0,
|
|
137
|
+
/**
|
|
138
|
+
* Opakované inkaso
|
|
139
|
+
*/
|
|
114
140
|
Recurrent = 1
|
|
115
141
|
}
|
|
116
142
|
export type Beneficiary = {
|
|
117
143
|
/**
|
|
118
|
-
* Maximálna dĺžka 70
|
|
119
|
-
*
|
|
120
144
|
* Rozšírenie o meno príjemcu
|
|
145
|
+
*
|
|
146
|
+
* Maximálna dĺžka 70
|
|
121
147
|
*/
|
|
122
148
|
name?: string;
|
|
123
149
|
/**
|
|
124
|
-
* Maximálna dĺžka 70
|
|
125
|
-
*
|
|
126
150
|
* Rozšírenie o adresu príjemcu
|
|
151
|
+
*
|
|
152
|
+
* Maximálna dĺžka 70
|
|
127
153
|
*/
|
|
128
154
|
street?: string;
|
|
129
155
|
/**
|
|
130
|
-
* Maximálna dĺžka 70
|
|
131
|
-
*
|
|
132
156
|
* Rozšírenie o adresu príjemcu (druhý riadok)
|
|
157
|
+
*
|
|
158
|
+
* Maximálna dĺžka 70
|
|
133
159
|
*/
|
|
134
160
|
city?: string;
|
|
135
161
|
};
|
|
136
162
|
export type SimplePayment = {
|
|
137
163
|
/**
|
|
138
|
-
* Maximálna dĺžka 15
|
|
139
|
-
*
|
|
140
164
|
* Čiastka platby. Povolené sú len kladné hodnoty. Desatinná čast je
|
|
141
165
|
* oddelená bodkou. Môže ostať nevyplnené, napríklad pre dobrovoľný
|
|
142
|
-
* príspevok (donations).
|
|
143
|
-
*
|
|
144
|
-
*
|
|
166
|
+
* príspevok (donations).
|
|
167
|
+
*
|
|
168
|
+
* Príklad: Tisíc sa uvádza ako `1000`. Jedna celá
|
|
169
|
+
* deväťdesiatdeväť sa uvádza ako `1.99`. Desať celých peťdesiat sa uvádza
|
|
170
|
+
* ako `10.5`. Nula celá nula osem sa uvádza ako `0.08`.
|
|
171
|
+
*
|
|
172
|
+
* Maximálna dĺžka 15
|
|
145
173
|
*/
|
|
146
174
|
amount?: number;
|
|
147
175
|
/**
|
|
176
|
+
* Mena v [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) formáte (3 písmená).
|
|
177
|
+
*
|
|
148
178
|
* Pattern: [A-Z]{3}
|
|
149
179
|
*
|
|
150
|
-
*
|
|
180
|
+
* @example "EUR"
|
|
151
181
|
*/
|
|
152
182
|
currencyCode: string | CurrencyCode;
|
|
153
183
|
/**
|
|
154
|
-
*
|
|
184
|
+
* Dátum splatnosti vo formáte [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) `"RRRR-MM-DD"`.
|
|
185
|
+
* Vprípade trvalého príkazu označuje dátum prvej platby.
|
|
155
186
|
*
|
|
156
|
-
*
|
|
157
|
-
* prípade trvalého príkazu označuje dátum prvej platby.
|
|
187
|
+
* Formát `YYYY-MM-DD`
|
|
158
188
|
*/
|
|
159
189
|
paymentDueDate?: string;
|
|
160
190
|
/**
|
|
191
|
+
* Variabilný symbol je maximálne 10 miestne číslo.
|
|
192
|
+
*
|
|
161
193
|
* Maximálna dĺžka 10
|
|
162
194
|
* Pattern: [0-9]{0,10}
|
|
163
|
-
*
|
|
164
|
-
* Variabilný symbol je maximálne 10 miestne číslo. Nepovinný údaj.
|
|
165
195
|
*/
|
|
166
196
|
variableSymbol?: string;
|
|
167
197
|
/**
|
|
198
|
+
* Konštantný symbol je 4 miestne identifikačné číslo.
|
|
199
|
+
*
|
|
168
200
|
* Maximálna dĺžka 4
|
|
169
201
|
* Pattern: [0-9]{0,4}
|
|
170
|
-
*
|
|
171
|
-
* Konštantný symbol je 4 miestne identifikačné číslo. Nepovinný údaj.
|
|
172
202
|
*/
|
|
173
203
|
constantSymbol?: string;
|
|
174
204
|
/**
|
|
205
|
+
* Špecifický symbol je maximálne 10 miestne číslo.
|
|
206
|
+
*
|
|
175
207
|
* Maximálna dĺžka 10
|
|
176
208
|
* Pattern: [0-9]{0,10}
|
|
177
|
-
*
|
|
178
|
-
* Špecifický symbol je maximálne 10 miestne číslo. Nepovinný údaj.
|
|
179
209
|
*/
|
|
180
210
|
specificSymbol?: string;
|
|
181
211
|
/**
|
|
182
|
-
* Maximálna dĺžka 35
|
|
183
|
-
*
|
|
184
212
|
* Referenčná informácia prijímateľa podľa SEPA.
|
|
213
|
+
*
|
|
214
|
+
* Maximálna dĺžka 35
|
|
185
215
|
*/
|
|
186
216
|
originatorsReferenceInformation?: string;
|
|
187
217
|
/**
|
|
188
|
-
* Maximálna dĺžka 140
|
|
189
|
-
*
|
|
190
218
|
* Správa pre prijímateľa. Údaje o platbe, na základe ktorých príjemca bude
|
|
191
|
-
* môcť platbu identifikovať.
|
|
219
|
+
* môcť platbu identifikovať.
|
|
220
|
+
*
|
|
221
|
+
* Maximálna dĺžka 140
|
|
192
222
|
*/
|
|
193
223
|
paymentNote?: string;
|
|
194
224
|
/**
|
|
@@ -214,7 +244,7 @@ export type StandingOrder = SimplePayment & {
|
|
|
214
244
|
/**
|
|
215
245
|
* Medzerou oddelený zoznam mesiacov, v ktoré sa má platba uskutočniť.
|
|
216
246
|
*/
|
|
217
|
-
month?:
|
|
247
|
+
month?: Month;
|
|
218
248
|
/**
|
|
219
249
|
* Opakovanie (periodicita) trvalého príkazu.
|
|
220
250
|
*/
|
|
@@ -222,7 +252,7 @@ export type StandingOrder = SimplePayment & {
|
|
|
222
252
|
/**
|
|
223
253
|
* Dátum poslednej platby v trvalom príkaze.
|
|
224
254
|
*
|
|
225
|
-
* Formát YYYYMMDD
|
|
255
|
+
* Formát `YYYYMMDD`
|
|
226
256
|
*/
|
|
227
257
|
lastDate?: string;
|
|
228
258
|
};
|
|
@@ -234,34 +264,34 @@ export type DirectDebit = SimplePayment & {
|
|
|
234
264
|
directDebitScheme?: DirectDebitScheme;
|
|
235
265
|
directDebitType?: DirectDebitType;
|
|
236
266
|
/**
|
|
237
|
-
* Maximálna dĺžka 35
|
|
238
|
-
*
|
|
239
267
|
* Identifikácia mandátu medzi veriteľom a dlžníkom podľa SEPA.
|
|
268
|
+
*
|
|
269
|
+
* Maximálna dĺžka 35
|
|
240
270
|
*/
|
|
241
271
|
mandateId?: string;
|
|
242
272
|
/**
|
|
243
|
-
* Maximálna dĺžka 35
|
|
244
|
-
*
|
|
245
273
|
* Identifikácia veriteľa podľa SEPA.
|
|
274
|
+
*
|
|
275
|
+
* Maximálna dĺžka 35
|
|
246
276
|
*/
|
|
247
277
|
creditorId?: string;
|
|
248
278
|
/**
|
|
249
|
-
* Maximálna dĺžka 35
|
|
250
|
-
*
|
|
251
279
|
* Identifikácia zmluvy medzi veriteľom a dlžníkom podľa SEPA.
|
|
280
|
+
*
|
|
281
|
+
* Maximálna dĺžka 35
|
|
252
282
|
*/
|
|
253
283
|
contractId?: string;
|
|
254
284
|
/**
|
|
255
|
-
* Maximálna dĺžka 15
|
|
256
|
-
*
|
|
257
285
|
* Maximálna čiastka inkasa.
|
|
286
|
+
*
|
|
287
|
+
* Maximálna dĺžka 15
|
|
258
288
|
*/
|
|
259
289
|
maxAmount?: number;
|
|
260
290
|
/**
|
|
261
|
-
* Maximálna dĺžka 8
|
|
262
|
-
* Formát YYYYMMDD
|
|
263
|
-
*
|
|
264
291
|
* Dátum platnosti inkasa. Platnosť inkasa zaníka dňom tohto dátumu.
|
|
292
|
+
*
|
|
293
|
+
* Maximálna dĺžka 8
|
|
294
|
+
* Formát `YYYYMMDD`
|
|
265
295
|
*/
|
|
266
296
|
validTillDate?: string;
|
|
267
297
|
};
|
|
@@ -271,10 +301,10 @@ export type DirectDebit = SimplePayment & {
|
|
|
271
301
|
export type Payment = PaymentOrder | StandingOrder | DirectDebit;
|
|
272
302
|
export type DataModel = {
|
|
273
303
|
/**
|
|
274
|
-
* Maximálna dĺžka 10
|
|
275
|
-
*
|
|
276
304
|
* Číslo faktúry v prípade, že údaje sú súčasťou faktúry, alebo
|
|
277
305
|
* identifikátor pre intérne potreby vystavovateľa.
|
|
306
|
+
*
|
|
307
|
+
* Maximálna dĺžka 10
|
|
278
308
|
*/
|
|
279
309
|
invoiceId?: string;
|
|
280
310
|
/**
|
|
@@ -284,7 +314,7 @@ export type DataModel = {
|
|
|
284
314
|
payments: Payment[];
|
|
285
315
|
};
|
|
286
316
|
/**
|
|
287
|
-
* ISO-4217
|
|
317
|
+
* [ISO-4217](https://en.wikipedia.org/wiki/ISO_4217)
|
|
288
318
|
*/
|
|
289
319
|
export declare enum CurrencyCode {
|
|
290
320
|
AED = "AED",
|
package/dist/types.js
CHANGED
|
@@ -7,34 +7,36 @@
|
|
|
7
7
|
export var Version;
|
|
8
8
|
(function (Version) {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Created this document from original by square specifications.
|
|
11
|
+
*
|
|
12
|
+
* **Released Date:** 2013-02-22
|
|
12
13
|
*/
|
|
13
14
|
Version[Version["1.0.0"] = 0] = "1.0.0";
|
|
14
15
|
/**
|
|
15
|
-
* 2015-06-24
|
|
16
16
|
* Added fields for beneficiary name and address
|
|
17
|
+
*
|
|
18
|
+
* **Released Date:** 2015-06-24
|
|
17
19
|
*/
|
|
18
20
|
Version[Version["1.1.0"] = 1] = "1.1.0";
|
|
19
21
|
})(Version || (Version = {}));
|
|
20
22
|
/**
|
|
21
23
|
* Kalendárny mesiac.
|
|
22
24
|
*/
|
|
23
|
-
export var
|
|
24
|
-
(function (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
})(
|
|
25
|
+
export var Month;
|
|
26
|
+
(function (Month) {
|
|
27
|
+
Month[Month["January"] = 1] = "January";
|
|
28
|
+
Month[Month["February"] = 2] = "February";
|
|
29
|
+
Month[Month["March"] = 4] = "March";
|
|
30
|
+
Month[Month["April"] = 8] = "April";
|
|
31
|
+
Month[Month["May"] = 16] = "May";
|
|
32
|
+
Month[Month["June"] = 32] = "June";
|
|
33
|
+
Month[Month["July"] = 64] = "July";
|
|
34
|
+
Month[Month["August"] = 128] = "August";
|
|
35
|
+
Month[Month["September"] = 256] = "September";
|
|
36
|
+
Month[Month["October"] = 512] = "October";
|
|
37
|
+
Month[Month["November"] = 1024] = "November";
|
|
38
|
+
Month[Month["December"] = 2048] = "December";
|
|
39
|
+
})(Month || (Month = {}));
|
|
38
40
|
/**
|
|
39
41
|
* Deň platby vyplývajúci z opakovania (Periodicity). Deň v mesiaci je číslo
|
|
40
42
|
* medzi 1 a 31. Deň v týždni je číslo medzi 1 a 7 (1 = pondelok, 2=utorok, …, 7
|
|
@@ -55,42 +57,63 @@ export var Periodicity;
|
|
|
55
57
|
* Možnosti platby sa dajú kombinovať. Oddeľujú sa medzerou a treba uviesť vždy
|
|
56
58
|
* aspoň jednu z možností:
|
|
57
59
|
*
|
|
58
|
-
* -
|
|
59
|
-
* -
|
|
60
|
-
* -
|
|
60
|
+
* - `PaymentOrder`: platobný príkaz
|
|
61
|
+
* - `StandingOrder`: trvalý príkaz, údaje sa vyplnia do StandingOrderExt
|
|
62
|
+
* - `DirectDebit`: inkaso, údaje sa vyplnia do DirectDebitExt
|
|
61
63
|
*/
|
|
62
64
|
export var PaymentOptions;
|
|
63
65
|
(function (PaymentOptions) {
|
|
66
|
+
/**
|
|
67
|
+
* Platobný príkaz
|
|
68
|
+
*/
|
|
64
69
|
PaymentOptions[PaymentOptions["PaymentOrder"] = 1] = "PaymentOrder";
|
|
70
|
+
/**
|
|
71
|
+
* Trvalý príkaz, údaje sa vyplnia do StandingOrderExt
|
|
72
|
+
*/
|
|
65
73
|
PaymentOptions[PaymentOptions["StandingOrder"] = 2] = "StandingOrder";
|
|
74
|
+
/**
|
|
75
|
+
* Inkaso, údaje sa vyplnia do DirectDebitExt
|
|
76
|
+
*/
|
|
66
77
|
PaymentOptions[PaymentOptions["DirectDebit"] = 4] = "DirectDebit";
|
|
67
78
|
})(PaymentOptions || (PaymentOptions = {}));
|
|
68
79
|
/**
|
|
69
80
|
* Inksaná schéma. Uvádza ja jedna z možností:
|
|
70
81
|
*
|
|
71
|
-
* SEPA - Inkaso zodpovedá schéme
|
|
72
|
-
* SEPA. other - iné
|
|
82
|
+
* - SEPA - Inkaso zodpovedá schéme
|
|
83
|
+
* - SEPA. other - iné
|
|
73
84
|
*/
|
|
74
85
|
export var DirectDebitScheme;
|
|
75
86
|
(function (DirectDebitScheme) {
|
|
87
|
+
/**
|
|
88
|
+
* other - iné
|
|
89
|
+
*/
|
|
76
90
|
DirectDebitScheme[DirectDebitScheme["Other"] = 0] = "Other";
|
|
91
|
+
/**
|
|
92
|
+
* SEPA - Inkaso zodpovedá schéme
|
|
93
|
+
*/
|
|
77
94
|
DirectDebitScheme[DirectDebitScheme["Sepa"] = 1] = "Sepa";
|
|
78
95
|
})(DirectDebitScheme || (DirectDebitScheme = {}));
|
|
79
96
|
/**
|
|
80
|
-
* Maximálna dĺžka 1
|
|
81
|
-
*
|
|
82
97
|
* Typ inkasa. Uvádza ja jedna z možností:
|
|
83
98
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
99
|
+
* Maximálna dĺžka 1
|
|
100
|
+
*
|
|
101
|
+
* - one-off - jednorázové inkaso
|
|
102
|
+
* - recurrent - opakované inkaso
|
|
86
103
|
*/
|
|
87
104
|
export var DirectDebitType;
|
|
88
105
|
(function (DirectDebitType) {
|
|
106
|
+
/**
|
|
107
|
+
* Jednorázové inkaso
|
|
108
|
+
*/
|
|
89
109
|
DirectDebitType[DirectDebitType["OneOff"] = 0] = "OneOff";
|
|
110
|
+
/**
|
|
111
|
+
* Opakované inkaso
|
|
112
|
+
*/
|
|
90
113
|
DirectDebitType[DirectDebitType["Recurrent"] = 1] = "Recurrent";
|
|
91
114
|
})(DirectDebitType || (DirectDebitType = {}));
|
|
92
115
|
/**
|
|
93
|
-
* ISO-4217
|
|
116
|
+
* [ISO-4217](https://en.wikipedia.org/wiki/ISO_4217)
|
|
94
117
|
*/
|
|
95
118
|
export var CurrencyCode;
|
|
96
119
|
(function (CurrencyCode) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BankAccount, DataModel, SimplePayment } from "./types.js";
|
|
2
|
+
export declare enum ValidationErrorMessage {
|
|
3
|
+
IBAN = "Invalid IBAN. Make sure ISO 13616 format is used.",
|
|
4
|
+
BIC = "Invalid BIC. Make sure ISO 9362 format is used.",
|
|
5
|
+
CurrencyCode = "Invalid currency code. Make sure ISO 4217 format is used.",
|
|
6
|
+
Date = "Invalid date. Make sure ISO 8601 format is used."
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* This error will be thrown in case of a validation issue. It provides message with error description and specific path to issue in dataModel object.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ValidationError extends Error {
|
|
12
|
+
name: string;
|
|
13
|
+
path: string;
|
|
14
|
+
/**
|
|
15
|
+
* @param message - explains, what is wrong on the specific field
|
|
16
|
+
* @param path - navigates to the specific field in DataModel, where error occurred
|
|
17
|
+
*/
|
|
18
|
+
constructor(message: ValidationErrorMessage, path: string);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* validates bankAccount fields:
|
|
22
|
+
* - iban (ISO 13616)
|
|
23
|
+
* - bic (ISO 9362)
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateBankAccount(bankAccount: BankAccount, path: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* validate simple payment fields:
|
|
28
|
+
* - currencyCode (ISO 4217)
|
|
29
|
+
* - paymentDueDate (ISO 8601)
|
|
30
|
+
* - bankAccounts
|
|
31
|
+
*
|
|
32
|
+
* @see validateBankAccount
|
|
33
|
+
*/
|
|
34
|
+
export declare function validateSimplePayment(simplePayment: SimplePayment, path: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Validate `payments` field of dataModel.
|
|
37
|
+
*
|
|
38
|
+
* @see validateSimplePayment
|
|
39
|
+
* @see ValidationError
|
|
40
|
+
*/
|
|
41
|
+
export declare function validateDataModel(dataModel: DataModel): DataModel;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import validator from "validator";
|
|
2
|
+
export var ValidationErrorMessage;
|
|
3
|
+
(function (ValidationErrorMessage) {
|
|
4
|
+
ValidationErrorMessage["IBAN"] = "Invalid IBAN. Make sure ISO 13616 format is used.";
|
|
5
|
+
ValidationErrorMessage["BIC"] = "Invalid BIC. Make sure ISO 9362 format is used.";
|
|
6
|
+
ValidationErrorMessage["CurrencyCode"] = "Invalid currency code. Make sure ISO 4217 format is used.";
|
|
7
|
+
ValidationErrorMessage["Date"] = "Invalid date. Make sure ISO 8601 format is used.";
|
|
8
|
+
})(ValidationErrorMessage || (ValidationErrorMessage = {}));
|
|
9
|
+
/**
|
|
10
|
+
* This error will be thrown in case of a validation issue. It provides message with error description and specific path to issue in dataModel object.
|
|
11
|
+
*/
|
|
12
|
+
export class ValidationError extends Error {
|
|
13
|
+
name = "ValidationError";
|
|
14
|
+
path;
|
|
15
|
+
/**
|
|
16
|
+
* @param message - explains, what is wrong on the specific field
|
|
17
|
+
* @param path - navigates to the specific field in DataModel, where error occurred
|
|
18
|
+
*/
|
|
19
|
+
constructor(message, path) {
|
|
20
|
+
super(String(message));
|
|
21
|
+
this.path = path;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* validates bankAccount fields:
|
|
26
|
+
* - iban (ISO 13616)
|
|
27
|
+
* - bic (ISO 9362)
|
|
28
|
+
*/
|
|
29
|
+
export function validateBankAccount(bankAccount, path) {
|
|
30
|
+
if (!validator.isIBAN(bankAccount.iban)) {
|
|
31
|
+
throw new ValidationError(ValidationErrorMessage.IBAN, `${path}.iban`);
|
|
32
|
+
}
|
|
33
|
+
if (bankAccount.bic && !validator.isBIC(bankAccount.bic)) {
|
|
34
|
+
throw new ValidationError(ValidationErrorMessage.BIC, `${path}.bic`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* validate simple payment fields:
|
|
39
|
+
* - currencyCode (ISO 4217)
|
|
40
|
+
* - paymentDueDate (ISO 8601)
|
|
41
|
+
* - bankAccounts
|
|
42
|
+
*
|
|
43
|
+
* @see validateBankAccount
|
|
44
|
+
*/
|
|
45
|
+
export function validateSimplePayment(simplePayment, path) {
|
|
46
|
+
for (const [index, bankAccount] of simplePayment.bankAccounts.entries()) {
|
|
47
|
+
validateBankAccount(bankAccount, `${path}.bankAccounts[${index}]`);
|
|
48
|
+
}
|
|
49
|
+
if (simplePayment.currencyCode && !validator.isISO4217(simplePayment.currencyCode)) {
|
|
50
|
+
throw new ValidationError(ValidationErrorMessage.CurrencyCode, `${path}.currencyCode`);
|
|
51
|
+
}
|
|
52
|
+
if (simplePayment.paymentDueDate && !validator.isDate(simplePayment.paymentDueDate)) {
|
|
53
|
+
throw new ValidationError(ValidationErrorMessage.Date, `${path}.paymentDueDate`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Validate `payments` field of dataModel.
|
|
58
|
+
*
|
|
59
|
+
* @see validateSimplePayment
|
|
60
|
+
* @see ValidationError
|
|
61
|
+
*/
|
|
62
|
+
export function validateDataModel(dataModel) {
|
|
63
|
+
for (const [index, payment] of dataModel.payments.entries()) {
|
|
64
|
+
validateSimplePayment(payment, `payments[${index}]`);
|
|
65
|
+
}
|
|
66
|
+
return dataModel;
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bysquare",
|
|
3
3
|
"description": "It's a national standard for payment QR codes adopted by Slovak Banking Association (SBA)",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.11.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"funding": "https://github.com/sponsors/xseman",
|
|
7
7
|
"homepage": "https://github.com/xseman/bysquare#readme",
|
|
@@ -20,19 +20,20 @@
|
|
|
20
20
|
"prebuild": "tsc --build --clean",
|
|
21
21
|
"build": "tsc --build",
|
|
22
22
|
"fmt": "dprint fmt",
|
|
23
|
+
"fmt:check": "dprint check",
|
|
23
24
|
"typecheck": "tsc --noEmit",
|
|
24
25
|
"version": "git checkout develop && npm test",
|
|
25
26
|
"postversion": "echo 'Now run npm run build && npm publish'",
|
|
26
|
-
"test": "TS_NODE_TRANSPILE_ONLY=true node --test --loader=ts-node/esm --no-warnings src/*.test.ts",
|
|
27
|
+
"test": "TS_NODE_TRANSPILE_ONLY=true node --test --experimental-test-coverage --loader=ts-node/esm --no-warnings src/*.test.ts",
|
|
27
28
|
"test:watch": "TS_NODE_TRANSPILE_ONLY=true node --test --watch --loader=ts-node/esm --no-warnings src/*.test.ts"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"rfc4648": "~1.5.0"
|
|
31
|
+
"lzma1": "0.0.3",
|
|
32
|
+
"validator": "^13.12.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/node": "
|
|
35
|
+
"@types/node": "^22.5.0",
|
|
36
|
+
"@types/validator": "^13.12.0",
|
|
36
37
|
"dprint": "~0.47.0",
|
|
37
38
|
"ts-node": "~10.9.0",
|
|
38
39
|
"typescript": "~5.5.0"
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
"!dist/*.test.*"
|
|
52
53
|
],
|
|
53
54
|
"engines": {
|
|
54
|
-
"node": ">=
|
|
55
|
+
"node": ">=16",
|
|
55
56
|
"npm": ">=7"
|
|
56
57
|
}
|
|
57
58
|
}
|