@atproto/lex-data 0.0.2 → 0.0.3
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/CHANGELOG.md +6 -0
- package/dist/uint8array-base64.d.ts +3 -0
- package/dist/uint8array-base64.d.ts.map +1 -0
- package/dist/uint8array-base64.js +3 -0
- package/dist/uint8array-base64.js.map +1 -0
- package/dist/uint8array-from-base64.d.ts +4 -3
- package/dist/uint8array-from-base64.d.ts.map +1 -1
- package/dist/uint8array-from-base64.js +9 -6
- package/dist/uint8array-from-base64.js.map +1 -1
- package/dist/uint8array-to-base64.d.ts +4 -3
- package/dist/uint8array-to-base64.d.ts.map +1 -1
- package/dist/uint8array-to-base64.js +7 -6
- package/dist/uint8array-to-base64.js.map +1 -1
- package/dist/uint8array.d.ts +6 -3
- package/dist/uint8array.d.ts.map +1 -1
- package/dist/uint8array.js +2 -1
- package/dist/uint8array.js.map +1 -1
- package/package.json +1 -1
- package/src/uint8array-base64.ts +2 -0
- package/src/uint8array-from-base64.test.ts +33 -19
- package/src/uint8array-from-base64.ts +19 -6
- package/src/uint8array-to-base64.test.ts +170 -0
- package/src/uint8array-to-base64.ts +18 -8
- package/src/uint8array.ts +13 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @atproto/lex-data
|
|
2
2
|
|
|
3
|
+
## 0.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4422](https://github.com/bluesky-social/atproto/pull/4422) [`693784c`](https://github.com/bluesky-social/atproto/commit/693784c3a0dee4b6a29aa1e018fce682dcae148f) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add support for base64url encoding/decoding
|
|
8
|
+
|
|
3
9
|
## 0.0.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uint8array-base64.d.ts","sourceRoot":"","sources":["../src/uint8array-base64.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,WAAW,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uint8array-base64.js","sourceRoot":"","sources":["../src/uint8array-base64.ts"],"names":[],"mappings":"","sourcesContent":["/** @default 'base64' */\nexport type Base64Alphabet = 'base64' | 'base64url'\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Base64Alphabet } from './uint8array-base64.js';
|
|
1
2
|
declare global {
|
|
2
3
|
interface Uint8ArrayConstructor {
|
|
3
4
|
/**
|
|
@@ -10,7 +11,7 @@ declare global {
|
|
|
10
11
|
}) => Uint8Array;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
|
-
export declare const fromBase64Native: ((b64: string) => Uint8Array) | null;
|
|
14
|
-
export declare const fromBase64Node: ((b64: string) => Uint8Array) | null;
|
|
15
|
-
export declare function fromBase64Ponyfill(b64: string): Uint8Array;
|
|
14
|
+
export declare const fromBase64Native: ((b64: string, alphabet?: Base64Alphabet) => Uint8Array) | null;
|
|
15
|
+
export declare const fromBase64Node: ((b64: string, alphabet?: Base64Alphabet) => Uint8Array) | null;
|
|
16
|
+
export declare function fromBase64Ponyfill(b64: string, alphabet?: Base64Alphabet): Uint8Array;
|
|
16
17
|
//# sourceMappingURL=uint8array-from-base64.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array-from-base64.d.ts","sourceRoot":"","sources":["../src/uint8array-from-base64.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"uint8array-from-base64.d.ts","sourceRoot":"","sources":["../src/uint8array-from-base64.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAIvD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B;;WAEG;QACH,UAAU,CAAC,EAAE,CACX,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;YACR,wBAAwB;YACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;YACjC,iBAAiB,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,qBAAqB,CAAA;SAC/D,KACE,UAAU,CAAA;KAChB;CACF;AAED,eAAO,MAAM,gBAAgB,SAGhB,MAAM,aACD,cAAc,KACvB,UAAU,QAMT,CAAA;AAEV,eAAO,MAAM,cAAc,SAEhB,MAAM,aACD,cAAc,KACvB,UAAU,QAQT,CAAA;AAER,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,cAAyB,GAClC,UAAU,CAIZ"}
|
|
@@ -6,13 +6,16 @@ const from_string_1 = require("uint8arrays/from-string");
|
|
|
6
6
|
const nodejs_buffer_js_1 = require("./lib/nodejs-buffer.js");
|
|
7
7
|
const Buffer = nodejs_buffer_js_1.NodeJSBuffer;
|
|
8
8
|
exports.fromBase64Native = typeof Uint8Array.fromBase64 === 'function'
|
|
9
|
-
? function fromBase64Native(b64) {
|
|
10
|
-
return Uint8Array.fromBase64(b64, {
|
|
9
|
+
? function fromBase64Native(b64, alphabet = 'base64') {
|
|
10
|
+
return Uint8Array.fromBase64(b64, {
|
|
11
|
+
alphabet,
|
|
12
|
+
lastChunkHandling: 'loose',
|
|
13
|
+
});
|
|
11
14
|
}
|
|
12
15
|
: null;
|
|
13
16
|
exports.fromBase64Node = Buffer
|
|
14
|
-
? function fromBase64Node(b64) {
|
|
15
|
-
const bytes = Buffer.from(b64,
|
|
17
|
+
? function fromBase64Node(b64, alphabet = 'base64') {
|
|
18
|
+
const bytes = Buffer.from(b64, alphabet);
|
|
16
19
|
verifyBase64ForBytes(b64, bytes);
|
|
17
20
|
// Convert to Uint8Array because even though Buffer is a sub class of
|
|
18
21
|
// Uint8Array, it serializes differently to Uint8Array (e.g. in JSON) and
|
|
@@ -20,8 +23,8 @@ exports.fromBase64Node = Buffer
|
|
|
20
23
|
return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
21
24
|
}
|
|
22
25
|
: null;
|
|
23
|
-
function fromBase64Ponyfill(b64) {
|
|
24
|
-
const bytes = (0, from_string_1.fromString)(b64, '
|
|
26
|
+
function fromBase64Ponyfill(b64, alphabet = 'base64') {
|
|
27
|
+
const bytes = (0, from_string_1.fromString)(b64, b64.endsWith('=') ? `${alphabet}pad` : alphabet);
|
|
25
28
|
verifyBase64ForBytes(b64, bytes);
|
|
26
29
|
return bytes;
|
|
27
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array-from-base64.js","sourceRoot":"","sources":["../src/uint8array-from-base64.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"uint8array-from-base64.js","sourceRoot":"","sources":["../src/uint8array-from-base64.ts"],"names":[],"mappings":"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","sourcesContent":["import { fromString } from 'uint8arrays/from-string'\nimport { NodeJSBuffer } from './lib/nodejs-buffer.js'\nimport { Base64Alphabet } from './uint8array-base64.js'\n\nconst Buffer = NodeJSBuffer\n\ndeclare global {\n interface Uint8ArrayConstructor {\n /**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64 Uint8Array.fromBase64()}\n */\n fromBase64?: (\n b64: string,\n options?: {\n /** @default 'base64' */\n alphabet?: 'base64' | 'base64url'\n lastChunkHandling?: 'loose' | 'strict' | 'stop-before-partial'\n },\n ) => Uint8Array\n }\n}\n\nexport const fromBase64Native =\n typeof Uint8Array.fromBase64 === 'function'\n ? function fromBase64Native(\n b64: string,\n alphabet: Base64Alphabet = 'base64',\n ): Uint8Array {\n return Uint8Array.fromBase64!(b64, {\n alphabet,\n lastChunkHandling: 'loose',\n })\n }\n : null\n\nexport const fromBase64Node = Buffer\n ? function fromBase64Node(\n b64: string,\n alphabet: Base64Alphabet = 'base64',\n ): Uint8Array {\n const bytes = Buffer.from(b64, alphabet)\n verifyBase64ForBytes(b64, bytes)\n // Convert to Uint8Array because even though Buffer is a sub class of\n // Uint8Array, it serializes differently to Uint8Array (e.g. in JSON) and\n // results in unexpected behavior downstream (e.g. in tests)\n return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n }\n : null\n\nexport function fromBase64Ponyfill(\n b64: string,\n alphabet: Base64Alphabet = 'base64',\n): Uint8Array {\n const bytes = fromString(b64, b64.endsWith('=') ? `${alphabet}pad` : alphabet)\n verifyBase64ForBytes(b64, bytes)\n return bytes\n}\n\n// @NOTE NodeJS will silently stop decoding at the first invalid character,\n// while \"uint8arrays/from-string\" will not validate that the padding is\n// correct. The following function performs basic validation to ensure that the\n// input was a valid base64 string. The availability of the \"bytes\" allows\n// to perform checks with O[1] complexity.\nfunction verifyBase64ForBytes(b64: string, bytes: Uint8Array): void {\n const paddingCount = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0\n const trimmedLength = b64.length - paddingCount\n const expectedByteLength = Math.floor((trimmedLength * 3) / 4)\n if (bytes.length !== expectedByteLength) {\n throw new Error('Invalid base64 string')\n }\n\n const expectedB64Length = (bytes.length / 3) * 4\n const expectedPaddingCount =\n expectedB64Length % 4 === 0 ? 0 : 4 - (expectedB64Length % 4)\n const expectedFullB64Length = expectedB64Length + expectedPaddingCount\n if (b64.length > expectedFullB64Length) {\n throw new Error('Invalid base64 string')\n }\n\n // The previous might still allow false positive if only the last few\n // chars are invalid.\n for (\n let i = Math.ceil(expectedB64Length);\n i < b64.length - paddingCount;\n i++\n ) {\n const code = b64.charCodeAt(i)\n if (\n !(code >= 65 && code <= 90) && // A-Z\n !(code >= 97 && code <= 122) && // a-z\n !(code >= 48 && code <= 57) && // 0-9\n code !== 43 && // +\n code !== 47 // /\n ) {\n throw new Error('Invalid base64 string')\n }\n }\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Base64Alphabet } from './uint8array-base64.js';
|
|
1
2
|
declare global {
|
|
2
3
|
interface Uint8Array {
|
|
3
4
|
/**
|
|
@@ -10,7 +11,7 @@ declare global {
|
|
|
10
11
|
}) => string;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
|
-
export declare const toBase64Native: ((bytes: Uint8Array) => string) | null;
|
|
14
|
-
export declare const toBase64Node: ((bytes: Uint8Array) => string) | null;
|
|
15
|
-
export declare function toBase64Ponyfill(bytes: Uint8Array): string;
|
|
14
|
+
export declare const toBase64Native: ((bytes: Uint8Array, alphabet?: Base64Alphabet) => string) | null;
|
|
15
|
+
export declare const toBase64Node: ((bytes: Uint8Array, alphabet?: Base64Alphabet) => string) | null;
|
|
16
|
+
export declare function toBase64Ponyfill(bytes: Uint8Array, alphabet?: Base64Alphabet): string;
|
|
16
17
|
//# sourceMappingURL=uint8array-to-base64.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array-to-base64.d.ts","sourceRoot":"","sources":["../src/uint8array-to-base64.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"uint8array-to-base64.d.ts","sourceRoot":"","sources":["../src/uint8array-to-base64.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAIvD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,UAAU;QAClB;;WAEG;QACH,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;YACpB,wBAAwB;YACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;YACjC,WAAW,CAAC,EAAE,OAAO,CAAA;SACtB,KAAK,MAAM,CAAA;KACb;CACF;AAED,eAAO,MAAM,cAAc,WAGZ,UAAU,aACP,cAAc,KACvB,MAAM,QAGL,CAAA;AAEV,eAAO,MAAM,YAAY,WAEZ,UAAU,aACP,cAAc,KACvB,MAAM,QAcL,CAAA;AAER,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,UAAU,EACjB,QAAQ,GAAE,cAAyB,GAClC,MAAM,CAER"}
|
|
@@ -6,13 +6,14 @@ const to_string_1 = require("uint8arrays/to-string");
|
|
|
6
6
|
const nodejs_buffer_js_1 = require("./lib/nodejs-buffer.js");
|
|
7
7
|
const Buffer = nodejs_buffer_js_1.NodeJSBuffer;
|
|
8
8
|
exports.toBase64Native = typeof Uint8Array.prototype.toBase64 === 'function'
|
|
9
|
-
? function toBase64Native(bytes) {
|
|
10
|
-
return bytes.toBase64({ omitPadding: true });
|
|
9
|
+
? function toBase64Native(bytes, alphabet = 'base64') {
|
|
10
|
+
return bytes.toBase64({ alphabet, omitPadding: true });
|
|
11
11
|
}
|
|
12
12
|
: null;
|
|
13
13
|
exports.toBase64Node = Buffer
|
|
14
|
-
? function toBase64Node(bytes) {
|
|
15
|
-
const
|
|
14
|
+
? function toBase64Node(bytes, alphabet = 'base64') {
|
|
15
|
+
const buffer = bytes instanceof Buffer ? bytes : Buffer.from(bytes);
|
|
16
|
+
const b64 = buffer.toString(alphabet);
|
|
16
17
|
// @NOTE We strip padding for strict compatibility with
|
|
17
18
|
// uint8arrays.toString behavior. Tests failing because of the presence of
|
|
18
19
|
// padding are not really synonymous with an actual error and we might
|
|
@@ -24,7 +25,7 @@ exports.toBase64Node = Buffer
|
|
|
24
25
|
: b64;
|
|
25
26
|
}
|
|
26
27
|
: null;
|
|
27
|
-
function toBase64Ponyfill(bytes) {
|
|
28
|
-
return (0, to_string_1.toString)(bytes,
|
|
28
|
+
function toBase64Ponyfill(bytes, alphabet = 'base64') {
|
|
29
|
+
return (0, to_string_1.toString)(bytes, alphabet);
|
|
29
30
|
}
|
|
30
31
|
//# sourceMappingURL=uint8array-to-base64.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array-to-base64.js","sourceRoot":"","sources":["../src/uint8array-to-base64.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"uint8array-to-base64.js","sourceRoot":"","sources":["../src/uint8array-to-base64.ts"],"names":[],"mappings":";;;AAiDA,4CAKC;AAtDD,qDAAgD;AAChD,6DAAqD;AAGrD,MAAM,MAAM,GAAG,+BAAY,CAAA;AAed,QAAA,cAAc,GACzB,OAAO,UAAU,CAAC,SAAS,CAAC,QAAQ,KAAK,UAAU;IACjD,CAAC,CAAC,SAAS,cAAc,CACrB,KAAiB,EACjB,WAA2B,QAAQ;QAEnC,OAAO,KAAK,CAAC,QAAS,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC;IACH,CAAC,CAAC,IAAI,CAAA;AAEG,QAAA,YAAY,GAAG,MAAM;IAChC,CAAC,CAAC,SAAS,YAAY,CACnB,KAAiB,EACjB,WAA2B,QAAQ;QAEnC,MAAM,MAAM,GAAG,KAAK,YAAY,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACnE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAErC,uDAAuD;QACvD,0EAA0E;QAC1E,sEAAsE;QACtE,6DAA6D;QAC7D,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI;YACtD,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI;gBACjD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO;gBAC1B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;YAC3B,CAAC,CAAC,GAAG,CAAA;IACT,CAAC;IACH,CAAC,CAAC,IAAI,CAAA;AAER,SAAgB,gBAAgB,CAC9B,KAAiB,EACjB,WAA2B,QAAQ;IAEnC,OAAO,IAAA,oBAAQ,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AAClC,CAAC","sourcesContent":["import { toString } from 'uint8arrays/to-string'\nimport { NodeJSBuffer } from './lib/nodejs-buffer.js'\nimport { Base64Alphabet } from './uint8array-base64.js'\n\nconst Buffer = NodeJSBuffer\n\ndeclare global {\n interface Uint8Array {\n /**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64 Uint8Array.prototype.toBase64()}\n */\n toBase64?: (options?: {\n /** @default 'base64' */\n alphabet?: 'base64' | 'base64url'\n omitPadding?: boolean\n }) => string\n }\n}\n\nexport const toBase64Native =\n typeof Uint8Array.prototype.toBase64 === 'function'\n ? function toBase64Native(\n bytes: Uint8Array,\n alphabet: Base64Alphabet = 'base64',\n ): string {\n return bytes.toBase64!({ alphabet, omitPadding: true })\n }\n : null\n\nexport const toBase64Node = Buffer\n ? function toBase64Node(\n bytes: Uint8Array,\n alphabet: Base64Alphabet = 'base64',\n ): string {\n const buffer = bytes instanceof Buffer ? bytes : Buffer.from(bytes)\n const b64 = buffer.toString(alphabet)\n\n // @NOTE We strip padding for strict compatibility with\n // uint8arrays.toString behavior. Tests failing because of the presence of\n // padding are not really synonymous with an actual error and we might\n // (should?) actually want to keep the padding at some point.\n return b64.charCodeAt(b64.length - 1) === /* '=' */ 0x3d\n ? b64.charCodeAt(b64.length - 2) === /* '=' */ 0x3d\n ? b64.slice(0, -2) // '=='\n : b64.slice(0, -1) // '='\n : b64\n }\n : null\n\nexport function toBase64Ponyfill(\n bytes: Uint8Array,\n alphabet: Base64Alphabet = 'base64',\n): string {\n return toString(bytes, alphabet)\n}\n"]}
|
package/dist/uint8array.d.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { Base64Alphabet } from './uint8array-base64.js';
|
|
2
|
+
export type { Base64Alphabet };
|
|
1
3
|
/**
|
|
2
4
|
* Encodes a Uint8Array into a base64 string.
|
|
3
5
|
*
|
|
4
6
|
* @returns The base64 encoded string
|
|
5
7
|
*/
|
|
6
|
-
export declare const toBase64: (bytes: Uint8Array) => string;
|
|
8
|
+
export declare const toBase64: (bytes: Uint8Array, alphabet?: Base64Alphabet) => string;
|
|
7
9
|
/**
|
|
8
|
-
* Decodes a base64 string into a Uint8Array.
|
|
10
|
+
* Decodes a base64 string into a Uint8Array. This function supports both padded
|
|
11
|
+
* and unpadded base64 strings.
|
|
9
12
|
*
|
|
10
13
|
* @returns The decoded {@link Uint8Array}
|
|
11
14
|
* @throws If the input is not a valid base64 string
|
|
12
15
|
*/
|
|
13
|
-
export declare const fromBase64: (b64: string) => Uint8Array;
|
|
16
|
+
export declare const fromBase64: (b64: string, alphabet?: Base64Alphabet) => Uint8Array;
|
|
14
17
|
/**
|
|
15
18
|
* Coerces various binary data representations into a Uint8Array.
|
|
16
19
|
*
|
package/dist/uint8array.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array.d.ts","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"uint8array.d.ts","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAYvD,YAAY,EAAE,cAAc,EAAE,CAAA;AAO9B;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,CACrB,KAAK,EAAE,UAAU,EACjB,QAAQ,CAAC,EAAE,cAAc,KACtB,MAA2D,CAAA;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,CACvB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,cAAc,KACtB,UAAqE,CAAA;AAS1E;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAkBnE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAY/D"}
|
package/dist/uint8array.js
CHANGED
|
@@ -16,7 +16,8 @@ const uint8array_to_base64_js_1 = require("./uint8array-to-base64.js");
|
|
|
16
16
|
*/
|
|
17
17
|
exports.toBase64 = uint8array_to_base64_js_1.toBase64Native ?? uint8array_to_base64_js_1.toBase64Node ?? uint8array_to_base64_js_1.toBase64Ponyfill;
|
|
18
18
|
/**
|
|
19
|
-
* Decodes a base64 string into a Uint8Array.
|
|
19
|
+
* Decodes a base64 string into a Uint8Array. This function supports both padded
|
|
20
|
+
* and unpadded base64 strings.
|
|
20
21
|
*
|
|
21
22
|
* @returns The decoded {@link Uint8Array}
|
|
22
23
|
* @throws If the input is not a valid base64 string
|
package/dist/uint8array.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;AAqDA,oCAkBC;AAED,8BAYC;AApFD,2EAIoC;AACpC,uEAIkC;AAIlC,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,0CAA0C;AAE1C;;;;GAIG;AACU,QAAA,QAAQ,GAGP,wCAAc,IAAI,sCAAY,IAAI,0CAAgB,CAAA;AAEhE;;;;;;GAMG;AACU,QAAA,UAAU,GAGL,4CAAgB,IAAI,0CAAc,IAAI,8CAAkB,CAAA;AAE1E,IAAI,gBAAQ,KAAK,0CAAgB,IAAI,kBAAU,KAAK,8CAAkB,EAAE,CAAC;IACvE,aAAa;IACb,OAAO,CAAC,IAAI,CACV,wJAAwJ,CACzJ,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CACnB,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAChD,CAAA;IACH,CAAC;IAED,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,SAAS,CAAC,CAAa,EAAE,CAAa;IACpD,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["import { Base64Alphabet } from './uint8array-base64.js'\nimport {\n fromBase64Native,\n fromBase64Node,\n fromBase64Ponyfill,\n} from './uint8array-from-base64.js'\nimport {\n toBase64Native,\n toBase64Node,\n toBase64Ponyfill,\n} from './uint8array-to-base64.js'\n\nexport type { Base64Alphabet }\n\n// @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /\n// Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /\n// toBase64 as deprecated. We can also drop NodeJS specific implementations\n// once NodeJS <24 is no longer supported.\n\n/**\n * Encodes a Uint8Array into a base64 string.\n *\n * @returns The base64 encoded string\n */\nexport const toBase64: (\n bytes: Uint8Array,\n alphabet?: Base64Alphabet,\n) => string = toBase64Native ?? toBase64Node ?? toBase64Ponyfill\n\n/**\n * Decodes a base64 string into a Uint8Array. This function supports both padded\n * and unpadded base64 strings.\n *\n * @returns The decoded {@link Uint8Array}\n * @throws If the input is not a valid base64 string\n */\nexport const fromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => Uint8Array = fromBase64Native ?? fromBase64Node ?? fromBase64Ponyfill\n\nif (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\n/**\n * Coerces various binary data representations into a Uint8Array.\n *\n * @return `undefined` if the input could not be coerced into a {@link Uint8Array}.\n */\nexport function asUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n if (ArrayBuffer.isView(input)) {\n return new Uint8Array(\n input.buffer,\n input.byteOffset,\n input.byteLength / Uint8Array.BYTES_PER_ELEMENT,\n )\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input)\n }\n\n return undefined\n}\n\nexport function ui8Equals(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) {\n return false\n }\n\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] !== b[i]) {\n return false\n }\n }\n\n return true\n}\n"]}
|
package/package.json
CHANGED
|
@@ -40,34 +40,48 @@ for (const fromBase64 of [
|
|
|
40
40
|
expect(ui8Equals(decoded, bytes)).toBe(true)
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
for (const
|
|
44
|
-
'',
|
|
45
|
-
'\0\0',
|
|
46
|
-
'\0\0\0',
|
|
47
|
-
'\0\0\0\0',
|
|
48
|
-
'__',
|
|
49
|
-
'é',
|
|
50
|
-
'àç',
|
|
51
|
-
'\0éàç',
|
|
52
|
-
'```',
|
|
53
|
-
'aaa',
|
|
54
|
-
'Hello, World!',
|
|
55
|
-
'😀😃😄😁😆😅😂🤣😊😇',
|
|
56
|
-
'👩💻👨💻👩🔬👨🔬👩🚀👨🚀',
|
|
57
|
-
'🌍🌎🌏🌐🪐🌟✨⚡🔥💧',
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
for (const buffer of [
|
|
44
|
+
Buffer.from(''),
|
|
45
|
+
Buffer.from('\0\0'),
|
|
46
|
+
Buffer.from('\0\0\0'),
|
|
47
|
+
Buffer.from('\0\0\0\0'),
|
|
48
|
+
Buffer.from('__'),
|
|
49
|
+
Buffer.from('é'),
|
|
50
|
+
Buffer.from('àç'),
|
|
51
|
+
Buffer.from('\0éàç'),
|
|
52
|
+
Buffer.from('```'),
|
|
53
|
+
Buffer.from('aaa'),
|
|
54
|
+
Buffer.from('Hello, World!'),
|
|
55
|
+
Buffer.from('😀😃😄😁😆😅😂🤣😊😇'),
|
|
56
|
+
Buffer.from('👩💻👨💻👩🔬👨🔬👩🚀👨🚀'),
|
|
57
|
+
Buffer.from('🌍🌎🌏🌐🪐🌟✨⚡🔥💧'),
|
|
58
|
+
Buffer.from(new Uint8Array([0xfb, 0xff, 0xbf])),
|
|
59
|
+
Buffer.from(new Uint8Array([0xfb, 0xff, 0xbf])),
|
|
60
|
+
Buffer.from(new Uint8Array([0x4d])),
|
|
61
|
+
Buffer.from(new Uint8Array([0x4d, 0x61])),
|
|
62
|
+
Buffer.from(new Uint8Array([0x4d, 0x61, 0x6e])),
|
|
63
|
+
Buffer.from(new Uint8Array([0x4d])),
|
|
64
|
+
Buffer.from(new Uint8Array([0x4d, 0x61])),
|
|
65
|
+
Buffer.from(new Uint8Array([0x00, 0x4d, 0x61, 0x6e, 0x00])),
|
|
66
|
+
]) {
|
|
60
67
|
const base64 = buffer.toString('base64')
|
|
61
68
|
const base64Unpadded = base64.replace(/=+$/, '')
|
|
69
|
+
const base64url = buffer.toString('base64url') // No padding in base64url
|
|
62
70
|
|
|
63
|
-
it(`decodes ${JSON.stringify(
|
|
71
|
+
it(`decodes ${JSON.stringify(base64)}`, () => {
|
|
64
72
|
const decoded = fromBase64(base64)
|
|
65
73
|
expect(decoded).toBeInstanceOf(Uint8Array)
|
|
66
74
|
expect(ui8Equals(decoded, buffer)).toBe(true)
|
|
67
75
|
})
|
|
68
76
|
|
|
77
|
+
it(`decodes ${JSON.stringify(base64url)} (base64url)`, () => {
|
|
78
|
+
const decoded = fromBase64(base64url, 'base64url')
|
|
79
|
+
expect(decoded).toBeInstanceOf(Uint8Array)
|
|
80
|
+
expect(ui8Equals(decoded, buffer)).toBe(true)
|
|
81
|
+
})
|
|
82
|
+
|
|
69
83
|
if (base64 !== base64Unpadded) {
|
|
70
|
-
it(`decodes ${JSON.stringify(
|
|
84
|
+
it(`decodes ${JSON.stringify(base64Unpadded)} (unpadded)`, () => {
|
|
71
85
|
const decoded = fromBase64(base64Unpadded)
|
|
72
86
|
expect(decoded).toBeInstanceOf(Uint8Array)
|
|
73
87
|
expect(ui8Equals(decoded, buffer)).toBe(true)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fromString } from 'uint8arrays/from-string'
|
|
2
2
|
import { NodeJSBuffer } from './lib/nodejs-buffer.js'
|
|
3
|
+
import { Base64Alphabet } from './uint8array-base64.js'
|
|
3
4
|
|
|
4
5
|
const Buffer = NodeJSBuffer
|
|
5
6
|
|
|
@@ -21,14 +22,23 @@ declare global {
|
|
|
21
22
|
|
|
22
23
|
export const fromBase64Native =
|
|
23
24
|
typeof Uint8Array.fromBase64 === 'function'
|
|
24
|
-
? function fromBase64Native(
|
|
25
|
-
|
|
25
|
+
? function fromBase64Native(
|
|
26
|
+
b64: string,
|
|
27
|
+
alphabet: Base64Alphabet = 'base64',
|
|
28
|
+
): Uint8Array {
|
|
29
|
+
return Uint8Array.fromBase64!(b64, {
|
|
30
|
+
alphabet,
|
|
31
|
+
lastChunkHandling: 'loose',
|
|
32
|
+
})
|
|
26
33
|
}
|
|
27
34
|
: null
|
|
28
35
|
|
|
29
36
|
export const fromBase64Node = Buffer
|
|
30
|
-
? function fromBase64Node(
|
|
31
|
-
|
|
37
|
+
? function fromBase64Node(
|
|
38
|
+
b64: string,
|
|
39
|
+
alphabet: Base64Alphabet = 'base64',
|
|
40
|
+
): Uint8Array {
|
|
41
|
+
const bytes = Buffer.from(b64, alphabet)
|
|
32
42
|
verifyBase64ForBytes(b64, bytes)
|
|
33
43
|
// Convert to Uint8Array because even though Buffer is a sub class of
|
|
34
44
|
// Uint8Array, it serializes differently to Uint8Array (e.g. in JSON) and
|
|
@@ -37,8 +47,11 @@ export const fromBase64Node = Buffer
|
|
|
37
47
|
}
|
|
38
48
|
: null
|
|
39
49
|
|
|
40
|
-
export function fromBase64Ponyfill(
|
|
41
|
-
|
|
50
|
+
export function fromBase64Ponyfill(
|
|
51
|
+
b64: string,
|
|
52
|
+
alphabet: Base64Alphabet = 'base64',
|
|
53
|
+
): Uint8Array {
|
|
54
|
+
const bytes = fromString(b64, b64.endsWith('=') ? `${alphabet}pad` : alphabet)
|
|
42
55
|
verifyBase64ForBytes(b64, bytes)
|
|
43
56
|
return bytes
|
|
44
57
|
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import 'core-js/modules/es.uint8-array.from-base64.js'
|
|
2
|
+
import 'core-js/modules/es.uint8-array.to-base64.js'
|
|
3
|
+
import assert from 'node:assert'
|
|
4
|
+
import {
|
|
5
|
+
toBase64Native,
|
|
6
|
+
toBase64Node,
|
|
7
|
+
toBase64Ponyfill,
|
|
8
|
+
} from './uint8array-to-base64.js'
|
|
9
|
+
|
|
10
|
+
for (const toBase64 of [
|
|
11
|
+
toBase64Native,
|
|
12
|
+
toBase64Node,
|
|
13
|
+
toBase64Ponyfill,
|
|
14
|
+
] as const) {
|
|
15
|
+
// Tests should run in NodeJS where implementations are either available or
|
|
16
|
+
// polyfilled (see core-js imports above).
|
|
17
|
+
assert(toBase64 !== null, 'toBase64 implementation should not be null')
|
|
18
|
+
|
|
19
|
+
describe(toBase64.name, () => {
|
|
20
|
+
describe('basic encoding', () => {
|
|
21
|
+
it('encodes empty Uint8Array', () => {
|
|
22
|
+
const encoded = toBase64(new Uint8Array(0))
|
|
23
|
+
expect(typeof encoded).toBe('string')
|
|
24
|
+
expect(encoded).toBe('')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('encodes 10MB', () => {
|
|
28
|
+
const bytes = Buffer.allocUnsafe(10_000_000).fill('🐩')
|
|
29
|
+
const encoded = toBase64(bytes)
|
|
30
|
+
expect(typeof encoded).toBe('string')
|
|
31
|
+
// Verify by decoding back
|
|
32
|
+
const decoded = Buffer.from(encoded, 'base64')
|
|
33
|
+
expect(decoded.equals(bytes)).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('base64 alphabet (default)', () => {
|
|
38
|
+
for (const string of [
|
|
39
|
+
'',
|
|
40
|
+
'\0\0',
|
|
41
|
+
'\0\0\0',
|
|
42
|
+
'\0\0\0\0',
|
|
43
|
+
'__',
|
|
44
|
+
'é',
|
|
45
|
+
'àç',
|
|
46
|
+
'\0éàç',
|
|
47
|
+
'```\x1b',
|
|
48
|
+
'aaa',
|
|
49
|
+
'Hello, World!',
|
|
50
|
+
'😀😃😄😁😆😅😂🤣😊😇',
|
|
51
|
+
'👩💻👨💻👩🔬👨🔬👩🚀👨🚀',
|
|
52
|
+
'🌍🌎🌏🌐🪐🌟✨⚡🔥💧',
|
|
53
|
+
] as const) {
|
|
54
|
+
const buffer = Buffer.from(string, 'utf8')
|
|
55
|
+
const expected = buffer.toString('base64').replace(/=+$/, '')
|
|
56
|
+
|
|
57
|
+
it(`encodes ${JSON.stringify(string)} as ${JSON.stringify(expected)}`, () => {
|
|
58
|
+
const encoded = toBase64(buffer)
|
|
59
|
+
expect(encoded).toBe(expected)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('base64url alphabet', () => {
|
|
65
|
+
for (const string of [
|
|
66
|
+
'',
|
|
67
|
+
'\0\0',
|
|
68
|
+
'\0\0\0',
|
|
69
|
+
'\0\0\0\0',
|
|
70
|
+
'__',
|
|
71
|
+
'é',
|
|
72
|
+
'àç',
|
|
73
|
+
'\0éàç',
|
|
74
|
+
'```\x1b',
|
|
75
|
+
'aaa',
|
|
76
|
+
'Hello, World!',
|
|
77
|
+
'😀😃😄😁😆😅😂🤣😊😇',
|
|
78
|
+
'👩💻👨💻👩🔬👨🔬👩🚀👨🚀',
|
|
79
|
+
'🌍🌎🌏🌐🪐🌟✨⚡🔥💧',
|
|
80
|
+
] as const) {
|
|
81
|
+
const buffer = Buffer.from(string, 'utf8')
|
|
82
|
+
const expected = buffer.toString('base64url')
|
|
83
|
+
|
|
84
|
+
it(`encodes ${JSON.stringify(string)} as ${JSON.stringify(expected)}`, () => {
|
|
85
|
+
const encoded = toBase64(buffer, 'base64url')
|
|
86
|
+
expect(encoded).toBe(expected)
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('base64 vs base64url character differences', () => {
|
|
92
|
+
// Test data that produces + and / in standard base64
|
|
93
|
+
// These should become - and _ in base64url
|
|
94
|
+
it('uses + and / for base64 alphabet', () => {
|
|
95
|
+
// 0xfb, 0xff, 0xbf produces "+/+/" in base64
|
|
96
|
+
const bytes = new Uint8Array([0xfb, 0xff, 0xbf])
|
|
97
|
+
const encoded = toBase64(bytes)
|
|
98
|
+
expect(encoded).toContain('+')
|
|
99
|
+
expect(encoded).toContain('/')
|
|
100
|
+
expect(encoded).not.toContain('-')
|
|
101
|
+
expect(encoded).not.toContain('_')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('uses - and _ for base64url alphabet', () => {
|
|
105
|
+
// Same bytes should use - and _ in base64url
|
|
106
|
+
const bytes = new Uint8Array([0xfb, 0xff, 0xbf])
|
|
107
|
+
const encoded = toBase64(bytes, 'base64url')
|
|
108
|
+
expect(encoded).toContain('-')
|
|
109
|
+
expect(encoded).toContain('_')
|
|
110
|
+
expect(encoded).not.toContain('+')
|
|
111
|
+
expect(encoded).not.toContain('/')
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('padding behavior', () => {
|
|
116
|
+
it('omits padding by default for 1-byte input', () => {
|
|
117
|
+
// 1 byte -> 2 base64 chars + 2 padding
|
|
118
|
+
const bytes = new Uint8Array([0x4d]) // 'M' -> 'TQ=='
|
|
119
|
+
const encoded = toBase64(bytes)
|
|
120
|
+
expect(encoded).toBe('TQ')
|
|
121
|
+
expect(encoded).not.toContain('=')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('omits padding by default for 2-byte input', () => {
|
|
125
|
+
// 2 bytes -> 3 base64 chars + 1 padding
|
|
126
|
+
const bytes = new Uint8Array([0x4d, 0x61]) // 'Ma' -> 'TWE='
|
|
127
|
+
const encoded = toBase64(bytes)
|
|
128
|
+
expect(encoded).toBe('TWE')
|
|
129
|
+
expect(encoded).not.toContain('=')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('no padding needed for 3-byte input', () => {
|
|
133
|
+
// 3 bytes -> 4 base64 chars, no padding needed
|
|
134
|
+
const bytes = new Uint8Array([0x4d, 0x61, 0x6e]) // 'Man' -> 'TWFu'
|
|
135
|
+
const encoded = toBase64(bytes)
|
|
136
|
+
expect(encoded).toBe('TWFu')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('includes double padding when omitPadding: false for 1-byte input', () => {
|
|
140
|
+
const bytes = new Uint8Array([0x4d]) // 'M' -> 'TQ=='
|
|
141
|
+
const encoded = toBase64(bytes)
|
|
142
|
+
expect(encoded).toBe('TQ')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('includes single padding when omitPadding: false for 2-byte input', () => {
|
|
146
|
+
const bytes = new Uint8Array([0x4d, 0x61]) // 'Ma' -> 'TWE='
|
|
147
|
+
const encoded = toBase64(bytes)
|
|
148
|
+
expect(encoded).toBe('TWE')
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('Uint8Array subarray handling', () => {
|
|
153
|
+
it('correctly encodes a subarray', () => {
|
|
154
|
+
const fullArray = new Uint8Array([0x00, 0x4d, 0x61, 0x6e, 0x00])
|
|
155
|
+
const subarray = fullArray.subarray(1, 4) // 'Man'
|
|
156
|
+
const encoded = toBase64(subarray)
|
|
157
|
+
expect(encoded).toBe('TWFu')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('correctly encodes a subarray with offset', () => {
|
|
161
|
+
const buffer = new ArrayBuffer(10)
|
|
162
|
+
const fullView = new Uint8Array(buffer)
|
|
163
|
+
fullView.set([0x00, 0x00, 0x4d, 0x61, 0x6e, 0x00, 0x00])
|
|
164
|
+
const subarray = new Uint8Array(buffer, 2, 3) // 'Man' at offset 2
|
|
165
|
+
const encoded = toBase64(subarray)
|
|
166
|
+
expect(encoded).toBe('TWFu')
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toString } from 'uint8arrays/to-string'
|
|
2
2
|
import { NodeJSBuffer } from './lib/nodejs-buffer.js'
|
|
3
|
+
import { Base64Alphabet } from './uint8array-base64.js'
|
|
3
4
|
|
|
4
5
|
const Buffer = NodeJSBuffer
|
|
5
6
|
|
|
@@ -18,16 +19,22 @@ declare global {
|
|
|
18
19
|
|
|
19
20
|
export const toBase64Native =
|
|
20
21
|
typeof Uint8Array.prototype.toBase64 === 'function'
|
|
21
|
-
? function toBase64Native(
|
|
22
|
-
|
|
22
|
+
? function toBase64Native(
|
|
23
|
+
bytes: Uint8Array,
|
|
24
|
+
alphabet: Base64Alphabet = 'base64',
|
|
25
|
+
): string {
|
|
26
|
+
return bytes.toBase64!({ alphabet, omitPadding: true })
|
|
23
27
|
}
|
|
24
28
|
: null
|
|
25
29
|
|
|
26
30
|
export const toBase64Node = Buffer
|
|
27
|
-
? function toBase64Node(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
? function toBase64Node(
|
|
32
|
+
bytes: Uint8Array,
|
|
33
|
+
alphabet: Base64Alphabet = 'base64',
|
|
34
|
+
): string {
|
|
35
|
+
const buffer = bytes instanceof Buffer ? bytes : Buffer.from(bytes)
|
|
36
|
+
const b64 = buffer.toString(alphabet)
|
|
37
|
+
|
|
31
38
|
// @NOTE We strip padding for strict compatibility with
|
|
32
39
|
// uint8arrays.toString behavior. Tests failing because of the presence of
|
|
33
40
|
// padding are not really synonymous with an actual error and we might
|
|
@@ -40,6 +47,9 @@ export const toBase64Node = Buffer
|
|
|
40
47
|
}
|
|
41
48
|
: null
|
|
42
49
|
|
|
43
|
-
export function toBase64Ponyfill(
|
|
44
|
-
|
|
50
|
+
export function toBase64Ponyfill(
|
|
51
|
+
bytes: Uint8Array,
|
|
52
|
+
alphabet: Base64Alphabet = 'base64',
|
|
53
|
+
): string {
|
|
54
|
+
return toString(bytes, alphabet)
|
|
45
55
|
}
|
package/src/uint8array.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Base64Alphabet } from './uint8array-base64.js'
|
|
1
2
|
import {
|
|
2
3
|
fromBase64Native,
|
|
3
4
|
fromBase64Node,
|
|
@@ -9,6 +10,8 @@ import {
|
|
|
9
10
|
toBase64Ponyfill,
|
|
10
11
|
} from './uint8array-to-base64.js'
|
|
11
12
|
|
|
13
|
+
export type { Base64Alphabet }
|
|
14
|
+
|
|
12
15
|
// @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /
|
|
13
16
|
// Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /
|
|
14
17
|
// toBase64 as deprecated. We can also drop NodeJS specific implementations
|
|
@@ -19,17 +22,22 @@ import {
|
|
|
19
22
|
*
|
|
20
23
|
* @returns The base64 encoded string
|
|
21
24
|
*/
|
|
22
|
-
export const toBase64: (
|
|
23
|
-
|
|
25
|
+
export const toBase64: (
|
|
26
|
+
bytes: Uint8Array,
|
|
27
|
+
alphabet?: Base64Alphabet,
|
|
28
|
+
) => string = toBase64Native ?? toBase64Node ?? toBase64Ponyfill
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
|
-
* Decodes a base64 string into a Uint8Array.
|
|
31
|
+
* Decodes a base64 string into a Uint8Array. This function supports both padded
|
|
32
|
+
* and unpadded base64 strings.
|
|
27
33
|
*
|
|
28
34
|
* @returns The decoded {@link Uint8Array}
|
|
29
35
|
* @throws If the input is not a valid base64 string
|
|
30
36
|
*/
|
|
31
|
-
export const fromBase64: (
|
|
32
|
-
|
|
37
|
+
export const fromBase64: (
|
|
38
|
+
b64: string,
|
|
39
|
+
alphabet?: Base64Alphabet,
|
|
40
|
+
) => Uint8Array = fromBase64Native ?? fromBase64Node ?? fromBase64Ponyfill
|
|
33
41
|
|
|
34
42
|
if (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {
|
|
35
43
|
/*#__PURE__*/
|