{"id":27808387,"url":"https://github.com/jawj/hextreme","last_synced_at":"2025-05-01T10:49:53.163Z","repository":{"id":262669385,"uuid":"887984676","full_name":"jawj/hextreme","owner":"jawj","description":"Fast hex and base64 encoding and decoding, string \u003c-\u003e Uint8Array","archived":false,"fork":false,"pushed_at":"2025-03-14T17:00:47.000Z","size":403,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-24T00:49:06.086Z","etag":null,"topics":["base64","base64url","decoding","encoding","fast","frombase64","fromhex","hex","javascript","loop-unrolling","tobase64","tohex","typescript","uint8array"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jawj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-13T16:05:56.000Z","updated_at":"2025-03-27T06:41:56.000Z","dependencies_parsed_at":"2024-12-05T10:24:41.738Z","dependency_job_id":"8c7d255b-dc69-488b-9a48-45d1df61af8b","html_url":"https://github.com/jawj/hextreme","commit_stats":null,"previous_names":["jawj/fasthex"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fhextreme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fhextreme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fhextreme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fhextreme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jawj","download_url":"https://codeload.github.com/jawj/hextreme/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251693322,"owners_count":21628651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base64","base64url","decoding","encoding","fast","frombase64","fromhex","hex","javascript","loop-unrolling","tobase64","tohex","typescript","uint8array"],"created_at":"2025-05-01T10:49:52.637Z","updated_at":"2025-05-01T10:49:53.156Z","avatar_url":"https://github.com/jawj.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hextreme\n\nHex and base64 string encoding and decoding for `Uint8Array` — like native [`.toHex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex)/[`.fromHex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromHex) and [`.toBase64()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64)/[`.fromBase64()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64), which are not yet widely supported.\n\nIntended to be as fast as reasonably possible using only plain JavaScript. The secret ingredients are: \n\n* Conversion between strings and typed arrays via `TextEncoder`, `TextDecoder`\n* Multi-byte reads, writes and lookups using `Uint16Array`, `Uint32Array`\n* A little bit of loop unrolling (which can make a difference in Chrome/V8)\n\nComprehensive tests. No external dependencies. ESM and CJS exports, plus TypeScript types. 4KB zipped.\n\n\n## Performance\n\nThe following benchmarks were run on an M3 Pro MacBook Pro, using 32 MiB of random data, and taking the mean of 10 trials.\n\nOn this machine, across methods and browsers, the headlines are that we are:\n\n* 4 – 36x **faster** than a representative JS implementation: the [feross/buffer](https://github.com/feross) shim package\n* 3 – 7x **faster** than Firefox's native methods (surprising — Firefox can surely improve on this)\n* 5 – 16x **slower** than Safari's native methods\n\n```\n                                   Chrome          Firefox             Safari\n                            131.0.6778.86            133.0   Tech Preview 209\n\n* Encode hex\n\nThis library                     22.59 ms         26.20 ms           44.10 ms\ncf. native toHex                        -        126.20 ms: x5        5.80 ms: /8                                                          \ncf. feross/buffer.toString      813.48 ms: x36   209.50 ms: x8      368.70 ms: x8\n\n* Decode hex\n\nThis library                     60.22 ms         32.60 ms           92.40 ms\ncf. native fromHex                      -        229.40 ms: x7        5.80 ms: /16\ncf. feross/buffer.from          757.89 ms: x13   546.60 ms: x17    1371.60 ms: x15\n\n* Encode base64\n\nThis library                     16.86 ms         20.90 ms           42.60 ms\ncf. native toBase64                     -         84.00 ms: x4        3.60 ms: /12\ncf. feross/buffer.toString      275.85 ms: x16   203.80 ms: x10     550.30 ms: x13\n\n* Decode base64\n\nThis library                     52.02 ms         36.60 ms           23.90 ms\ncf. native fromBase64                   -        123.00 ms: x3        4.60 ms: /5\ncf. feross/buffer.from          200.80 ms: x4    248.10 ms: x7      281.70 ms: x12\n```\n\n## Usage\n\nTo install:\n\n```bash\nnpm install hextreme\n```\n\n### Hex encoding\n\n`toHex(bytes: Uint8Array, { alphabet?: 'lower' | 'upper' } = {}): string`\n\nEncodes binary data to a hex string. \n\nThe `alphabet` option defaults to `'lower'`, but may alternatively be set to `'upper'`.\n\nExamples:\n\n```javascript\nimport { toHex } from 'hextreme';\n\ntoHex(new Uint8Array([254, 237, 250, 206]));\n// 'feedface'\n\ntoHex(new Uint8Array([254, 237, 250, 206]), { alphabet: 'upper' });\n// 'FEEDFACE'\n```\n\n### Hex decoding\n\n`fromHex(hex: string, { onInvalidInput?: 'throw' | 'truncate' } = {}): Uint8Array`\n\nDecodes a hex string (upper-, lower- or mixed-case) to binary data.\n\nThe `onInvalidInput` option defaults to `'throw'`, in which case any non-hex character in the input causes an error to be thrown. This matches the behaviour of `toHex()` on a `Uint8Array` (where supported).\n\n`onInvalidInput` may otherwise be set to `'truncate'`, in which case decoding stops at the first non-hex character pair encountered. This matches the behaviour of `toString('hex')` on a Node `Buffer`.\n\nExamples:\n\n```javascript\nimport { fromHex } from 'hextreme';\n\nfromHex('FEEDface');\n// Uint8Array(4) [ 254, 237, 250, 206 ]\n\nfromHex('FEEDfXce');\n// Uncaught Error: Invalid pair in hex input at index 4\n\nfromHex('FEEDfXce', { onInvalidInput: 'truncate' });\n// Uint8Array(2) [ 254, 237 ]\n```\n\n### Base64 encoding\n\n`toBase64(bytes: Uint8Array, { alphabet?: 'base64' | 'base64url', omitPadding?: boolean } = {}): string;`\n\nEncodes binary data to a base64 string.\n\nThe `alphabet` option defaults to `'base64'`. It may alternatively be set to `'base64url'`, in which case the `+` and `/` characters are replaced with `-` and `_`.\n\nThe `omitPadding` option defaults to `false`, so that the output string is padded to a multiple of 4 characters using the `=` character. It can be set to `true` to prevent padding being applied.\n\nExamples:\n\n```javascript\nimport { toBase64 } from 'hextreme';\n\nconst bytes = new Uint8Array([133, 233, 101, 163, 255, 191, 194, 138, 229, 116]);\n\ntoBase64(bytes);\n// 'hello/+/worldA=='\n\ntoBase64(bytes, { alphabet: 'base64url' });\n// 'hello_-_worldA=='\n\ntoBase64(bytes, { alphabet: 'base64url', omitPadding: true });\n// 'hello_-_worldA'\n```\n\n### Base64 decoding\n\n`fromBase64(base64: string, { alphabet?: 'base64' | 'base64url' | 'base64any', onInvalidInput?: 'throw' | 'skip' } = {}): Uint8Array;`\n\nDecodes a base64 string to binary data. Whitespace in the input string (spaces, tabs, `\\r` and `\\n`) is ignored.\n\nThe `alphabet` option defaults to `'base64'`, but may alternatively be set to `'base64url'`, in which case `-` and `_` are expected instead of `+` and `/`, or `'base64any'`, in which case both alternatives are recognised.\n\nThe `onInvalidInput` option defaults to `'throw'`, in which case any non-base64, non-whitespace character in the input causes an error to be thrown. This matches the behaviour of `toBase64()` on a `Uint8Array` (where available).\n\n`onInvalidInput` may otherwise be set to `'skip'`, in which case any non-base64 characters are skipped and decoding continues (apart from `=`, which ends decoding). This matches the behaviour of `toString('base64')` on a Node `Buffer`.\n\n_Note that decoding becomes roughly 2x slower if whitespace or invalid characters are encountered in the input string._\n\nExamples:\n\n```javascript\nimport { fromBase64 } from 'hextreme';\n\nfromBase64('hello/+/worldA==');\n// Uint8Array(10) [ 133, 233, 101, 163, 255, 191, 194, 138, 229, 116 ]\n\nfromBase64('hello/+/worldA');\n// Uint8Array(10) [ 133, 233, 101, 163, 255, 191, 194, 138, 229, 116 ]\n\nfromBase64('hello_-_worldA==', { alphabet: 'base64url' });\n// Uint8Array(10) [ 133, 233, 101, 163, 255, 191, 194, 138, 229, 116 ]\n\nfromBase64('hello_+_worldA==', { alphabet: 'base64any' });\n// Uint8Array(10) [ 133, 233, 101, 163, 255, 191, 194, 138, 229, 116 ]\n\nfromBase64('hello/:+/worldA==');\n// Uncaught Error: Invalid character in base64 at index 6\n\nfromBase64('hello/:+/worldA==', { onInvalidInput: 'skip' });\n// Uint8Array(10) [ 133, 233, 101, 163, 255, 191, 194, 138, 229, 116 ]\n```\n\n## Development\n\nThe source is in `src`. To build: `npm run build`.\n\nTo run tests: `npm run test`. To run a subset of tests on a big-endian platform (which has some different code paths), see [big-endian/README.md](big-endian/README.md).\n\nTo run benchmarks: `npm run perfCli` (for Node and Bun) and `npm run perfBrowser`.\n\n## Licence\n\nCopyright (C) 2024 George MacKerron and released under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawj%2Fhextreme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjawj%2Fhextreme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawj%2Fhextreme/lists"}