@keeex/utils 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +105 -0
- package/lib/array.d.ts +28 -0
- package/lib/array.js +36 -0
- package/lib/arraybuffer.d.ts +138 -0
- package/lib/arraybuffer.js +141 -0
- package/lib/async/asynctrigger.d.ts +50 -0
- package/lib/async/asynctrigger.js +108 -0
- package/lib/async/deferredpromise.d.ts +32 -0
- package/lib/async/deferredpromise.js +66 -0
- package/lib/async/keycache.d.ts +56 -0
- package/lib/async/keycache.js +103 -0
- package/lib/async/queues.d.ts +69 -0
- package/lib/async/queues.js +135 -0
- package/lib/async/timecache.d.ts +58 -0
- package/lib/async/timecache.js +118 -0
- package/lib/base58.d.ts +27 -0
- package/lib/base58.js +83 -0
- package/lib/base64.d.ts +51 -0
- package/lib/base64.js +126 -0
- package/lib/benchmark.d.ts +126 -0
- package/lib/benchmark.js +177 -0
- package/lib/bits/arraybuffer.d.ts +35 -0
- package/lib/bits/arraybuffer.js +64 -0
- package/lib/bits/base64.d.ts +35 -0
- package/lib/bits/base64.js +70 -0
- package/lib/bits/hex.d.ts +17 -0
- package/lib/bits/hex.js +30 -0
- package/lib/bits/uint8array.d.ts +28 -0
- package/lib/bits/uint8array.js +42 -0
- package/lib/bytebuffer.d.ts +27 -0
- package/lib/bytebuffer.js +29 -0
- package/lib/consts.d.ts +33 -0
- package/lib/consts.js +33 -0
- package/lib/cron/logger.d.ts +22 -0
- package/lib/cron/logger.js +31 -0
- package/lib/cron/scheduledtask.d.ts +71 -0
- package/lib/cron/scheduledtask.js +137 -0
- package/lib/cron/types.d.ts +53 -0
- package/lib/cron/types.js +31 -0
- package/lib/cron.d.ts +29 -0
- package/lib/cron.js +47 -0
- package/lib/dict.d.ts +56 -0
- package/lib/dict.js +74 -0
- package/lib/error.d.ts +25 -0
- package/lib/error.js +41 -0
- package/lib/global.d.ts +27 -0
- package/lib/global.js +53 -0
- package/lib/hex.d.ts +32 -0
- package/lib/hex.js +58 -0
- package/lib/idx.d.ts +51 -0
- package/lib/idx.js +81 -0
- package/lib/json.d.ts +57 -0
- package/lib/json.js +116 -0
- package/lib/marshalling/marshaller.d.ts +51 -0
- package/lib/marshalling/marshaller.js +155 -0
- package/lib/marshalling/unmarshaller.d.ts +53 -0
- package/lib/marshalling/unmarshaller.js +124 -0
- package/lib/marshalling/util.d.ts +25 -0
- package/lib/marshalling/util.js +25 -0
- package/lib/number.d.ts +17 -0
- package/lib/number.js +21 -0
- package/lib/path.d.ts +25 -0
- package/lib/path.js +29 -0
- package/lib/promise.d.ts +42 -0
- package/lib/promise.js +78 -0
- package/lib/starttime.d.ts +23 -0
- package/lib/starttime.js +29 -0
- package/lib/string.d.ts +65 -0
- package/lib/string.js +108 -0
- package/lib/types/array.d.ts +34 -0
- package/lib/types/array.js +64 -0
- package/lib/types/enum.d.ts +30 -0
- package/lib/types/enum.js +44 -0
- package/lib/types/predicateerror.d.ts +40 -0
- package/lib/types/predicateerror.js +107 -0
- package/lib/types/primitive.d.ts +23 -0
- package/lib/types/primitive.js +34 -0
- package/lib/types/record.d.ts +67 -0
- package/lib/types/record.js +235 -0
- package/lib/types/types.d.ts +64 -0
- package/lib/types/types.js +115 -0
- package/lib/types/utils.d.ts +18 -0
- package/lib/types/utils.js +67 -0
- package/lib/uint8array.d.ts +176 -0
- package/lib/uint8array.js +438 -0
- package/lib/units.d.ts +159 -0
- package/lib/units.js +290 -0
- package/lib/utils/buffer.d.ts +49 -0
- package/lib/utils/buffer.js +79 -0
- package/lib/utils/fourbytes.d.ts +29 -0
- package/lib/utils/fourbytes.js +45 -0
- package/package.json +1 -0
- package/web/array.d.ts +28 -0
- package/web/array.js +34 -0
- package/web/arraybuffer.d.ts +138 -0
- package/web/arraybuffer.js +141 -0
- package/web/async/asynctrigger.d.ts +50 -0
- package/web/async/asynctrigger.js +106 -0
- package/web/async/deferredpromise.d.ts +32 -0
- package/web/async/deferredpromise.js +65 -0
- package/web/async/keycache.d.ts +56 -0
- package/web/async/keycache.js +97 -0
- package/web/async/queues.d.ts +69 -0
- package/web/async/queues.js +131 -0
- package/web/async/timecache.d.ts +58 -0
- package/web/async/timecache.js +107 -0
- package/web/base58.d.ts +27 -0
- package/web/base58.js +78 -0
- package/web/base64.d.ts +51 -0
- package/web/base64.js +136 -0
- package/web/benchmark.d.ts +126 -0
- package/web/benchmark.js +183 -0
- package/web/bits/arraybuffer.d.ts +35 -0
- package/web/bits/arraybuffer.js +59 -0
- package/web/bits/base64.d.ts +35 -0
- package/web/bits/base64.js +67 -0
- package/web/bits/hex.d.ts +17 -0
- package/web/bits/hex.js +27 -0
- package/web/bits/uint8array.d.ts +28 -0
- package/web/bits/uint8array.js +41 -0
- package/web/bytebuffer.d.ts +27 -0
- package/web/bytebuffer.js +29 -0
- package/web/consts.d.ts +33 -0
- package/web/consts.js +33 -0
- package/web/cron/logger.d.ts +22 -0
- package/web/cron/logger.js +30 -0
- package/web/cron/scheduledtask.d.ts +71 -0
- package/web/cron/scheduledtask.js +136 -0
- package/web/cron/types.d.ts +53 -0
- package/web/cron/types.js +31 -0
- package/web/cron.d.ts +29 -0
- package/web/cron.js +47 -0
- package/web/dict.d.ts +56 -0
- package/web/dict.js +67 -0
- package/web/error.d.ts +25 -0
- package/web/error.js +39 -0
- package/web/global.d.ts +27 -0
- package/web/global.js +49 -0
- package/web/hex.d.ts +32 -0
- package/web/hex.js +52 -0
- package/web/idx.d.ts +51 -0
- package/web/idx.js +76 -0
- package/web/json.d.ts +57 -0
- package/web/json.js +98 -0
- package/web/marshalling/marshaller.d.ts +51 -0
- package/web/marshalling/marshaller.js +150 -0
- package/web/marshalling/unmarshaller.d.ts +53 -0
- package/web/marshalling/unmarshaller.js +115 -0
- package/web/marshalling/util.d.ts +25 -0
- package/web/marshalling/util.js +25 -0
- package/web/number.d.ts +17 -0
- package/web/number.js +21 -0
- package/web/path.d.ts +25 -0
- package/web/path.js +26 -0
- package/web/promise.d.ts +42 -0
- package/web/promise.js +74 -0
- package/web/starttime.d.ts +23 -0
- package/web/starttime.js +29 -0
- package/web/string.d.ts +65 -0
- package/web/string.js +101 -0
- package/web/types/array.d.ts +34 -0
- package/web/types/array.js +63 -0
- package/web/types/enum.d.ts +30 -0
- package/web/types/enum.js +40 -0
- package/web/types/predicateerror.d.ts +40 -0
- package/web/types/predicateerror.js +128 -0
- package/web/types/primitive.d.ts +23 -0
- package/web/types/primitive.js +33 -0
- package/web/types/record.d.ts +67 -0
- package/web/types/record.js +213 -0
- package/web/types/types.d.ts +64 -0
- package/web/types/types.js +123 -0
- package/web/types/utils.d.ts +18 -0
- package/web/types/utils.js +30 -0
- package/web/uint8array.d.ts +176 -0
- package/web/uint8array.js +412 -0
- package/web/units.d.ts +159 -0
- package/web/units.js +312 -0
- package/web/utils/buffer.d.ts +49 -0
- package/web/utils/buffer.js +76 -0
- package/web/utils/fourbytes.d.ts +29 -0
- package/web/utils/fourbytes.js +45 -0
package/lib/base58.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-magic-numbers */
|
|
17
|
+
// Source was tracked back to:
|
|
18
|
+
// https://gist.github.com/diafygi/90a3e80ca1c2793220e5/
|
|
19
|
+
// License at the time of writing is "DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE"
|
|
20
|
+
// which I think allows cleaning and reusing.
|
|
21
|
+
const MAP = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
22
|
+
const toB58 = (input, mapping) => {
|
|
23
|
+
const b58Digits = [];
|
|
24
|
+
let result = "";
|
|
25
|
+
let b58DigitsIndex = 0;
|
|
26
|
+
const len = input.byteLength;
|
|
27
|
+
for (let inputIndex = 0; inputIndex < len; ++inputIndex) {
|
|
28
|
+
let carryAmount = input[inputIndex];
|
|
29
|
+
b58DigitsIndex = 0;
|
|
30
|
+
if (!(carryAmount || result.length ^ inputIndex))
|
|
31
|
+
result += "1";
|
|
32
|
+
while (b58DigitsIndex in b58Digits || carryAmount) {
|
|
33
|
+
let pushedValue = b58Digits[b58DigitsIndex];
|
|
34
|
+
pushedValue = pushedValue ? pushedValue * 256 + carryAmount : carryAmount;
|
|
35
|
+
carryAmount = (pushedValue / 58) | 0;
|
|
36
|
+
b58Digits[b58DigitsIndex] = pushedValue % 58;
|
|
37
|
+
b58DigitsIndex++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
while (b58DigitsIndex--)
|
|
41
|
+
result += mapping[b58Digits[b58DigitsIndex]];
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
const fromB58 = (base58, mapping) => {
|
|
45
|
+
const remainder = [];
|
|
46
|
+
const resultBytes = [];
|
|
47
|
+
let remainderIndex = 0;
|
|
48
|
+
const len = base58.length;
|
|
49
|
+
for (let inputIndex = 0; inputIndex < len; ++inputIndex) {
|
|
50
|
+
let currentInput = mapping.indexOf(base58[inputIndex]);
|
|
51
|
+
remainderIndex = 0;
|
|
52
|
+
if (currentInput < 0)
|
|
53
|
+
throw new Error("Unexpected state");
|
|
54
|
+
if (!(currentInput || resultBytes.length ^ inputIndex))
|
|
55
|
+
resultBytes.push(0);
|
|
56
|
+
while (remainderIndex in remainder || currentInput) {
|
|
57
|
+
let currentValue = remainder[remainderIndex];
|
|
58
|
+
currentValue = currentValue ? currentValue * 58 + currentInput : currentInput;
|
|
59
|
+
currentInput = currentValue >> 8;
|
|
60
|
+
remainder[remainderIndex] = currentValue % 256;
|
|
61
|
+
remainderIndex++;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
while (remainderIndex--)
|
|
65
|
+
resultBytes.push(remainder[remainderIndex]);
|
|
66
|
+
return new Uint8Array(resultBytes);
|
|
67
|
+
};
|
|
68
|
+
/** @public */
|
|
69
|
+
export const encode = (data) => toB58(data, MAP);
|
|
70
|
+
/** @public */
|
|
71
|
+
export const decode = (b58) => fromB58(b58, MAP);
|
|
72
|
+
const BYTE_COUNT = 256;
|
|
73
|
+
const B58_COUNT = 58;
|
|
74
|
+
/** Compute the expected length of a base58 encoding */
|
|
75
|
+
const getBase58LengthFromBuf8 = (dataLengthInBytes) => Math.ceil((dataLengthInBytes * Math.log(BYTE_COUNT)) / Math.log(B58_COUNT));
|
|
76
|
+
/**
|
|
77
|
+
* Encode a buf8 with base58.
|
|
78
|
+
*
|
|
79
|
+
* The output is padded accordingly to always accomodate a buffer of the full length of the input.
|
|
80
|
+
*
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export const encodePad = (data) => encode(data).padStart(getBase58LengthFromBuf8(data.byteLength), "1");
|
package/lib/base64.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
/** @public */
|
|
17
|
+
export declare const buf82B64: (buffer: ArrayBuffer | Uint8Array) => string;
|
|
18
|
+
export interface ArmorB64Input {
|
|
19
|
+
buffer: ArrayBuffer | Uint8Array;
|
|
20
|
+
label: string;
|
|
21
|
+
bagAttributes?: string;
|
|
22
|
+
}
|
|
23
|
+
interface Buf2ArmorB64 {
|
|
24
|
+
(buffer: ArrayBuffer | Uint8Array, label?: string, lineWidth?: number, bagAttributes?: string): string;
|
|
25
|
+
(input: ArmorB64Input | Array<ArmorB64Input>, lineWidth?: number): string;
|
|
26
|
+
}
|
|
27
|
+
/** @public */
|
|
28
|
+
export declare const buf82ArmorB64: Buf2ArmorB64;
|
|
29
|
+
export interface ArmorBase64Data {
|
|
30
|
+
arrayBuffer: ArrayBuffer;
|
|
31
|
+
buf8: Uint8Array;
|
|
32
|
+
label: string;
|
|
33
|
+
bagAttributes?: string;
|
|
34
|
+
}
|
|
35
|
+
/** @public */
|
|
36
|
+
export declare const armorB642Buf8: (armorB64: string) => ArmorBase64Data;
|
|
37
|
+
/** @public */
|
|
38
|
+
export declare const multipleArmorB642Buf8: (armorB64: string) => Array<ArmorBase64Data>;
|
|
39
|
+
/**
|
|
40
|
+
* Return the length of the data in a b64 string.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export declare const b64Len: (data: string, strict: boolean) => number;
|
|
45
|
+
/**
|
|
46
|
+
* Return the length of the data in an armored b64 string.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export declare const armorB64Len: (armorB64: string) => number;
|
|
51
|
+
export {};
|
package/lib/base64.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { asArray } from "./array.js";
|
|
17
|
+
import { ab2b64, b642ab } from "./bits/arraybuffer.js";
|
|
18
|
+
import { b64Len as b64LenBits } from "./bits/base64.js";
|
|
19
|
+
import { getUint8Array } from "./bits/uint8array.js";
|
|
20
|
+
import { buf82b64 } from "./uint8array.js";
|
|
21
|
+
/** @public */
|
|
22
|
+
export const buf82B64 = (buffer) => buffer instanceof ArrayBuffer ? ab2b64(buffer) : buf82b64(buffer);
|
|
23
|
+
const headerBegin = "-----BEGIN ";
|
|
24
|
+
const headerEnd = "-----END ";
|
|
25
|
+
const headerSuffix = "-----";
|
|
26
|
+
const bagAttributesHeader = "Bag Attributes";
|
|
27
|
+
const singleInput2ArmorB64 = ({ buffer, label, bagAttributes }, lineWidth) => {
|
|
28
|
+
const b64Data = buf82B64(buffer);
|
|
29
|
+
const splitB64Data = lineWidth >= b64Data.length
|
|
30
|
+
? b64Data
|
|
31
|
+
: (b64Data.match(new RegExp(`(.{1,${lineWidth}})`, "gu"))?.join("\n") ?? "");
|
|
32
|
+
const header = `${headerBegin}${label}${headerSuffix}\n`;
|
|
33
|
+
const footer = `\n${headerEnd}${label}${headerSuffix}\n`;
|
|
34
|
+
const bag = bagAttributes ? `${bagAttributesHeader}\n${bagAttributes}\n` : "";
|
|
35
|
+
return `${bag}${header}${splitB64Data}${footer}`;
|
|
36
|
+
};
|
|
37
|
+
const DEFAULT_WIDTH = 64;
|
|
38
|
+
/** @public */
|
|
39
|
+
export const buf82ArmorB64 = (bufferOrInput, labelOrLineWidth, lineWidth, bagAttributes) => {
|
|
40
|
+
if (bufferOrInput instanceof ArrayBuffer || bufferOrInput instanceof Uint8Array) {
|
|
41
|
+
const label = labelOrLineWidth ?? "DATA";
|
|
42
|
+
return singleInput2ArmorB64({
|
|
43
|
+
bagAttributes: bagAttributes,
|
|
44
|
+
buffer: bufferOrInput,
|
|
45
|
+
label: label,
|
|
46
|
+
}, lineWidth ?? DEFAULT_WIDTH);
|
|
47
|
+
}
|
|
48
|
+
return asArray(bufferOrInput)
|
|
49
|
+
.map((input) => singleInput2ArmorB64(input, labelOrLineWidth ?? DEFAULT_WIDTH))
|
|
50
|
+
.join("");
|
|
51
|
+
};
|
|
52
|
+
const splitArmorB64 = (armorB64) => {
|
|
53
|
+
const res = [];
|
|
54
|
+
const lines = armorB64.split("\n");
|
|
55
|
+
const bagAttributesLines = [];
|
|
56
|
+
let inBagAttributes = false;
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
58
|
+
let base64Begin;
|
|
59
|
+
for (let i = 0; i < lines.length; ++i) {
|
|
60
|
+
const line = lines[i];
|
|
61
|
+
if (base64Begin === undefined) {
|
|
62
|
+
if (line.startsWith(headerBegin) && line.endsWith(headerSuffix)) {
|
|
63
|
+
inBagAttributes = false;
|
|
64
|
+
base64Begin = i;
|
|
65
|
+
}
|
|
66
|
+
else if (inBagAttributes) {
|
|
67
|
+
bagAttributesLines.push(line);
|
|
68
|
+
}
|
|
69
|
+
else if (line.startsWith(bagAttributesHeader)) {
|
|
70
|
+
inBagAttributes = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (line.startsWith(headerEnd) && line.endsWith(headerSuffix)) {
|
|
74
|
+
const bagAttributes = bagAttributesLines.length > 0 ? bagAttributesLines.join("\n") : undefined;
|
|
75
|
+
const headLine = lines[base64Begin];
|
|
76
|
+
const label = headLine.substring(headerBegin.length, headLine.length - headerSuffix.length);
|
|
77
|
+
const labelEnd = line.substring(headerEnd.length, line.length - headerSuffix.length);
|
|
78
|
+
if (label !== labelEnd)
|
|
79
|
+
throw new Error("Invalid end marker");
|
|
80
|
+
res.push({
|
|
81
|
+
b64: lines.slice(base64Begin + 1, i).join(""),
|
|
82
|
+
bagAttributes,
|
|
83
|
+
label: headLine.substring(headerBegin.length, headLine.length - headerSuffix.length),
|
|
84
|
+
});
|
|
85
|
+
base64Begin = undefined;
|
|
86
|
+
bagAttributesLines.length = 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (res.length === 0)
|
|
90
|
+
throw new Error("Not an armored base64 input");
|
|
91
|
+
return res;
|
|
92
|
+
};
|
|
93
|
+
/** @public */
|
|
94
|
+
export const armorB642Buf8 = (armorB64) => {
|
|
95
|
+
const [{ label, b64, bagAttributes }] = splitArmorB64(armorB64);
|
|
96
|
+
const arrayBuffer = b642ab(b64, false);
|
|
97
|
+
return {
|
|
98
|
+
arrayBuffer,
|
|
99
|
+
bagAttributes,
|
|
100
|
+
buf8: getUint8Array(arrayBuffer),
|
|
101
|
+
label,
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
/** @public */
|
|
105
|
+
export const multipleArmorB642Buf8 = (armorB64) => {
|
|
106
|
+
const splitted = splitArmorB64(armorB64);
|
|
107
|
+
return splitted.map(({ b64, label, bagAttributes }) => {
|
|
108
|
+
const arrayBuffer = b642ab(b64, false);
|
|
109
|
+
return { arrayBuffer, bagAttributes, buf8: getUint8Array(arrayBuffer), label };
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Return the length of the data in a b64 string.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export const b64Len = (data, strict) => b64LenBits(data, strict);
|
|
118
|
+
/**
|
|
119
|
+
* Return the length of the data in an armored b64 string.
|
|
120
|
+
*
|
|
121
|
+
* @public
|
|
122
|
+
*/
|
|
123
|
+
export const armorB64Len = (armorB64) => {
|
|
124
|
+
const [{ b64 }] = splitArmorB64(armorB64);
|
|
125
|
+
return b64Len(b64, false);
|
|
126
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Awaitable } from "./types/types.js";
|
|
17
|
+
export type BenchmarkFunction = (() => Promise<void>) | (() => void);
|
|
18
|
+
/**
|
|
19
|
+
* Run the provided function for given iterations and return the average runtime in ms.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export declare const benchmarkTime: (func: BenchmarkFunction, iterations: number) => Promise<number>;
|
|
24
|
+
interface DynamicBenchSettings {
|
|
25
|
+
/**
|
|
26
|
+
* Minimum number of run before we can stop.
|
|
27
|
+
*
|
|
28
|
+
* Defaults to 5.
|
|
29
|
+
*/
|
|
30
|
+
minRun?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Maximum number of run after which we stop trying to get a stable value.
|
|
33
|
+
*
|
|
34
|
+
* When either this value or maxDuration is exceeded, the benchmark gives up.
|
|
35
|
+
*
|
|
36
|
+
* Defaults to 10000.
|
|
37
|
+
*/
|
|
38
|
+
maxRun?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Maximum duration before the benchmark gives up on running new iterations.
|
|
41
|
+
*
|
|
42
|
+
* When either this value or maxDuration is exceeded, the benchmark gives up.
|
|
43
|
+
*
|
|
44
|
+
* Defaults to never.
|
|
45
|
+
*/
|
|
46
|
+
maxDurationMs?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Number of runs to keep to compute the average duration.
|
|
49
|
+
*
|
|
50
|
+
* Defaults to 5.
|
|
51
|
+
*/
|
|
52
|
+
averageWindowSize?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Number of consecutive run that must fit withing the margin of error.
|
|
55
|
+
*
|
|
56
|
+
* If the average of the last `stableRun` are closer than `maxDeltaMs` to the average duration,
|
|
57
|
+
* the benchmark completes.
|
|
58
|
+
*
|
|
59
|
+
* Defaults to 3.
|
|
60
|
+
*/
|
|
61
|
+
stableRun?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Maximum delta between the fastest and slowest iteration in the last `stableRun` runs to accept.
|
|
64
|
+
*
|
|
65
|
+
* If the average of the last `stableRun` are closer than `maxDeltaMs` to the average duration,
|
|
66
|
+
* the benchmark completes.
|
|
67
|
+
*
|
|
68
|
+
* Defaults to 10 (ms).
|
|
69
|
+
*/
|
|
70
|
+
maxDeltaMs?: number;
|
|
71
|
+
/** Set to true to output debug on the console when running the benchmark */
|
|
72
|
+
debugLog?: boolean;
|
|
73
|
+
}
|
|
74
|
+
interface DynamicBenchSimple extends DynamicBenchSettings {
|
|
75
|
+
/**
|
|
76
|
+
* Function to benchmark.
|
|
77
|
+
*
|
|
78
|
+
* Make sure this function can be called multiple time without side effect and for roughly the
|
|
79
|
+
* same duration each time.
|
|
80
|
+
*/
|
|
81
|
+
func: BenchmarkFunction;
|
|
82
|
+
}
|
|
83
|
+
interface DynamicBenchAdvanced extends DynamicBenchSettings {
|
|
84
|
+
/**
|
|
85
|
+
* Function that return the adjusted function to benchmark.
|
|
86
|
+
*
|
|
87
|
+
* This function receive a multiplier as its single parameter, starting at 1.
|
|
88
|
+
* This value is increased until either the function duration is above the given threshold or it
|
|
89
|
+
* reaches a set maximum.
|
|
90
|
+
*/
|
|
91
|
+
getFunc: (multiplier: number) => Awaitable<BenchmarkFunction>;
|
|
92
|
+
/**
|
|
93
|
+
* Maximum value for the multiplier.
|
|
94
|
+
*
|
|
95
|
+
* Defaults to 1000.
|
|
96
|
+
*/
|
|
97
|
+
maxMultiplier?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Minimum value for the function duration.
|
|
100
|
+
*
|
|
101
|
+
* Defaults to 10.
|
|
102
|
+
*/
|
|
103
|
+
minFuncDurationMs?: number;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Benchmark the duration of a function.
|
|
107
|
+
*
|
|
108
|
+
* This benchmark will run the function multiple time until it reaches a stable average.
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
export declare const dynamicBenchmark: (dynamicBenchSetup: DynamicBenchSimple) => Promise<number>;
|
|
113
|
+
interface AdvancedBenchmarkResult {
|
|
114
|
+
multiplier: number;
|
|
115
|
+
durationMs: number;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Advanced dynamic benchmark where the length of the benchmark function can be adjusted.
|
|
119
|
+
*
|
|
120
|
+
* The `multiplier` property/parameter can be increased as needed until the benchmark function reach
|
|
121
|
+
* a given minimum duration, after which it is effectively benchmarked.
|
|
122
|
+
*
|
|
123
|
+
* @public
|
|
124
|
+
*/
|
|
125
|
+
export declare const advancedDynamicBenchmark: (dynamicBenchSetup: DynamicBenchAdvanced) => Promise<AdvancedBenchmarkResult>;
|
|
126
|
+
export {};
|
package/lib/benchmark.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { createLogger } from "@keeex/log";
|
|
17
|
+
/** Return now() up to the best precision available */
|
|
18
|
+
const getNow = typeof performance.now === "function"
|
|
19
|
+
? () => performance.now()
|
|
20
|
+
: () => Date.now();
|
|
21
|
+
/**
|
|
22
|
+
* Run the provided function for given iterations and return the average runtime in ms.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export const benchmarkTime = async (func, iterations) => {
|
|
27
|
+
const usePromises = func() instanceof Promise;
|
|
28
|
+
const start = getNow();
|
|
29
|
+
if (usePromises) {
|
|
30
|
+
// eslint-disable-next-line no-await-in-loop
|
|
31
|
+
for (let i = 0; i < iterations; ++i)
|
|
32
|
+
await func();
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// We checked that the function does not return a promise above
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
37
|
+
for (let i = 0; i < iterations; ++i)
|
|
38
|
+
func();
|
|
39
|
+
}
|
|
40
|
+
const end = getNow();
|
|
41
|
+
const delta = end - start;
|
|
42
|
+
return delta / iterations;
|
|
43
|
+
};
|
|
44
|
+
/** Benchmark the function once */
|
|
45
|
+
const benchOneRun = async (usePromise, func) => {
|
|
46
|
+
if (usePromise) {
|
|
47
|
+
const before = getNow();
|
|
48
|
+
await func();
|
|
49
|
+
return getNow() - before;
|
|
50
|
+
}
|
|
51
|
+
const before = getNow();
|
|
52
|
+
func();
|
|
53
|
+
return getNow() - before;
|
|
54
|
+
};
|
|
55
|
+
const getBenchFuncInfo = async (func) => {
|
|
56
|
+
const before = getNow();
|
|
57
|
+
const testRun = func();
|
|
58
|
+
const isPromise = testRun instanceof Promise;
|
|
59
|
+
if (isPromise)
|
|
60
|
+
await testRun;
|
|
61
|
+
const firstRunDurationMs = getNow() - before;
|
|
62
|
+
return { isPromise, firstRunDurationMs };
|
|
63
|
+
};
|
|
64
|
+
/** Compute the average of an array, excluding the max and min value */
|
|
65
|
+
const computeAverage = (values) => {
|
|
66
|
+
const maxValue = Math.max(...values);
|
|
67
|
+
const minValue = Math.min(...values);
|
|
68
|
+
const filtered = [...values];
|
|
69
|
+
filtered.splice(filtered.indexOf(maxValue), 1);
|
|
70
|
+
filtered.splice(filtered.indexOf(minValue), 1);
|
|
71
|
+
return filtered.reduce((acc, cur) => acc + cur) / filtered.length;
|
|
72
|
+
};
|
|
73
|
+
const addToAverageWindow = (value, window, len) => {
|
|
74
|
+
while (window.length >= len)
|
|
75
|
+
window.shift();
|
|
76
|
+
window.push(value);
|
|
77
|
+
};
|
|
78
|
+
let logger = null;
|
|
79
|
+
const getLogger = () => {
|
|
80
|
+
logger ??= createLogger({ tag: "@keeex/js-utils:benchmark" });
|
|
81
|
+
return logger;
|
|
82
|
+
};
|
|
83
|
+
const getLog = (printDebug) => printDebug
|
|
84
|
+
? (msg) => {
|
|
85
|
+
getLogger().info(msg);
|
|
86
|
+
}
|
|
87
|
+
: // eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
88
|
+
() => { };
|
|
89
|
+
const defaultBenchConfig = {
|
|
90
|
+
averageWindowSize: 5,
|
|
91
|
+
debugLog: false,
|
|
92
|
+
maxDeltaMs: 10,
|
|
93
|
+
maxRun: 10000,
|
|
94
|
+
minRun: 5,
|
|
95
|
+
stableRun: 3,
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Benchmark the duration of a function.
|
|
99
|
+
*
|
|
100
|
+
* This benchmark will run the function multiple time until it reaches a stable average.
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export const dynamicBenchmark = async (dynamicBenchSetup) => {
|
|
105
|
+
const cfg = { ...defaultBenchConfig, ...dynamicBenchSetup };
|
|
106
|
+
const log = getLog(cfg.debugLog);
|
|
107
|
+
log("Getting benchmark function informations");
|
|
108
|
+
const funcInfo = await getBenchFuncInfo(cfg.func);
|
|
109
|
+
let runCounter = 1;
|
|
110
|
+
log(`First run: ${funcInfo.firstRunDurationMs}ms; use promises: ${funcInfo.isPromise ? "true" : "false"}`);
|
|
111
|
+
const averageWindow = [];
|
|
112
|
+
averageWindow.push(funcInfo.firstRunDurationMs);
|
|
113
|
+
log("Filling average window with initial runs");
|
|
114
|
+
while (averageWindow.length < cfg.averageWindowSize || runCounter < cfg.minRun) {
|
|
115
|
+
log(`Run ${runCounter + 1}`);
|
|
116
|
+
addToAverageWindow(
|
|
117
|
+
// eslint-disable-next-line no-await-in-loop
|
|
118
|
+
await benchOneRun(funcInfo.isPromise, cfg.func), averageWindow, cfg.averageWindowSize);
|
|
119
|
+
++runCounter;
|
|
120
|
+
}
|
|
121
|
+
let consecutiveSuccess = 0;
|
|
122
|
+
while (runCounter < cfg.maxRun) {
|
|
123
|
+
const currentAverage = computeAverage(averageWindow);
|
|
124
|
+
log(`Doing new run ${runCounter + 1}`);
|
|
125
|
+
// eslint-disable-next-line no-await-in-loop
|
|
126
|
+
const nextRun = await benchOneRun(funcInfo.isPromise, cfg.func);
|
|
127
|
+
++runCounter;
|
|
128
|
+
if (Math.abs(currentAverage - nextRun) <= cfg.maxDeltaMs) {
|
|
129
|
+
log(`Average run: ${currentAverage}ms, new run: ${nextRun}ms, under delta ${cfg.maxDeltaMs}`);
|
|
130
|
+
++consecutiveSuccess;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
log(`Average run: ${currentAverage}ms, new run: ${nextRun}ms, over delta ${cfg.maxDeltaMs}`);
|
|
134
|
+
consecutiveSuccess = 0;
|
|
135
|
+
}
|
|
136
|
+
averageWindow.shift();
|
|
137
|
+
averageWindow.push(nextRun);
|
|
138
|
+
if (consecutiveSuccess >= cfg.stableRun) {
|
|
139
|
+
log(`Found ${consecutiveSuccess} successive run under delta, ending benchmark`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (consecutiveSuccess < cfg.stableRun)
|
|
144
|
+
log("Benchmark was inconclusive");
|
|
145
|
+
return computeAverage(averageWindow);
|
|
146
|
+
};
|
|
147
|
+
const advancedDefaults = {
|
|
148
|
+
maxMultiplier: 1000,
|
|
149
|
+
minFuncDurationMs: 10,
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Advanced dynamic benchmark where the length of the benchmark function can be adjusted.
|
|
153
|
+
*
|
|
154
|
+
* The `multiplier` property/parameter can be increased as needed until the benchmark function reach
|
|
155
|
+
* a given minimum duration, after which it is effectively benchmarked.
|
|
156
|
+
*
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
export const advancedDynamicBenchmark = async (dynamicBenchSetup) => {
|
|
160
|
+
const cfg = { ...advancedDefaults, ...dynamicBenchSetup };
|
|
161
|
+
const log = getLog(cfg.debugLog);
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
163
|
+
let durationMs;
|
|
164
|
+
let multiplier = 0;
|
|
165
|
+
while (durationMs === undefined ||
|
|
166
|
+
(durationMs < cfg.minFuncDurationMs && multiplier <= cfg.maxMultiplier)) {
|
|
167
|
+
log(`Advanced benchmark, multiplier: ${multiplier}`);
|
|
168
|
+
++multiplier;
|
|
169
|
+
// eslint-disable-next-line no-await-in-loop
|
|
170
|
+
const func = await cfg.getFunc(multiplier);
|
|
171
|
+
// eslint-disable-next-line no-await-in-loop
|
|
172
|
+
durationMs = await dynamicBenchmark({ ...cfg, func });
|
|
173
|
+
log(`Duration: ${durationMs}ms, target: ${cfg.minFuncDurationMs}`);
|
|
174
|
+
}
|
|
175
|
+
log(`Final results: ${durationMs}ms with multiplier ${multiplier}`);
|
|
176
|
+
return { multiplier, durationMs };
|
|
177
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Return an ArrayBuffer that match the provided Uint8Array
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare const getArrayBuffer: (typedArray: ArrayBuffer | Uint8Array) => ArrayBuffer;
|
|
22
|
+
/**
|
|
23
|
+
* Convert an array buffer to a b64 string
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export declare const ab2b64: (data: ArrayBuffer) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Convert a b64 string to an array buffer
|
|
30
|
+
*
|
|
31
|
+
* @param strict - If enabled, prevent input from having extra data after the B64 string.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export declare const b642ab: (data: string, strict?: boolean) => ArrayBuffer;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { encode as encodeB64, decode as decodeB64 } from "base64-arraybuffer";
|
|
17
|
+
import { b64EffectiveData, B64_PAD2, B64_PAD1, B64_PAD0, B64_CHARBLOCK } from "./base64.js";
|
|
18
|
+
/**
|
|
19
|
+
* Return an ArrayBuffer that match the provided Uint8Array
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export const getArrayBuffer = (typedArray) => {
|
|
24
|
+
if (typedArray instanceof ArrayBuffer)
|
|
25
|
+
return typedArray;
|
|
26
|
+
const ab = typedArray.buffer;
|
|
27
|
+
if (typedArray.byteOffset === 0 && typedArray.byteLength === ab.byteLength)
|
|
28
|
+
return ab;
|
|
29
|
+
return ab.slice(typedArray.byteOffset, typedArray.byteOffset + typedArray.byteLength);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Convert an array buffer to a b64 string
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export const ab2b64 = (data) => encodeB64(data);
|
|
37
|
+
/**
|
|
38
|
+
* Convert a b64 string to an array buffer
|
|
39
|
+
*
|
|
40
|
+
* @param strict - If enabled, prevent input from having extra data after the B64 string.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export const b642ab = (data, strict = false) => {
|
|
45
|
+
const effectiveData = b64EffectiveData(data, strict);
|
|
46
|
+
const result = decodeB64(effectiveData);
|
|
47
|
+
if (strict && effectiveData.length > 0) {
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
49
|
+
let padding;
|
|
50
|
+
if (effectiveData.endsWith("==")) {
|
|
51
|
+
padding = B64_PAD2;
|
|
52
|
+
}
|
|
53
|
+
else if (effectiveData.endsWith("=")) {
|
|
54
|
+
padding = B64_PAD1;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
padding = B64_PAD0;
|
|
58
|
+
}
|
|
59
|
+
const outputLength = (effectiveData.length / B64_CHARBLOCK) * (B64_CHARBLOCK - 1) - padding;
|
|
60
|
+
if (result.byteLength !== outputLength)
|
|
61
|
+
throw new Error("Invalid output length");
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
};
|