├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .yarn └── releases │ └── yarn-4.1.1.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── benchmarks ├── base58.js ├── dataview.js ├── msgpack-decode-complex.js ├── msgpack-decode.js ├── msgpack-encode-complex.js ├── msgpack-encode.js └── utf8-decode.js ├── package.json ├── packages ├── base-codec │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decoder.ts │ │ ├── encoder.ts │ │ └── index.ts │ └── tsconfig.json ├── base10 │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decode.ts │ │ ├── encode.ts │ │ ├── index.ts │ │ └── util.ts │ ├── tests │ │ └── codec.spec.ts │ └── tsconfig.json ├── base58 │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decode.ts │ │ ├── encode.ts │ │ ├── index.ts │ │ └── util.ts │ ├── tests │ │ └── codec.spec.ts │ └── tsconfig.json ├── base62 │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decode.ts │ │ ├── encode.ts │ │ ├── index.ts │ │ └── util.ts │ ├── tests │ │ └── codec.spec.ts │ └── tsconfig.json ├── json │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decoder.ts │ │ ├── encoder.ts │ │ └── index.ts │ ├── tests │ │ └── codec.spec.ts │ └── tsconfig.json ├── msgpack │ ├── .gitattributes │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ │ ├── decoder.bs.js │ │ ├── decoder.res │ │ ├── decoder.ts │ │ ├── encoder.ts │ │ ├── ext │ │ │ ├── TimestampDecoder.ts │ │ │ ├── TimestampEncoder.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── tests │ │ ├── codec.spec.ts │ │ └── decode-complex.spec.ts │ └── tsconfig.json └── qrjson │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ ├── decoder.ts │ ├── encoder.ts │ └── index.ts │ ├── tests │ └── codec.spec.ts │ └── tsconfig.json ├── tsconfig.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [], 6 | "access": "restricted", 7 | "baseBranch": "main", 8 | "updateInternalDependencies": "patch", 9 | "ignore": [] 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | charset = utf-8 3 | 4 | [*.ts] 5 | indent_size = 2 6 | indent_style = space 7 | insert_final_newline = true -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .yarn/** linguist-vendored 2 | .yarn/releases/* binary 3 | .yarn/plugins/* binary 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: 7 | - main 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | test: 14 | name: Test packages 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - uses: actions/setup-node@v4 20 | with: 21 | node-version: 20 22 | cache: yarn 23 | 24 | - name: Install dependencies 25 | shell: bash 26 | run: | 27 | yarn install --immutable 28 | 29 | - name: Build and validate packages 30 | run: | 31 | yarn workspaces foreach --worktree --interlaced --topological run build 32 | 33 | - name: Run all tests 34 | run: | 35 | yarn test 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | pull-requests: write 15 | steps: 16 | - name: Checkout Repo 17 | uses: actions/checkout@v4 18 | with: 19 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 20 | fetch-depth: 0 21 | 22 | - name: Setup Node.js 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: 20 26 | cache: yarn 27 | 28 | - name: Install Dependencies 29 | run: yarn install --immutable 30 | 31 | - name: Create Release Pull Request 32 | uses: cometkim/yarn-changeset-action@v1 33 | with: 34 | autoPublish: true 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | *.tsbuildinfo 4 | 5 | node_modules/ 6 | 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/releases 10 | !.yarn/plugins 11 | !.yarn/sdks 12 | !.yarn/versions 13 | .pnp.* 14 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nmMode: hardlinks-global 2 | 3 | nodeLinker: node-modules 4 | 5 | yarnPath: .yarn/releases/yarn-4.1.1.cjs 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # urlpack 2 | 3 | Pure JavaScript toolkit for data URLs 4 | 5 | - [json](packages/json): Compress JSON data into compact & URL-safe format 6 | - [qrjson](packages/qrjson): Compress JSON data into compact & suitable for numeric QR Codes format 7 | - [msgpack](packages/msgpack): Lightweight & Full-featured MessagePack implementation 8 | - [base-codec](packages/base-codec): Base-N codec generator 9 | - [base10](packages/base10): Base10 codec (0~9) 10 | - [base58](packages/base58): Base58 codec (Bitcoin flavored) 11 | - [base62](packages/base62): Base62 codec 12 | 13 | ## LICENSE 14 | 15 | MIT 16 | -------------------------------------------------------------------------------- /benchmarks/base58.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | import { makeBaseEncoder, makeBaseDecoder } from '@urlpack/base-codec'; 5 | import baseXCodec from 'base-x'; 6 | import * as base58js from 'base58-js'; 7 | 8 | const baseAlphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 9 | const urlpack = { 10 | ...makeBaseEncoder(baseAlphabet), 11 | ...makeBaseDecoder(baseAlphabet), 12 | }; 13 | const baseX = baseXCodec(baseAlphabet); 14 | 15 | const buffer = Buffer.from(` 16 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 17 | `); 18 | const text = urlpack.encode(buffer); 19 | 20 | new Benchmark.Suite() 21 | .add('@urlpack/base-codec encode', () => { 22 | urlpack.encode(buffer); 23 | }) 24 | .add('@urlpack/base-codec decode', () => { 25 | urlpack.decode(text); 26 | }) 27 | .add('base-x encode', () => { 28 | baseX.encode(buffer); 29 | }) 30 | .add('base-x decode', () => { 31 | baseX.decode(text); 32 | }) 33 | .add('base58-js encode', () => { 34 | base58js.binary_to_base58(buffer); 35 | }) 36 | .add('base58-js decode', () => { 37 | base58js.base58_to_binary(text); 38 | }) 39 | .on('cycle', event => { 40 | console.log(event.target.toString()); 41 | }) 42 | .run(); 43 | -------------------------------------------------------------------------------- /benchmarks/dataview.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | const bin = new Uint8Array(Array(10000).fill(0)); 5 | const staticView = new DataView(bin.buffer); 6 | const staticViewOffset = new DataView(bin.buffer, 5000); 7 | 8 | new Benchmark.Suite() 9 | .add('direct access', () => { 10 | bin[5000] 11 | }) 12 | .add('dataview from offset (static)', () => { 13 | staticViewOffset.getUint8(0) 14 | }) 15 | .add('dataview from offset', () => { 16 | let view = new DataView(bin.buffer, 5000) 17 | view.getUint8(0) 18 | }) 19 | .add('dataview get offset (static)', () => { 20 | staticView.getUint8(0, 5000) 21 | }) 22 | .add('dataview get offset', () => { 23 | let view = new DataView(bin.buffer) 24 | view.getUint8(0, 5000) 25 | }) 26 | .on('cycle', event => { 27 | console.log(event.target.toString()); 28 | }) 29 | .run(); 30 | -------------------------------------------------------------------------------- /benchmarks/msgpack-decode-complex.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | import { makeMessagePackDecoder } from '@urlpack/msgpack'; 5 | const urlpack = makeMessagePackDecoder(); 6 | 7 | import msgpack from '@msgpack/msgpack'; 8 | 9 | import _msgpack5 from 'msgpack5'; 10 | const msgpack5 = _msgpack5(); 11 | 12 | import msgpackLite from 'msgpack-lite'; 13 | 14 | import * as msgpackr from 'msgpackr'; 15 | 16 | const complex1 = new Uint8Array([0x82, 0xa1, 0x61, 0x81, 0xa1, 0x62, 0xa1, 0x63, 0xa1, 0x63, 0x94, 0xc0, 0xc0, 0xc0, 0x81, 0xa1, 0x64, 0xa1, 0x63]); 17 | const complex2 = new Uint8Array([0x88, 0xa3, 0x69, 0x6e, 0x74, 0x1, 0xa5, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0xcb, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa7, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0xc3, 0xa4, 0x6e, 0x75, 0x6c, 0x6c, 0xc0, 0xa6, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa7, 0x66, 0x6f, 0x6f, 0x20, 0x62, 0x61, 0x72, 0xa5, 0x61, 0x72, 0x72, 0x61, 0x79, 0x92, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72, 0xa6, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x82, 0xa3, 0x66, 0x6f, 0x6f, 0x1, 0xa3, 0x62, 0x61, 0x7a, 0xcb, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa4, 0x64, 0x61, 0x74, 0x65, 0xd7, 0xff, 0xbe, 0x7f, 0x17, 0x0, 0x60, 0xf8, 0x3c, 0x5f]); 18 | 19 | new Benchmark.Suite() 20 | .add('warmup', () => { 21 | urlpack.decode(complex1); 22 | msgpack.decode(complex1); 23 | msgpack5.decode(complex1); 24 | msgpackLite.decode(complex1); 25 | msgpackr.decode(complex1); 26 | }) 27 | .add('decode complex 1 - @urlpack/msgpack', () => { 28 | urlpack.decode(complex1); 29 | }) 30 | .add('decode complex 1 - @msgpack/msgpack', () => { 31 | msgpack.decode(complex1); 32 | }) 33 | .add('decode complex 1 - msgpack5', () => { 34 | msgpack5.decode(complex1); 35 | }) 36 | .add('decode complex 1 - msgpack-lite', () => { 37 | msgpackLite.decode(complex1); 38 | }) 39 | .add('decode complex 1 - msgpackr', () => { 40 | msgpackr.decode(complex1); 41 | }) 42 | .add('decode complex 2 - @urlpack/msgpack', () => { 43 | urlpack.decode(complex2); 44 | }) 45 | .add('decode complex 2 - @msgpack/msgpack', () => { 46 | msgpack.decode(complex2); 47 | }) 48 | .add('decode complex 2 - msgpack5', () => { 49 | msgpack5.decode(complex2); 50 | }) 51 | .add('decode complex 2 - msgpack-lite', () => { 52 | msgpackLite.decode(complex2); 53 | }) 54 | .add('decode complex 2 - msgpackr', () => { 55 | msgpackr.decode(complex2); 56 | }) 57 | .on('cycle', event => { 58 | console.log(event.target.toString()); 59 | }) 60 | .run(); 61 | -------------------------------------------------------------------------------- /benchmarks/msgpack-decode.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | import { makeMessagePackDecoder } from '@urlpack/msgpack'; 5 | const urlpack = makeMessagePackDecoder(); 6 | 7 | import msgpack from '@msgpack/msgpack'; 8 | 9 | import _msgpack5 from 'msgpack5'; 10 | const msgpack5 = _msgpack5(); 11 | 12 | import msgpackLite from 'msgpack-lite'; 13 | 14 | import * as msgpackr from 'msgpackr'; 15 | 16 | new Benchmark.Suite() 17 | .add('decode misc - @urlpack/msgpack', () => { 18 | urlpack.decode(new Uint8Array([0])); 19 | urlpack.decode(new Uint8Array([0xc0])); 20 | urlpack.decode(new Uint8Array([0xc3])); 21 | urlpack.decode(new Uint8Array([0xc2])); 22 | }) 23 | .add('decode misc - @msgpack/msgpack', () => { 24 | msgpack.decode(new Uint8Array([0])); 25 | msgpack.decode(new Uint8Array([0xc0])); 26 | msgpack.decode(new Uint8Array([0xc3])); 27 | msgpack.decode(new Uint8Array([0xc2])); 28 | }) 29 | .add('decode misc - msgpack5', () => { 30 | msgpack5.decode(new Uint8Array([0])); 31 | msgpack5.decode(new Uint8Array([0xc0])); 32 | msgpack5.decode(new Uint8Array([0xc3])); 33 | msgpack5.decode(new Uint8Array([0xc2])); 34 | }) 35 | .add('decode misc - msgpack-lite', () => { 36 | msgpackLite.decode(new Uint8Array([0])); 37 | msgpackLite.decode(new Uint8Array([0xc0])); 38 | msgpackLite.decode(new Uint8Array([0xc3])); 39 | msgpackLite.decode(new Uint8Array([0xc2])); 40 | }) 41 | .add('decode misc - msgpackr', () => { 42 | msgpackr.decode(new Uint8Array([0])); 43 | msgpackr.decode(new Uint8Array([0xc0])); 44 | msgpackr.decode(new Uint8Array([0xc3])); 45 | msgpackr.decode(new Uint8Array([0xc2])); 46 | }) 47 | .add('decode positive int - @urlpack/msgpack', () => { 48 | urlpack.decode(new Uint8Array([0x01])); 49 | urlpack.decode(new Uint8Array([0xcd, 0x01, 0x00])); 50 | urlpack.decode(new Uint8Array([0xce, 0x00, 0x01, 0x00, 0x00])); 51 | urlpack.decode(new Uint8Array([0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])); 52 | urlpack.decode(new Uint8Array([0xcf, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 53 | }) 54 | .add('decode positive int - @msgpack/msgpack', () => { 55 | msgpack.decode(new Uint8Array([0x01])); 56 | msgpack.decode(new Uint8Array([0xcd, 0x01, 0x00])); 57 | msgpack.decode(new Uint8Array([0xce, 0x00, 0x01, 0x00, 0x00])); 58 | msgpack.decode(new Uint8Array([0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])); 59 | msgpack.decode(new Uint8Array([0xcf, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 60 | }) 61 | .add('decode positive int - msgpack5', () => { 62 | msgpack5.decode(new Uint8Array([0x01])); 63 | msgpack5.decode(new Uint8Array([0xcd, 0x01, 0x00])); 64 | msgpack5.decode(new Uint8Array([0xce, 0x00, 0x01, 0x00, 0x00])); 65 | msgpack5.decode(new Uint8Array([0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])); 66 | msgpack5.decode(new Uint8Array([0xcf, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 67 | }) 68 | .add('decode positive int - msgpack-lite', () => { 69 | msgpackLite.decode(new Uint8Array([0x01])); 70 | msgpackLite.decode(new Uint8Array([0xcd, 0x01, 0x00])); 71 | msgpackLite.decode(new Uint8Array([0xce, 0x00, 0x01, 0x00, 0x00])); 72 | msgpackLite.decode(new Uint8Array([0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])); 73 | msgpackLite.decode(new Uint8Array([0xcf, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 74 | }) 75 | .add('decode positive int - msgpackr', () => { 76 | msgpackr.decode(new Uint8Array([0x01])); 77 | msgpackr.decode(new Uint8Array([0xcd, 0x01, 0x00])); 78 | msgpackr.decode(new Uint8Array([0xce, 0x00, 0x01, 0x00, 0x00])); 79 | msgpackr.decode(new Uint8Array([0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])); 80 | msgpackr.decode(new Uint8Array([0xcf, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 81 | }) 82 | .add('decode negative int - @urlpack/msgpack', () => { 83 | urlpack.decode(new Uint8Array([0xff])); 84 | urlpack.decode(new Uint8Array([0xd1, 0xff, 0x00])); 85 | urlpack.decode(new Uint8Array([0xd2, 0xff, 0xff, 0x00, 0x00])); 86 | urlpack.decode(new Uint8Array([0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00])); 87 | urlpack.decode(new Uint8Array([0xd3, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])); 88 | }) 89 | .add('decode negative int - @msgpack/msgpack', () => { 90 | msgpack.decode(new Uint8Array([0xff])); 91 | msgpack.decode(new Uint8Array([0xd1, 0xff, 0x00])); 92 | msgpack.decode(new Uint8Array([0xd2, 0xff, 0xff, 0x00, 0x00])); 93 | msgpack.decode(new Uint8Array([0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00])); 94 | msgpack.decode(new Uint8Array([0xd3, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])); 95 | }) 96 | .add('decode negative int - msgpack5', () => { 97 | msgpack5.decode(new Uint8Array([0xff])); 98 | msgpack5.decode(new Uint8Array([0xd1, 0xff, 0x00])); 99 | msgpack5.decode(new Uint8Array([0xd2, 0xff, 0xff, 0x00, 0x00])); 100 | msgpack5.decode(new Uint8Array([0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00])); 101 | msgpack5.decode(new Uint8Array([0xd3, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])); 102 | }) 103 | .add('decode negative int - msgpack-lite', () => { 104 | msgpackLite.decode(new Uint8Array([0xff])); 105 | msgpackLite.decode(new Uint8Array([0xd1, 0xff, 0x00])); 106 | msgpackLite.decode(new Uint8Array([0xd2, 0xff, 0xff, 0x00, 0x00])); 107 | msgpackLite.decode(new Uint8Array([0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00])); 108 | msgpackLite.decode(new Uint8Array([0xd3, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])); 109 | }) 110 | .add('decode negative int - msgpackr', () => { 111 | msgpackr.decode(new Uint8Array([0xff])); 112 | msgpackr.decode(new Uint8Array([0xd1, 0xff, 0x00])); 113 | msgpackr.decode(new Uint8Array([0xd2, 0xff, 0xff, 0x00, 0x00])); 114 | msgpackr.decode(new Uint8Array([0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00])); 115 | msgpackr.decode(new Uint8Array([0xd3, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])); 116 | }) 117 | .add('decode float - @urlpack/msgpack', () => { 118 | urlpack.decode(new Uint8Array([0xca, 0x3f, 0x00, 0x00, 0x00])); 119 | urlpack.decode(new Uint8Array([0xcb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])); 120 | urlpack.decode(new Uint8Array([0xcb, 0x3f, 0xf5, 0x64, 0x5a, 0x1c, 0xac, 0x08, 0x31])); 121 | }) 122 | .add('decode float - @msgpack/msgpack', () => { 123 | msgpack.decode(new Uint8Array([0xca, 0x3f, 0x00, 0x00, 0x00])); 124 | msgpack.decode(new Uint8Array([0xcb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])); 125 | msgpack.decode(new Uint8Array([0xcb, 0x3f, 0xf5, 0x64, 0x5a, 0x1c, 0xac, 0x08, 0x31])); 126 | }) 127 | .add('decode float - msgpack5', () => { 128 | msgpack5.decode(new Uint8Array([0xca, 0x3f, 0x00, 0x00, 0x00])); 129 | msgpack5.decode(new Uint8Array([0xcb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])); 130 | msgpack5.decode(new Uint8Array([0xcb, 0x3f, 0xf5, 0x64, 0x5a, 0x1c, 0xac, 0x08, 0x31])); 131 | }) 132 | .add('decode float - msgpack-lite', () => { 133 | msgpackLite.decode(new Uint8Array([0xca, 0x3f, 0x00, 0x00, 0x00])); 134 | msgpackLite.decode(new Uint8Array([0xcb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])); 135 | msgpackLite.decode(new Uint8Array([0xcb, 0x3f, 0xf5, 0x64, 0x5a, 0x1c, 0xac, 0x08, 0x31])); 136 | }) 137 | .add('decode float - msgpackr', () => { 138 | msgpackr.decode(new Uint8Array([0xca, 0x3f, 0x00, 0x00, 0x00])); 139 | msgpackr.decode(new Uint8Array([0xcb, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])); 140 | msgpackr.decode(new Uint8Array([0xcb, 0x3f, 0xf5, 0x64, 0x5a, 0x1c, 0xac, 0x08, 0x31])); 141 | }) 142 | .add('decode str - @urlpack/msgpack', () => { 143 | urlpack.decode(new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21])); 144 | urlpack.decode(new Uint8Array([0xda, 0x01, 0x27, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x64, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x75, 0x69, 0x73, 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x6c, 0x65, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x20, 0x6c, 0x61, 0x63, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x61, 0x72, 0x63, 0x75, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x53, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x65, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x6e, 0x61, 0x72, 0x65, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x76, 0x69, 0x76, 0x65, 0x72, 0x72, 0x61, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x74, 0x75, 0x72, 0x70, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x63, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x75, 0x74, 0x2e])); 145 | }) 146 | .add('decode str - @msgpack/msgpack', () => { 147 | msgpack.decode(new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21])); 148 | msgpack.decode(new Uint8Array([0xda, 0x01, 0x27, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x64, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x75, 0x69, 0x73, 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x6c, 0x65, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x20, 0x6c, 0x61, 0x63, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x61, 0x72, 0x63, 0x75, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x53, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x65, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x6e, 0x61, 0x72, 0x65, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x76, 0x69, 0x76, 0x65, 0x72, 0x72, 0x61, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x74, 0x75, 0x72, 0x70, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x63, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x75, 0x74, 0x2e])); 149 | }) 150 | .add('decode str - msgpack5', () => { 151 | msgpack5.decode(new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21])); 152 | msgpack5.decode(new Uint8Array([0xda, 0x01, 0x27, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x64, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x75, 0x69, 0x73, 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x6c, 0x65, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x20, 0x6c, 0x61, 0x63, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x61, 0x72, 0x63, 0x75, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x53, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x65, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x6e, 0x61, 0x72, 0x65, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x76, 0x69, 0x76, 0x65, 0x72, 0x72, 0x61, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x74, 0x75, 0x72, 0x70, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x63, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x75, 0x74, 0x2e])); 153 | }) 154 | .add('decode str - msgpack-lite', () => { 155 | msgpackLite.decode(new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21])); 156 | msgpackLite.decode(new Uint8Array([0xda, 0x01, 0x27, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x64, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x75, 0x69, 0x73, 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x6c, 0x65, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x20, 0x6c, 0x61, 0x63, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x61, 0x72, 0x63, 0x75, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x53, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x65, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x6e, 0x61, 0x72, 0x65, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x76, 0x69, 0x76, 0x65, 0x72, 0x72, 0x61, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x74, 0x75, 0x72, 0x70, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x63, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x75, 0x74, 0x2e])); 157 | }) 158 | .add('decode str - msgpackr', () => { 159 | msgpackr.decode(new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21])); 160 | msgpackr.decode(new Uint8Array([0xda, 0x01, 0x27, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x64, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x75, 0x69, 0x73, 0x6d, 0x6f, 0x64, 0x2c, 0x20, 0x6c, 0x65, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x20, 0x6c, 0x61, 0x63, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x61, 0x72, 0x63, 0x75, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x53, 0x65, 0x64, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x65, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x6e, 0x61, 0x72, 0x65, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2e, 0x20, 0x45, 0x74, 0x69, 0x61, 0x6d, 0x20, 0x76, 0x69, 0x76, 0x65, 0x72, 0x72, 0x61, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x74, 0x75, 0x72, 0x70, 0x69, 0x73, 0x2c, 0x20, 0x61, 0x63, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x75, 0x74, 0x2e])); 161 | }) 162 | .add('decode bin - @urlpack/msgpack', () => { 163 | urlpack.decode(new Uint8Array([0xc4, 0xff, ...Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)])); 164 | }) 165 | .add('decode bin - @msgpack/msgpack', () => { 166 | msgpack.decode(new Uint8Array([0xc4, 0xff, ...Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)])); 167 | }) 168 | .add('decode bin - msgpack5', () => { 169 | msgpack5.decode(new Uint8Array([0xc4, 0xff, ...Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)])); 170 | }) 171 | .add('decode bin - msgpack-lite', () => { 172 | msgpackLite.decode(new Uint8Array([0xc4, 0xff, ...Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)])); 173 | }) 174 | .add('decode bin - msgpackr', () => { 175 | msgpackr.decode(new Uint8Array([0xc4, 0xff, ...Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)])); 176 | }) 177 | .add('decode fixarray - @urlpack/msgpack', () => { 178 | urlpack.decode(new Uint8Array([0x95, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0])); 179 | }) 180 | .add('decode fixarray - @msgpack/msgpack', () => { 181 | msgpack.decode(new Uint8Array([0x95, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0])); 182 | }) 183 | .add('decode fixarray - msgpack5', () => { 184 | msgpack5.decode(new Uint8Array([0x95, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0])); 185 | }) 186 | .add('decode fixarray - msgpack-lite', () => { 187 | msgpackLite.decode(new Uint8Array([0x95, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0])); 188 | }) 189 | .add('decode fixarray - msgpackr', () => { 190 | msgpackr.decode(new Uint8Array([0x95, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0])); 191 | }) 192 | .add('decode array 8 - @urlpack/msgpack', () => { 193 | urlpack.decode(new Uint8Array([0xdc, 0x01, 0x00, ...Array(2**8).fill(null)])); 194 | }) 195 | .add('decode array 8 - @msgpack/msgpack', () => { 196 | msgpack.decode(new Uint8Array([0xdc, 0x01, 0x00, ...Array(2**8).fill(null)])); 197 | }) 198 | .add('decode array 8 - msgpack5', () => { 199 | msgpack5.decode(new Uint8Array([0xdc, 0x01, 0x00, ...Array(2**8).fill(null)])); 200 | }) 201 | .add('decode array 8 - msgpack-lite', () => { 202 | msgpackLite.decode(new Uint8Array([0xdc, 0x01, 0x00, ...Array(2**8).fill(null)])); 203 | }) 204 | .add('decode array 8 - msgpackr', () => { 205 | msgpackr.decode(new Uint8Array([0xdc, 0x01, 0x00, ...Array(2**8).fill(null)])); 206 | }) 207 | .add('decode fixmap - @urlpack/msgpack', () => { 208 | urlpack.decode(new Uint8Array([0x85, 0xa1, 0x61, 0xc0, 0xa1, 0x62, 0xc0, 0xa1, 0x63, 0xc0, 0xa1, 0x64, 0xc0, 0xa1, 0x65, 0xc0])); 209 | }) 210 | .add('decode fixmap - @msgpack/msgpack', () => { 211 | msgpack.decode(new Uint8Array([0x85, 0xa1, 0x61, 0xc0, 0xa1, 0x62, 0xc0, 0xa1, 0x63, 0xc0, 0xa1, 0x64, 0xc0, 0xa1, 0x65, 0xc0])); 212 | }) 213 | .add('decode fixmap - msgpack5', () => { 214 | msgpack5.decode(new Uint8Array([0x85, 0xa1, 0x61, 0xc0, 0xa1, 0x62, 0xc0, 0xa1, 0x63, 0xc0, 0xa1, 0x64, 0xc0, 0xa1, 0x65, 0xc0])); 215 | }) 216 | .add('decode fixmap - msgpack-lite', () => { 217 | msgpackLite.decode(new Uint8Array([0x85, 0xa1, 0x61, 0xc0, 0xa1, 0x62, 0xc0, 0xa1, 0x63, 0xc0, 0xa1, 0x64, 0xc0, 0xa1, 0x65, 0xc0])); 218 | }) 219 | .add('decode fixmap - msgpackr', () => { 220 | msgpackr.decode(new Uint8Array([0x85, 0xa1, 0x61, 0xc0, 0xa1, 0x62, 0xc0, 0xa1, 0x63, 0xc0, 0xa1, 0x64, 0xc0, 0xa1, 0x65, 0xc0])); 221 | }) 222 | .on('cycle', event => { 223 | console.log(event.target.toString()); 224 | }) 225 | .run(); 226 | -------------------------------------------------------------------------------- /benchmarks/msgpack-encode-complex.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | import { makeMessagePackEncoder } from '@urlpack/msgpack'; 5 | const urlpack = makeMessagePackEncoder(); 6 | 7 | import msgpack from '@msgpack/msgpack'; 8 | 9 | import _msgpack5 from 'msgpack5' 10 | const msgpack5 = _msgpack5(); 11 | 12 | import msgpackLite from 'msgpack-lite'; 13 | 14 | import * as msgpackr from 'msgpackr'; 15 | 16 | const complex1 = { 17 | a: { b: 'c' }, 18 | c: [null, null, null, { d: 'c' }], 19 | }; 20 | const complex2 = { 21 | 'int': 1, 22 | 'float': 0.5, 23 | 'boolean': true, 24 | 'null': null, 25 | 'string': 'foo bar', 26 | 'array': [ 27 | 'foo', 28 | 'bar', 29 | ], 30 | 'object': { 31 | 'foo': 1, 32 | 'baz': 0.5, 33 | }, 34 | 'date': new Date(1626881119799), 35 | }; 36 | 37 | new Benchmark.Suite() 38 | .add('warmup', () => { 39 | urlpack.encode(complex1); 40 | msgpack.encode(complex1); 41 | msgpack5.encode(complex1); 42 | msgpackLite.encode(complex1); 43 | msgpackr.encode(complex1); 44 | }) 45 | .add('encode complex 1 - @urlpack/msgpack', () => { 46 | urlpack.encode(complex1); 47 | }) 48 | .add('encode complex 1 - @msgpack/msgpack', () => { 49 | msgpack.encode(complex1); 50 | }) 51 | .add('encode complex 1 - msgpack5', () => { 52 | msgpack5.encode(complex1); 53 | }) 54 | .add('encode complex 1 - msgpack-lite', () => { 55 | msgpackLite.encode(complex1); 56 | }) 57 | .add('encode complex 1 - msgpackr', () => { 58 | msgpackr.encode(complex1); 59 | }) 60 | .add('encode complex 2 - @urlpack/msgpack', () => { 61 | urlpack.encode(complex2); 62 | }) 63 | .add('encode complex 2 - @msgpack/msgpack', () => { 64 | msgpack.encode(complex2); 65 | }) 66 | .add('encode complex 2 - msgpack5', () => { 67 | msgpack5.encode(complex2); 68 | }) 69 | .add('encode complex 2 - msgpack-lite', () => { 70 | msgpackLite.encode(complex2); 71 | }) 72 | .add('encode complex 2 - msgpackr', () => { 73 | msgpackr.encode(complex2); 74 | }) 75 | .on('cycle', event => { 76 | console.log(event.target.toString()); 77 | }) 78 | .run(); 79 | -------------------------------------------------------------------------------- /benchmarks/msgpack-encode.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | import { makeMessagePackEncoder } from '@urlpack/msgpack'; 5 | const urlpack = makeMessagePackEncoder(); 6 | 7 | import msgpack from '@msgpack/msgpack'; 8 | 9 | import _msgpack5 from 'msgpack5' 10 | const msgpack5 = _msgpack5(); 11 | 12 | import msgpackLite from 'msgpack-lite'; 13 | 14 | import * as msgpackr from 'msgpackr'; 15 | 16 | new Benchmark.Suite() 17 | .add('encode misc - @urlpack/msgpack', () => { 18 | urlpack.encode(0); 19 | urlpack.encode(null); 20 | urlpack.encode(true); 21 | urlpack.encode(false); 22 | }) 23 | .add('encode misc - @msgpack/msgpack', () => { 24 | msgpack.encode(0); 25 | msgpack.encode(null); 26 | msgpack.encode(true); 27 | msgpack.encode(false); 28 | }) 29 | .add('encode misc - msgpack5', () => { 30 | msgpack5.encode(0); 31 | msgpack5.encode(null); 32 | msgpack5.encode(true); 33 | msgpack5.encode(false); 34 | }) 35 | .add('encode misc - msgpack-lite', () => { 36 | msgpackLite.encode(0); 37 | msgpackLite.encode(null); 38 | msgpackLite.encode(true); 39 | msgpackLite.encode(false); 40 | }) 41 | .add('encode misc - msgpackr', () => { 42 | msgpackr.encode(0); 43 | msgpackr.encode(null); 44 | msgpackr.encode(true); 45 | msgpackr.encode(false); 46 | }) 47 | .add('encode positive int - @urlpack/msgpack', () => { 48 | urlpack.encode(1); 49 | urlpack.encode(256); 50 | urlpack.encode(65536); 51 | urlpack.encode(4294967296); 52 | urlpack.encode(9007199254740991); 53 | }) 54 | .add('encode positive int - @msgpack/msgpack', () => { 55 | msgpack.encode(1); 56 | msgpack.encode(256); 57 | msgpack.encode(65536); 58 | msgpack.encode(4294967296); 59 | msgpack.encode(9007199254740991); 60 | }) 61 | .add('encode positive int - msgpack5', () => { 62 | msgpack5.encode(1); 63 | msgpack5.encode(256); 64 | msgpack5.encode(65536); 65 | msgpack5.encode(4294967296); 66 | msgpack5.encode(9007199254740991); 67 | }) 68 | .add('encode positive int - msgpack-lite', () => { 69 | msgpackLite.encode(1); 70 | msgpackLite.encode(256); 71 | msgpackLite.encode(65536); 72 | msgpackLite.encode(4294967296); 73 | msgpackLite.encode(9007199254740991); 74 | }) 75 | .add('encode positive int - msgpackr', () => { 76 | msgpackr.encode(1); 77 | msgpackr.encode(256); 78 | msgpackr.encode(65536); 79 | msgpackr.encode(4294967296); 80 | msgpackr.encode(9007199254740991); 81 | }) 82 | .add('encode negative int - @urlpack/msgpack', () => { 83 | urlpack.encode(-1); 84 | urlpack.encode(-256); 85 | urlpack.encode(-65536); 86 | urlpack.encode(-4294967296); 87 | urlpack.encode(-9007199254740991); 88 | }) 89 | .add('encode negative int - @msgpack/msgpack', () => { 90 | msgpack.encode(-1); 91 | msgpack.encode(-256); 92 | msgpack.encode(-65536); 93 | msgpack.encode(-4294967296); 94 | msgpack.encode(-9007199254740991); 95 | }) 96 | .add('encode negative int - msgpack5', () => { 97 | msgpack5.encode(-1); 98 | msgpack5.encode(-256); 99 | msgpack5.encode(-65536); 100 | msgpack5.encode(-4294967296); 101 | msgpack5.encode(-9007199254740991); 102 | }) 103 | .add('encode negative int - msgpack-lite', () => { 104 | msgpackLite.encode(-1); 105 | msgpackLite.encode(-256); 106 | msgpackLite.encode(-65536); 107 | msgpackLite.encode(-4294967296); 108 | msgpackLite.encode(-9007199254740991); 109 | }) 110 | .add('encode negative int - msgpackr', () => { 111 | msgpackr.encode(-1); 112 | msgpackr.encode(-256); 113 | msgpackr.encode(-65536); 114 | msgpackr.encode(-4294967296); 115 | msgpackr.encode(-9007199254740991); 116 | }) 117 | .add('encode float - @urlpack/msgpack', () => { 118 | urlpack.encode(0.5); 119 | urlpack.encode(1.2); 120 | urlpack.encode(1.337); 121 | }) 122 | .add('encode float - @msgpack/msgpack', () => { 123 | msgpack.encode(0.5); 124 | msgpack.encode(1.2); 125 | msgpack.encode(1.337); 126 | }) 127 | .add('encode float - msgpack5', () => { 128 | msgpack5.encode(0.5); 129 | msgpack5.encode(1.2); 130 | msgpack5.encode(1.337); 131 | }) 132 | .add('encode float - msgpack-lite', () => { 133 | msgpackLite.encode(0.5); 134 | msgpackLite.encode(1.2); 135 | msgpackLite.encode(1.337); 136 | }) 137 | .add('encode float - msgpackr', () => { 138 | msgpackr.encode(0.5); 139 | msgpackr.encode(1.2); 140 | msgpackr.encode(1.337); 141 | }) 142 | .add('encode str - @urlpack/msgpack', () => { 143 | urlpack.encode('Hello World!'); 144 | urlpack.encode('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie, sem sed rutrum euismod, leo tellus mattis velit, nec consequat lacus mi quis arcu. Etiam eget urna sem. Sed nulla ex, maximus eget ornare sit amet, tristique at diam. Etiam viverra feugiat turpis, ac varius dui mollis ut.'); 145 | }) 146 | .add('encode str - @msgpack/msgpack', () => { 147 | msgpack.encode('Hello World!'); 148 | msgpack.encode('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie, sem sed rutrum euismod, leo tellus mattis velit, nec consequat lacus mi quis arcu. Etiam eget urna sem. Sed nulla ex, maximus eget ornare sit amet, tristique at diam. Etiam viverra feugiat turpis, ac varius dui mollis ut.'); 149 | }) 150 | .add('encode str - msgpack5', () => { 151 | msgpack5.encode('Hello World!'); 152 | msgpack5.encode('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie, sem sed rutrum euismod, leo tellus mattis velit, nec consequat lacus mi quis arcu. Etiam eget urna sem. Sed nulla ex, maximus eget ornare sit amet, tristique at diam. Etiam viverra feugiat turpis, ac varius dui mollis ut.'); 153 | }) 154 | .add('encode str - msgpack-lite', () => { 155 | msgpackLite.encode('Hello World!'); 156 | msgpackLite.encode('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie, sem sed rutrum euismod, leo tellus mattis velit, nec consequat lacus mi quis arcu. Etiam eget urna sem. Sed nulla ex, maximus eget ornare sit amet, tristique at diam. Etiam viverra feugiat turpis, ac varius dui mollis ut.'); 157 | }) 158 | .add('encode str - msgpackr', () => { 159 | msgpackr.encode('Hello World!'); 160 | msgpackr.encode('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie, sem sed rutrum euismod, leo tellus mattis velit, nec consequat lacus mi quis arcu. Etiam eget urna sem. Sed nulla ex, maximus eget ornare sit amet, tristique at diam. Etiam viverra feugiat turpis, ac varius dui mollis ut.'); 161 | }) 162 | .add('encode bin - @urlpack/msgpack', () => { 163 | const bin8 = new Uint8Array(Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)); 164 | urlpack.encode(bin8); 165 | }) 166 | .add('encode bin - @msgpack/msgpack', () => { 167 | const bin8 = new Uint8Array(Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)); 168 | msgpack.encode(bin8); 169 | }) 170 | .add('encode bin - msgpack5', () => { 171 | const bin8 = new Uint8Array(Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)); 172 | msgpack5.encode(bin8); 173 | }) 174 | .add('encode bin - msgpack-lite', () => { 175 | const bin8 = new Uint8Array(Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)); 176 | msgpackLite.encode(bin8); 177 | }) 178 | .add('encode bin - msgpackr', () => { 179 | const bin8 = new Uint8Array(Array(2**8 - 1).fill(0).map((_, idx) => idx % 256)); 180 | msgpackr.encode(bin8); 181 | }) 182 | .add('encode fixarray - @urlpack/msgpack', () => { 183 | urlpack.encode([null, null, null, null, null]); 184 | }) 185 | .add('encode fixarray - @msgpack/msgpack', () => { 186 | msgpack.encode([null, null, null, null, null]); 187 | }) 188 | .add('encode fixarray - msgpack5', () => { 189 | msgpack5.encode([null, null, null, null, null]); 190 | }) 191 | .add('encode fixarray - msgpack-lite', () => { 192 | msgpackLite.encode([null, null, null, null, null]); 193 | }) 194 | .add('encode fixarray - msgpackr', () => { 195 | msgpackr.encode([null, null, null, null, null]); 196 | }) 197 | .add('encode array 8 - @urlpack/msgpack', () => { 198 | const arr = Array(2**8 - 1).fill(null); 199 | urlpack.encode(arr); 200 | }) 201 | .add('encode array 8 - @msgpack/msgpack', () => { 202 | const arr = Array(2**8 - 1).fill(null); 203 | msgpack.encode(arr); 204 | }) 205 | .add('encode array 8 - msgpack5', () => { 206 | const arr = Array(2**8 - 1).fill(null); 207 | msgpack5.encode(arr); 208 | }) 209 | .add('encode array 8 - msgpack-lite', () => { 210 | const arr = Array(2**8 - 1).fill(null); 211 | msgpackLite.encode(arr); 212 | }) 213 | .add('encode array 8 - msgpackr', () => { 214 | const arr = Array(2**8 - 1).fill(null); 215 | msgpackr.encode(arr); 216 | }) 217 | .add('encode array 16 - @urlpack/msgpack', () => { 218 | const arr = Array(2**16 - 1).fill(null); 219 | urlpack.encode(arr); 220 | }) 221 | .add('encode array 16 - @msgpack/msgpack', () => { 222 | const arr = Array(2**16 - 1).fill(null); 223 | msgpack.encode(arr); 224 | }) 225 | .add('encode array 16 - msgpack5', () => { 226 | const arr = Array(2**16 - 1).fill(null); 227 | msgpack5.encode(arr); 228 | }) 229 | .add('encode array 16 - msgpack-lite', () => { 230 | const arr = Array(2**16 - 1).fill(null); 231 | msgpackLite.encode(arr); 232 | }) 233 | .add('encode array 16 - msgpackr', () => { 234 | const arr = Array(2**16 - 1).fill(null); 235 | msgpackr.encode(arr); 236 | }) 237 | .add('encode fixmap - @urlpack/msgpack', () => { 238 | urlpack.encode({ a: null, b: null, c: null, d: null, e: null }); 239 | }) 240 | .add('encode fixmap - @msgpack/msgpack', () => { 241 | msgpack.encode({ a: null, b: null, c: null, d: null, e: null }); 242 | }) 243 | .add('encode fixmap - msgpack5', () => { 244 | msgpack5.encode({ a: null, b: null, c: null, d: null, e: null }); 245 | }) 246 | .add('encode fixmap - msgpack-lite', () => { 247 | msgpackLite.encode({ a: null, b: null, c: null, d: null, e: null }); 248 | }) 249 | .add('encode fixmap - msgpackr', () => { 250 | msgpackr.encode({ a: null, b: null, c: null, d: null, e: null }); 251 | }) 252 | .on('cycle', event => { 253 | console.log(event.target.toString()); 254 | }) 255 | .run(); 256 | -------------------------------------------------------------------------------- /benchmarks/utf8-decode.js: -------------------------------------------------------------------------------- 1 | import _benchmark from 'benchmark'; 2 | const { Benchmark } = _benchmark; 3 | 4 | const textDecoder = new TextDecoder(); 5 | 6 | const utf8DecodeJs = (function (bytes) { 7 | let offset = 0; 8 | const end = bytes.length; 9 | 10 | const units = []; 11 | let result = ""; 12 | while (offset < end) { 13 | const byte1 = bytes[offset++]; 14 | if ((byte1 & 0x80) === 0) { 15 | // 1 byte 16 | units.push(byte1); 17 | } else if ((byte1 & 0xe0) === 0xc0) { 18 | // 2 bytes 19 | const byte2 = bytes[offset++] & 0x3f; 20 | units.push(((byte1 & 0x1f) << 6) | byte2); 21 | } else if ((byte1 & 0xf0) === 0xe0) { 22 | // 3 bytes 23 | const byte2 = bytes[offset++] & 0x3f; 24 | const byte3 = bytes[offset++] & 0x3f; 25 | units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); 26 | } else if ((byte1 & 0xf8) === 0xf0) { 27 | // 4 bytes 28 | const byte2 = bytes[offset++] & 0x3f; 29 | const byte3 = bytes[offset++] & 0x3f; 30 | const byte4 = bytes[offset++] & 0x3f; 31 | let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; 32 | if (unit > 0xffff) { 33 | unit -= 0x10000; 34 | units.push(((unit >>> 10) & 0x3ff) | 0xd800); 35 | unit = 0xdc00 | (unit & 0x3ff); 36 | } 37 | units.push(unit); 38 | } else { 39 | units.push(byte1); 40 | } 41 | 42 | if (units.length >= 0x1_000) { 43 | result += String.fromCharCode(...units); 44 | units.length = 0; 45 | } 46 | } 47 | 48 | if (units.length > 0) { 49 | result += String.fromCharCode(...units); 50 | } 51 | 52 | return result; 53 | }); 54 | 55 | const textEncoded = new Uint8Array([0xac, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21]); 56 | 57 | new Benchmark.Suite() 58 | .add('TextDecoder', () => { 59 | textDecoder.decode(textEncoded); 60 | }) 61 | .add('utf8DecodeJs', () => { 62 | utf8DecodeJs(textEncoded); 63 | }) 64 | .on('cycle', event => { 65 | console.log(event.target.toString()); 66 | }) 67 | .run(); 68 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/project", 3 | "type": "module", 4 | "private": true, 5 | "license": "MIT", 6 | "workspaces": [ 7 | "packages/*" 8 | ], 9 | "scripts": { 10 | "typecheck": "tsc --noEmit", 11 | "test": "uvu -r tsm", 12 | "test:watch": "yarn test || true && watchlist packages/*/src packages/*/tests -- yarn test" 13 | }, 14 | "devDependencies": { 15 | "@changesets/cli": "^2.27.1", 16 | "@msgpack/msgpack": "^3.0.0-beta2", 17 | "@urlpack/base58": "workspace:^2.0.0", 18 | "@urlpack/msgpack": "workspace:^2.0.0", 19 | "base-x": "^4.0.0", 20 | "base58-js": "^2.0.0", 21 | "benchmark": "^2.1.4", 22 | "msgpack-lite": "^0.1.26", 23 | "msgpack5": "^6.0.2", 24 | "msgpackr": "^1.10.1", 25 | "tsm": "^2.3.0", 26 | "typescript": "^5.4.3", 27 | "uvu": "^0.5.6", 28 | "watchlist": "^0.3.1" 29 | }, 30 | "packageManager": "yarn@4.1.1" 31 | } 32 | -------------------------------------------------------------------------------- /packages/base-codec/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/base-codec/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base-codec 2 | 3 | ## 2.0.0 4 | ### Major Changes 5 | 6 | - ebbf3d3: Drop UMD support and change to ESM-first package 7 | 8 | ### Minor Changes 9 | 10 | - eafc5dd: Remove sideEffects assertion in all packages, to avoid unpredictable bundler issues 11 | 12 | ### Patch Changes 13 | 14 | - 481b54b: Add `types` fields in exports 15 | -------------------------------------------------------------------------------- /packages/base-codec/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/base-codec/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base-codec 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/base-codec)](https://npm.im/@urlpack/base-codec) 4 | [![License](https://img.shields.io/npm/l/@urlpack/base-codec)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/base-codec)](https://bundlephobia.com/package/@urlpack/base-codec) 6 | 7 | Pure JavaScript implementation of the Base-N codec.\ 8 | (1~255, it isn't compat with the Base16, Base32 and Base64) 9 | 10 | - Zero dependencies 11 | - ES Modules & Browser compatible 12 | - Tree-shakable encoder and decoder 13 | 14 | ## Usage 15 | 16 | ```ts 17 | import { makeBaseEncoder, makeBaseDecoder } from '@urlpack/base-codec'; 18 | 19 | // Flickr-flavored Base58 characters 20 | const alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' 21 | 22 | const encoder = makeBaseEncoder(alphabet); 23 | encoder.encode(binary); // Uint8Array => string 24 | 25 | const decoder = makeBaseDecoder(alphabet); 26 | decoder.encode(str); // => string => Uint8Array 27 | ``` 28 | 29 | ## Benchmark 30 | 31 | ```txt 32 | @urlpack/base-codec encode x 1,178 ops/sec ±0.23% (99 runs sampled) 33 | @urlpack/base-codec decode x 1,948 ops/sec ±0.37% (100 runs sampled) 34 | 35 | base-x encode x 1,381 ops/sec ±0.54% (97 runs sampled) 36 | base-x decode x 2,039 ops/sec ±0.33% (100 runs sampled) 37 | 38 | base58-js encode x 1,017 ops/sec ±0.16% (98 runs sampled) 39 | base58-js decode x 335 ops/sec ±0.21% (96 runs sampled) 40 | ``` 41 | 42 | It should be better. PR welcome 43 | 44 | ## License 45 | 46 | MIT 47 | -------------------------------------------------------------------------------- /packages/base-codec/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/base-codec", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/base-codec", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/base-codec" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build --standalone" 34 | }, 35 | "devDependencies": { 36 | "nanobundle": "^2.0.0", 37 | "typescript": "^5.4.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/base-codec/src/decoder.ts: -------------------------------------------------------------------------------- 1 | interface MakeBaseDecoder { 2 | (baseAlphabet: string): { 3 | decode: (input: string) => Uint8Array; 4 | }; 5 | } 6 | 7 | export const makeBaseDecoder: MakeBaseDecoder = baseAlphabet => { 8 | let n = baseAlphabet.length; 9 | if (n === 0 || n > 255) { 10 | throw new Error('Invalid base alphabet length: ' + n); 11 | } 12 | 13 | let map = new Map( 14 | Array.from(baseAlphabet, (char, i) => [char, i]), 15 | ); 16 | 17 | return { 18 | decode: input => { 19 | // encoding_flag: 20 | // - 0: counting leading zeros 21 | // - 1: processing 22 | let flag = 0; 23 | let leadingZeros = 0; 24 | let decoding: number[] = []; 25 | 26 | for (let char of input) { 27 | let carry = map.get(char); 28 | if (carry == null) { 29 | throw new Error('Invalid character: ' + char); 30 | } 31 | if (!(flag || carry)) { 32 | leadingZeros++; 33 | } else { 34 | flag = 1; 35 | } 36 | 37 | for (let i = 0; (carry || i < decoding.length); i++) { 38 | carry += decoding[i] * n >>> 0; 39 | decoding[i] = carry % 256; 40 | carry = carry / 256 | 0; 41 | } 42 | } 43 | 44 | let len = leadingZeros + decoding.length; 45 | let values = new Uint8Array(len); 46 | for (let i = 0; i < len; i++) { 47 | values[i] = i < leadingZeros 48 | ? 0 49 | : decoding[len - i - 1]; 50 | } 51 | 52 | return values; 53 | }, 54 | }; 55 | }; 56 | -------------------------------------------------------------------------------- /packages/base-codec/src/encoder.ts: -------------------------------------------------------------------------------- 1 | interface MakeBaseEncoder { 2 | (baseAlphabet: string): { 3 | encode: (input: Uint8Array) => string, 4 | }; 5 | } 6 | 7 | export const makeBaseEncoder: MakeBaseEncoder = baseAlphabet => { 8 | let n = baseAlphabet.length; 9 | if (n === 0 || n > 255) { 10 | throw new Error('Invalid base alphabet length: ' + n); 11 | } 12 | return { 13 | encode: input => { 14 | // encoding_flag: 15 | // - 0: counting leading zeros 16 | // - 1: processing 17 | let flag = 0; 18 | let leadingZeros = 0; 19 | let encoding = []; 20 | 21 | for (let byte of input) { 22 | if (!(flag || byte)) { 23 | leadingZeros++; 24 | } else { 25 | flag = 1; 26 | } 27 | 28 | let carry = byte; 29 | for (let i = 0; (carry || i < encoding.length); i++) { 30 | carry += encoding[i] << 8; 31 | encoding[i] = carry % n; 32 | carry = carry / n | 0; 33 | } 34 | } 35 | 36 | let len = leadingZeros + encoding.length; 37 | let values = Array(len); 38 | for (let i = 0; i < len; i++) { 39 | values[i] = baseAlphabet[ 40 | i < leadingZeros 41 | ? 0 42 | : encoding[len - i - 1] 43 | ]; 44 | } 45 | 46 | return values.join(''); 47 | }, 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /packages/base-codec/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encoder.ts'; 2 | export * from './decoder.ts'; 3 | -------------------------------------------------------------------------------- /packages/base-codec/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/base10/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/base10/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base10 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - f47c286: New codecs for QR Codes URL (See https://huonw.github.io/blog/2024/03/qr-base10-base64/) 8 | -------------------------------------------------------------------------------- /packages/base10/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/base10/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base10 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/base10)](https://npm.im/@urlpack/base10) 4 | [![License](https://img.shields.io/npm/l/@urlpack/base10)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/base10)](https://bundlephobia.com/package/@urlpack/base10) 6 | 7 | Pure JavaScript implementation of the Base10 codec. 8 | 9 | - Zero dependencies 10 | - ES Modules & Browser compatible 11 | - Tree-shakable encoder and decoder 12 | 13 | ## License 14 | 15 | MIT 16 | -------------------------------------------------------------------------------- /packages/base10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/base10", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/base10", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/base10" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build", 34 | "test": "uvu -r tsm", 35 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 36 | }, 37 | "dependencies": { 38 | "@urlpack/base-codec": "workspace:^2.0.0" 39 | }, 40 | "devDependencies": { 41 | "nanobundle": "^2.0.0", 42 | "tsm": "^2.3.0", 43 | "typescript": "^5.4.3", 44 | "uvu": "^0.5.6", 45 | "watchlist": "^0.3.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/base10/src/decode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseDecoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultDecoder = makeBaseDecoder(baseAlphabet); 6 | export const decode: (encoding: string) => Uint8Array = defaultDecoder.decode; 7 | -------------------------------------------------------------------------------- /packages/base10/src/encode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseEncoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultEncoder = makeBaseEncoder(baseAlphabet); 6 | export const encode: (binary: Uint8Array) => string = defaultEncoder.encode; 7 | -------------------------------------------------------------------------------- /packages/base10/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encode.ts'; 2 | export * from './decode.ts'; 3 | -------------------------------------------------------------------------------- /packages/base10/src/util.ts: -------------------------------------------------------------------------------- 1 | export const baseAlphabet = '0123456789'; 2 | -------------------------------------------------------------------------------- /packages/base10/tests/codec.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { encode, decode } from '@urlpack/base10'; 5 | 6 | const textEncoder = new TextEncoder(); 7 | 8 | const cases: Array<[binary: Uint8Array, text: string]> = [ 9 | [ 10 | textEncoder.encode('안녕하세요!'), 11 | '314474236304828881015048610782331442209', 12 | ], 13 | [ 14 | textEncoder.encode( 15 | 'The quick brown fox jumps over the lazy dog.', 16 | ), 17 | '3024830571690175283291907639196436031967763819210983988162282536502237781693262640684650930677706176554798', 18 | ], 19 | [ 20 | new Uint8Array([0x00, 0x00, 0x28, 0x7f, 0xb4, 0xcd]), 21 | '00679457997', 22 | ], 23 | ]; 24 | 25 | for (const [binary, text] of cases) { 26 | test('base10.encode', () => { 27 | assert.equal(encode(binary), text); 28 | }); 29 | 30 | test('base10.decode', () => { 31 | assert.equal(decode(text), binary); 32 | }); 33 | } 34 | 35 | test.run(); 36 | -------------------------------------------------------------------------------- /packages/base10/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/base58/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/base58/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base58 2 | 3 | ## 2.0.0 4 | 5 | ### Major Changes 6 | 7 | - ebbf3d3: Drop UMD support and change to ESM-first package 8 | 9 | ### Minor Changes 10 | 11 | - eafc5dd: Remove sideEffects assertion in all packages, to avoid unpredictable bundler issues 12 | 13 | ### Patch Changes 14 | 15 | - b242537: Removed sideEffects assertion to avoid unpredictable bundle issues 16 | - 481b54b: Add `types` fields in exports 17 | - Updated dependencies [ebbf3d3] 18 | - Updated dependencies [481b54b] 19 | - Updated dependencies [eafc5dd] 20 | - @urlpack/base-codec@2.0.0 21 | 22 | ## 1.0.4 23 | 24 | ### Patch Changes 25 | 26 | - 1d4cd8f: link dependencies using the workspace protocol, it should use "yarn npm publish" for publishing from now on 27 | -------------------------------------------------------------------------------- /packages/base58/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/base58/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base58 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/base58)](https://npm.im/@urlpack/base58) 4 | [![License](https://img.shields.io/npm/l/@urlpack/base58)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/base58)](https://bundlephobia.com/package/@urlpack/base58) 6 | 7 | Pure JavaScript implementation of the Base58 codec. 8 | 9 | - Zero dependencies 10 | - ES Modules & Browser compatible 11 | - Tree-shakable encoder and decoder 12 | 13 | ## Characters 14 | 15 | This package is using Bitcoin style. 16 | 17 | ```txt 18 | 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz 19 | ``` 20 | 21 | You can make your own Base-N codec with custom alphabet using [`@urlpack/base-codec`](https://github.com/daangn/urlpack/tree/main/packages/base-codec) 22 | 23 | ## License 24 | 25 | MIT 26 | -------------------------------------------------------------------------------- /packages/base58/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/base58", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/base58", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/base58" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build", 34 | "test": "uvu -r tsm", 35 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 36 | }, 37 | "dependencies": { 38 | "@urlpack/base-codec": "workspace:^2.0.0" 39 | }, 40 | "devDependencies": { 41 | "nanobundle": "^2.0.0", 42 | "tsm": "^2.3.0", 43 | "typescript": "^5.4.3", 44 | "uvu": "^0.5.6", 45 | "watchlist": "^0.3.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/base58/src/decode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseDecoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultDecoder = makeBaseDecoder(baseAlphabet); 6 | export const decode: (encoding: string) => Uint8Array = defaultDecoder.decode; 7 | -------------------------------------------------------------------------------- /packages/base58/src/encode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseEncoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultEncoder = makeBaseEncoder(baseAlphabet); 6 | export const encode: (binary: Uint8Array) => string = defaultEncoder.encode; 7 | -------------------------------------------------------------------------------- /packages/base58/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encode.ts'; 2 | export * from './decode.ts'; 3 | -------------------------------------------------------------------------------- /packages/base58/src/util.ts: -------------------------------------------------------------------------------- 1 | export const baseAlphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 2 | -------------------------------------------------------------------------------- /packages/base58/tests/codec.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { encode, decode } from '@urlpack/base58'; 5 | 6 | const textEncoder = new TextEncoder(); 7 | 8 | // https://tools.ietf.org/id/draft-msporny-base58-01.html 9 | const cases: Array<[binary: Uint8Array, text: string]> = [ 10 | [ 11 | textEncoder.encode('Hello World!'), 12 | '2NEpo7TZRRrLZSi2U', 13 | ], 14 | [ 15 | textEncoder.encode( 16 | 'The quick brown fox jumps over the lazy dog.', 17 | ), 18 | 'USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z' 19 | , 20 | ], 21 | [ 22 | new Uint8Array([0x00, 0x00, 0x28, 0x7f, 0xb4, 0xcd]), 23 | '11233QC4', 24 | ], 25 | ]; 26 | 27 | for (const [binary, text] of cases) { 28 | test('base58.encode', () => { 29 | assert.equal(encode(binary), text); 30 | }); 31 | 32 | test('base58.decode', () => { 33 | assert.equal(decode(text), binary); 34 | }); 35 | } 36 | 37 | test.run(); 38 | -------------------------------------------------------------------------------- /packages/base58/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/base62/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/base62/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base62 2 | 3 | ## 2.0.0 4 | 5 | ### Major Changes 6 | 7 | - ebbf3d3: Drop UMD support and change to ESM-first package 8 | 9 | ### Minor Changes 10 | 11 | - eafc5dd: Remove sideEffects assertion in all packages, to avoid unpredictable bundler issues 12 | 13 | ### Patch Changes 14 | 15 | - b242537: Removed sideEffects assertion to avoid unpredictable bundle issues 16 | - 481b54b: Add `types` fields in exports 17 | - Updated dependencies [ebbf3d3] 18 | - Updated dependencies [481b54b] 19 | - Updated dependencies [eafc5dd] 20 | - @urlpack/base-codec@2.0.0 21 | 22 | ## 1.0.4 23 | 24 | ### Patch Changes 25 | 26 | - 1d4cd8f: link dependencies using the workspace protocol, it should use "yarn npm publish" for publishing from now on 27 | -------------------------------------------------------------------------------- /packages/base62/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/base62/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/base62 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/base62)](https://npm.im/@urlpack/base62) 4 | [![License](https://img.shields.io/npm/l/@urlpack/base62)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/base62)](https://bundlephobia.com/package/@urlpack/base62) 6 | 7 | Pure JavaScript implementation of the Base62 codec. 8 | 9 | - Zero dependencies 10 | - ES Modules & Browser compatible 11 | - Tree-shakable encoder and decoder 12 | 13 | ## Characters 14 | 15 | This package is using GMP style. 16 | 17 | ```txt 18 | 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 19 | ``` 20 | 21 | You can make your own Base-N codec with custom alphabet using [`@urlpack/base-codec`](https://github.com/daangn/urlpack/tree/main/packages/base-codec) 22 | 23 | ## License 24 | 25 | MIT 26 | -------------------------------------------------------------------------------- /packages/base62/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/base62", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/base62", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/base62" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build", 34 | "test": "uvu -r tsm", 35 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 36 | }, 37 | "dependencies": { 38 | "@urlpack/base-codec": "workspace:^2.0.0" 39 | }, 40 | "devDependencies": { 41 | "@types/benchmark": "^2.1.5", 42 | "benchmark": "^2.1.4", 43 | "nanobundle": "^2.0.0", 44 | "tsm": "^2.3.0", 45 | "typescript": "^5.4.3", 46 | "uvu": "^0.5.6", 47 | "watchlist": "^0.3.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/base62/src/decode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseDecoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultDecoder = makeBaseDecoder(baseAlphabet); 6 | export const decode: (encoding: string) => Uint8Array = defaultDecoder.decode; 7 | -------------------------------------------------------------------------------- /packages/base62/src/encode.ts: -------------------------------------------------------------------------------- 1 | import { makeBaseEncoder } from '@urlpack/base-codec'; 2 | 3 | import { baseAlphabet } from './util.ts'; 4 | 5 | const defaultEncoder = makeBaseEncoder(baseAlphabet); 6 | export const encode: (binary: Uint8Array) => string = defaultEncoder.encode; 7 | -------------------------------------------------------------------------------- /packages/base62/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encode.ts'; 2 | export * from './decode.ts'; 3 | -------------------------------------------------------------------------------- /packages/base62/src/util.ts: -------------------------------------------------------------------------------- 1 | // Use GMP-style by default 2 | export const baseAlphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 3 | -------------------------------------------------------------------------------- /packages/base62/tests/codec.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { encode, decode } from '@urlpack/base62'; 5 | 6 | const textEncoder = new TextEncoder(); 7 | 8 | // https://tools.ietf.org/id/draft-msporny-base58-01.html 9 | const cases: Array<[binary: Uint8Array, text: string]> = [ 10 | [ 11 | textEncoder.encode('Hello World!'), 12 | 'T8dgcjRGkZ3aysdN', 13 | ], 14 | [ 15 | textEncoder.encode( 16 | 'The quick brown fox jumps over the lazy dog.', 17 | ), 18 | 'XGPLPeg6g0VCuZCSfg8LKEZOBVFQ79VvzR8f2OlDiCg5SwBJDmeq6nysKtS', 19 | ], 20 | [ 21 | new Uint8Array([0x00, 0x00, 0x28, 0x7f, 0xb4, 0xcd]), 22 | '00jyw3x', 23 | ], 24 | ]; 25 | 26 | for (const [binary, text] of cases) { 27 | test('base62.encode', () => { 28 | assert.equal(encode(binary), text); 29 | }); 30 | 31 | test('base62.decode', () => { 32 | assert.equal(decode(text), binary); 33 | }); 34 | } 35 | 36 | test.run(); 37 | -------------------------------------------------------------------------------- /packages/base62/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/json/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/json/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/json 2 | 3 | ## 2.0.0 4 | 5 | ### Major Changes 6 | 7 | - ebbf3d3: Drop UMD support and change to ESM-first package 8 | 9 | ### Minor Changes 10 | 11 | - 858692a: Changed the msgpack extension signature, and reimplemented decoder 12 | - eafc5dd: Remove sideEffects assertion in all packages, to avoid unpredictable bundler issues 13 | 14 | ### Patch Changes 15 | 16 | - 481b54b: Add `types` fields in exports 17 | - ac16c04: Fix to be able to override base codec properly 18 | - Updated dependencies [858692a] 19 | - Updated dependencies [ebbf3d3] 20 | - Updated dependencies [b242537] 21 | - Updated dependencies [e87d19b] 22 | - Updated dependencies [481b54b] 23 | - Updated dependencies [eafc5dd] 24 | - Updated dependencies [c8ff827] 25 | - @urlpack/msgpack@2.0.0 26 | - @urlpack/base58@2.0.0 27 | 28 | ## 1.0.4 29 | 30 | ### Patch Changes 31 | 32 | - 1d4cd8f: link dependencies using the workspace protocol, it should use "yarn npm publish" for publishing from now on 33 | - Updated dependencies [1d4cd8f] 34 | - @urlpack/base58@1.0.4 35 | -------------------------------------------------------------------------------- /packages/json/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/json/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/json 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/json)](https://npm.im/@urlpack/json) 4 | [![License](https://img.shields.io/npm/l/@urlpack/json)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/json)](https://bundlephobia.com/package/@urlpack/json) 6 | 7 | Compress JSON data into compact & URL-safe formats 8 | 9 | - ES Modules & Browser compatible 10 | - Compact output using [MessagePack](https://msgpack.org/) 11 | - URL safe formats (Base62, Base58) 12 | - Composable & Tree-shakable 13 | 14 | ## Usage 15 | 16 | ```ts 17 | import { makeJsonEncoder } from '@urlpack/json'; 18 | 19 | const encoder = makeJsonEncoder(); 20 | 21 | encoder.encode({ 22 | href: 'http://daangn.com', 23 | uid: 1234567, 24 | context: { 25 | foo: 'bar', 26 | baz: [1,2,3,4,5], 27 | }, 28 | }) 29 | // => 'QL3sGqgSwhebCV6jsPsxSCG6DPGZUAo7qtLbEFxFN3bequ3qABcg6pxvpvr36FveMxCtD4zNSWSpHmxgz8' 30 | // 31 | // Only 82 characters, 35% smaller output than JSON.stringify + lz-string 32 | ``` 33 | 34 | ## LICENSE 35 | 36 | MIT 37 | -------------------------------------------------------------------------------- /packages/json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/json", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/json", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/json" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build", 34 | "test": "uvu -r tsm", 35 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 36 | }, 37 | "dependencies": { 38 | "@urlpack/base58": "workspace:^2.0.0", 39 | "@urlpack/msgpack": "workspace:^2.0.0" 40 | }, 41 | "devDependencies": { 42 | "@urlpack/base-codec": "workspace:^2.0.0", 43 | "nanobundle": "^2.0.0", 44 | "tsm": "^2.3.0", 45 | "typescript": "^5.4.3", 46 | "uvu": "^0.5.6", 47 | "watchlist": "^0.3.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/json/src/decoder.ts: -------------------------------------------------------------------------------- 1 | import { decode as decodeBase58 } from '@urlpack/base58'; 2 | import { makeMessagePackDecoder } from '@urlpack/msgpack'; 3 | 4 | type JsonDecoderOptions = { 5 | decodeString?: (str: string) => Uint8Array, 6 | decodeBinary?: (binary: Uint8Array) => Data, 7 | }; 8 | 9 | export function makeJsonDecoder(options: JsonDecoderOptions = {}): { 10 | decode: (str: string) => Data, 11 | } { 12 | const decodeString = options.decodeString || decodeBase58; 13 | const decodeBinary = options.decodeBinary || makeMessagePackDecoder().decode; 14 | return { 15 | decode: str => decodeBinary(decodeString(str)) as Data, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /packages/json/src/encoder.ts: -------------------------------------------------------------------------------- 1 | import { encode as encodeToBase58 } from '@urlpack/base58'; 2 | import { makeMessagePackEncoder } from '@urlpack/msgpack'; 3 | 4 | type JsonEncoderOptions = { 5 | encodeData?: (data: Data) => Uint8Array, 6 | encodeBinary?: (binary: Uint8Array) => string, 7 | }; 8 | 9 | export function makeJsonEncoder(options: JsonEncoderOptions = {}): { 10 | encode: (data: Data) => string, 11 | } { 12 | const encodeData = options.encodeData || makeMessagePackEncoder().encode; 13 | const encodeBinary = options.encodeBinary || encodeToBase58; 14 | return { 15 | encode: data => encodeBinary(encodeData(data as any)), 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /packages/json/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encoder.ts'; 2 | export * from './decoder.ts'; 3 | -------------------------------------------------------------------------------- /packages/json/tests/codec.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { makeBaseEncoder, makeBaseDecoder } from '@urlpack/base-codec'; 5 | import { makeJsonEncoder, makeJsonDecoder } from '@urlpack/json'; 6 | 7 | test('pack json with default (msgpack, base58)', () => { 8 | const data = { 9 | href: 'http://daangn.com', 10 | uid: 1234567, 11 | context: { 12 | foo: 'bar', 13 | baz: [1, 2, 3, 4, 5], 14 | }, 15 | }; 16 | 17 | const { encode } = makeJsonEncoder(); 18 | const { decode } = makeJsonDecoder(); 19 | 20 | const stored = encode(data); 21 | console.log(stored); 22 | 23 | assert.equal(decode(stored), data); 24 | }); 25 | 26 | test('pack json with custom (msgpack, base34)', () => { 27 | const data = { 28 | href: 'http://daangn.com', 29 | uid: 1234567, 30 | context: { 31 | foo: 'bar', 32 | baz: [1, 2, 3, 4, 5], 33 | }, 34 | }; 35 | 36 | const alphabet = '123456789abcdefghijkmnopqrstuvwxyz'; 37 | const baseEncoder = makeBaseEncoder(alphabet); 38 | const baseDecoder = makeBaseDecoder(alphabet); 39 | const { encode } = makeJsonEncoder({ encodeBinary: baseEncoder.encode }); 40 | const { decode } = makeJsonDecoder({ decodeString: baseDecoder.decode }); 41 | 42 | const stored = encode(data); 43 | console.log(stored); 44 | 45 | assert.equal(decode(stored), data); 46 | }); 47 | 48 | test.run(); 49 | -------------------------------------------------------------------------------- /packages/json/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/msgpack/.gitattributes: -------------------------------------------------------------------------------- 1 | src/*.bs.js linguist-generated 2 | -------------------------------------------------------------------------------- /packages/msgpack/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/msgpack/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/msgpack 2 | 3 | ## 2.0.0 4 | 5 | ### Major Changes 6 | 7 | - 858692a: Changed the msgpack extension signature, and reimplemented decoder 8 | - ebbf3d3: Drop UMD support and change to ESM-first package 9 | 10 | ### Minor Changes 11 | 12 | - eafc5dd: Remove sideEffects assertion in all packages, to avoid unpredictable bundler issues 13 | - c8ff827: switch to ESM first 14 | 15 | ### Patch Changes 16 | 17 | - e87d19b: Fix negative float decoding (#14) 18 | - 481b54b: Add `types` fields in exports 19 | 20 | ## 1.0.3 21 | 22 | ### Patch Changes 23 | 24 | - bump version (yarn 1 doesn't seems to respect publishConfig fields) 25 | 26 | ## 1.0.2 27 | 28 | ### Patch Changes 29 | 30 | - 30a610b: fix decoding for long string on dict 31 | - 65ec067: Make it polyfill friendly by avoiding bigint liternal syntax 32 | -------------------------------------------------------------------------------- /packages/msgpack/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/msgpack/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/msgpack 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/msgpack)](https://npm.im/@urlpack/msgpack) 4 | [![License](https://img.shields.io/npm/l/@urlpack/msgpack)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/msgpack)](https://bundlephobia.com/package/@urlpack/msgpack) 6 | 7 | Pure JavaScript implementation of the [MessagePack](https://msgpack.org/) codec. (See [specification](https://github.com/msgpack/msgpack/blob/master/spec.md)) 8 | 9 | - Lightweight (only ~3KB min-gzipped) 10 | - Zero dependencies (No Node.js dependencies) 11 | - ES Modules & Web compatible 12 | - Tree-shakable, DCE-friendly both encoder and decoder 13 | 14 | ## Usage 15 | 16 | ```ts 17 | import { makeMessagePackEncoder, makeMessagePackDecoder } from '@urlpack/msgpack'; 18 | 19 | const encoder = makeMessagePackEncoder(); 20 | const decoder = makeMessagePackDecoder(); 21 | 22 | encoder.encode(data); // JSON => Uint8Array 23 | decoder.decode(binary); // Uint8Array => JSON 24 | ``` 25 | 26 | ### Using custom extensions 27 | 28 | You can use your own [extension](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types) codecs. 29 | 30 | encoder: 31 | ```ts 32 | import type { EncoderExtension } from '@urlpack/msgpack'; 33 | 34 | const myEncoderExtension: EncoderExtension = { 35 | type: 1, // 0 ~ 127 36 | 37 | check(input): input is MyObject { 38 | // validate input object is my extension type 39 | }, 40 | 41 | encode(input) {/* encode input object to binary */} 42 | }; 43 | 44 | const encoderExt = makeMessagePackEncoder({ 45 | encoderExtensions: [myEncoderExtension], 46 | }); 47 | ``` 48 | 49 | decoder: 50 | ```ts 51 | import type { DecoderExtension } from '@urlpack/msgpack'; 52 | 53 | const myDecoderExtension: DecoderExtension = { 54 | type: 1, // 0 ~ 127 55 | 56 | /** 57 | * - binary is Uint8Array that start from data part 58 | * - byteLength notice how many bytes you have to read 59 | */ 60 | decode(binary, length) { /* should returns decoded MyObject */ }, 61 | }; 62 | 63 | const decoderExt = makeMessagePackDecoder({ 64 | decoderExtensions: [myDecoderExtension], 65 | }); 66 | ``` 67 | 68 | ## About performance 69 | 70 | The current implementation is not that optimized. 71 | 72 | It is suitable for use as a callback for webpage that doesn't run the codec at high frequency, etc. 73 | 74 | If you are dealing with large data or want very high-performance, We recommend using the [official JS implementation](https://github.com/msgpack/msgpack-javascript) or [msgpackr](https://github.com/kriszyp/msgpackr). 75 | 76 | ## Benchmark 77 | 78 | Run on Desktop (Intel i5-9600K (6) @ 4.600GHz), Ubuntu 20.04.3 LTS x86_64 and Node.js v16.10.0 (v8 9.3.345.19) 79 | 80 | @urlpack/msgpack v1.0.3 vs. 81 | - [@msgpack/msgpack](https://github.com/msgpack/msgpack-javascript) v2.7.1 82 | - [msgpack5](https://github.com/mcollina/msgpack5) v5.3.2 83 | - [msgpack-lite](https://github.com/kawanet/msgpack-lite) v0.1.26 84 | - [msgpackr](https://github.com/kriszyp/msgpackr) 85 | 86 | ### Bundle stats 87 | 88 | | | Size | Size (min+gzipped) | ESM support?* | DCE-friendly?* | Zero-dependencies* | 89 | |:-----------------|-------:|-------------------:|---------------------|----------------|--------------------| 90 | | @urlpack/msgpack | 9.2kB | 3.2kB | ✔ | ✔ | ✔ | 91 | | @msgpack/msgpack | 29.5kB | 7.5kB | 🟡 (No export map) | ✔ | ✔ | 92 | | msgpack-lite | 24.9kB | 7.8kB | ❌ | ❌ | ❌ | 93 | | msgpackr | 27.5kB | 9.9kB | ✔ | ✔ | ✔ | 94 | 95 | * Packages should provide an ESM bundle and an export map so that it can be resolved on the Node.js environment. 96 | * Encoder and decoder should be separated modules to eliminate unnecessary code on a production build. 97 | * Additional shims are required for browsers if the package depends on Node APIs (e.g. `Buffer`). 98 | 99 | ### Encoding speed 100 | 101 | ```txt 102 | encode complex 1 - @urlpack/msgpack x 555,240 ops/sec ±1.45% (91 runs sampled) 103 | encode complex 1 - @msgpack/msgpack x 1,487,981 ops/sec ±0.89% (91 runs sampled) 104 | encode complex 1 - msgpack5 x 187,549 ops/sec ±0.62% (97 runs sampled) 105 | encode complex 1 - msgpack-lite x 888,246 ops/sec ±0.66% (96 runs sampled) 106 | encode complex 1 - msgpackr x 5,192,484 ops/sec ±0.48% (99 runs sampled) 107 | 108 | encode complex 2 - @urlpack/msgpack x 214,766 ops/sec ±0.75% (94 runs sampled) 109 | encode complex 2 - @msgpack/msgpack x 797,785 ops/sec ±0.80% (96 runs sampled) 110 | encode complex 2 - msgpack5 x 128,513 ops/sec ±0.60% (94 runs sampled) 111 | encode complex 2 - msgpack-lite x 385,248 ops/sec ±0.58% (96 runs sampled) 112 | encode complex 2 - msgpackr x 2,219,375 ops/sec ±0.31% (101 runs sampled) 113 | ``` 114 | 115 | ### Decoding speed 116 | 117 | ```txt 118 | decode complex 1 - @urlpack/msgpack x 1,270,298 ops/sec ±0.93% (97 runs sampled) 119 | decode complex 1 - @msgpack/msgpack x 2,399,679 ops/sec ±0.30% (100 runs sampled) 120 | decode complex 1 - msgpack5 x 482,239 ops/sec ±0.52% (98 runs sampled) 121 | decode complex 1 - msgpack-lite x 1,199,416 ops/sec ±0.28% (99 runs sampled) 122 | decode complex 1 - msgpackr x 5,277,932 ops/sec ±0.37% (93 runs sampled) 123 | 124 | decode complex 2 - @urlpack/msgpack x 476,016 ops/sec ±0.26% (99 runs sampled) 125 | decode complex 2 - @msgpack/msgpack x 1,109,229 ops/sec ±0.31% (100 runs sampled) 126 | decode complex 2 - msgpack5 x 204,347 ops/sec ±0.50% (99 runs sampled) 127 | decode complex 2 - msgpack-lite x 357,116 ops/sec ±0.91% (95 runs sampled) 128 | decode complex 2 - msgpackr x 2,181,796 ops/sec ±0.28% (96 runs sampled) 129 | ``` 130 | 131 | ## License 132 | 133 | MIT 134 | -------------------------------------------------------------------------------- /packages/msgpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/msgpack", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/msgpack", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/msgpack" 10 | }, 11 | "type": "module", 12 | "main": "./src/index.ts", 13 | "publishConfig": { 14 | "access": "public", 15 | "main": "./lib/index.mjs", 16 | "module": "./lib/index.mjs", 17 | "types": "./lib/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./lib/index.d.ts", 21 | "import": "./lib/index.mjs", 22 | "require": "./lib/index.cjs" 23 | }, 24 | "./package.json": "./package.json" 25 | } 26 | }, 27 | "files": [ 28 | "src", 29 | "lib" 30 | ], 31 | "scripts": { 32 | "prepack": "yarn build", 33 | "build": "nanobundle build --standalone", 34 | "test": "uvu -r tsm", 35 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 36 | }, 37 | "devDependencies": { 38 | "@rescript/std": "^9.1.3", 39 | "concurrently": "^8.2.2", 40 | "esbuild": "^0.20.2", 41 | "nanobundle": "^2.0.0", 42 | "tsm": "^2.3.0", 43 | "typescript": "^5.4.3", 44 | "uvu": "^0.5.6", 45 | "watchlist": "^0.3.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/msgpack/src/decoder.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by ReScript, PLEASE EDIT WITH CARE 2 | 3 | import * as Js_exn from "@rescript/std/lib/es6/js_exn.js"; 4 | import * as Js_dict from "@rescript/std/lib/es6/js_dict.js"; 5 | import * as Pervasives from "@rescript/std/lib/es6/pervasives.js"; 6 | import { timestampDecoder as timestampExt } from "./ext/TimestampDecoder"; 7 | 8 | var decode2 = (function (_t, bytes) { 9 | let offset = 0; 10 | const end = bytes.length; 11 | 12 | const units = []; 13 | let result = ""; 14 | while (offset < end) { 15 | const byte1 = bytes[offset++]; 16 | if ((byte1 & 0x80) === 0) { 17 | // 1 byte 18 | units.push(byte1); 19 | } else if ((byte1 & 0xe0) === 0xc0) { 20 | // 2 bytes 21 | const byte2 = bytes[offset++] & 0x3f; 22 | units.push(((byte1 & 0x1f) << 6) | byte2); 23 | } else if ((byte1 & 0xf0) === 0xe0) { 24 | // 3 bytes 25 | const byte2 = bytes[offset++] & 0x3f; 26 | const byte3 = bytes[offset++] & 0x3f; 27 | units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); 28 | } else if ((byte1 & 0xf8) === 0xf0) { 29 | // 4 bytes 30 | const byte2 = bytes[offset++] & 0x3f; 31 | const byte3 = bytes[offset++] & 0x3f; 32 | const byte4 = bytes[offset++] & 0x3f; 33 | let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; 34 | if (unit > 0xffff) { 35 | unit -= 0x10000; 36 | units.push(((unit >>> 10) & 0x3ff) | 0xd800); 37 | unit = 0xdc00 | (unit & 0x3ff); 38 | } 39 | units.push(unit); 40 | } else { 41 | units.push(byte1); 42 | } 43 | 44 | if (units.length >= 0x1_000) { 45 | result += String.fromCharCode(...units); 46 | units.length = 0; 47 | } 48 | } 49 | 50 | if (units.length > 0) { 51 | result += String.fromCharCode(...units); 52 | } 53 | 54 | return result; 55 | }); 56 | 57 | var $$TextDecoder = { 58 | decode2: decode2 59 | }; 60 | 61 | var flip64 = (function(binary) { 62 | let carry = 1; 63 | for (let i = 7; i >= 0; i--) { 64 | const v = (binary[i] ^ 0xff) + carry; 65 | binary[i] = v & 0xff; 66 | carry = v >> 8; 67 | } 68 | }); 69 | 70 | function make(extensions) { 71 | var textDecoder = new TextDecoder(); 72 | var extensions$1 = Js_dict.fromArray(extensions); 73 | return { 74 | textDecoder: textDecoder, 75 | extensions: extensions$1 76 | }; 77 | } 78 | 79 | function decode(t, binary) { 80 | var extensions = t.extensions; 81 | var textDecoder = t.textDecoder; 82 | var binary$1 = binary.slice(); 83 | var view = new DataView(binary$1.buffer); 84 | var decode$1 = function (binary, _state, _cursor) { 85 | while(true) { 86 | var cursor = _cursor; 87 | var state = _state; 88 | if (typeof state === "number") { 89 | var header = view.getUint8(cursor); 90 | var cursor$1 = cursor + 1 | 0; 91 | if (header < 128) { 92 | _cursor = cursor$1; 93 | _state = { 94 | TAG: /* Done */5, 95 | _0: header 96 | }; 97 | continue ; 98 | } 99 | if (header < 144) { 100 | var len = header & 15; 101 | _cursor = cursor$1; 102 | _state = { 103 | TAG: /* DecodeMap */2, 104 | _0: len, 105 | _1: {} 106 | }; 107 | continue ; 108 | } 109 | if (header < 160) { 110 | var len$1 = header & 15; 111 | _cursor = cursor$1; 112 | _state = { 113 | TAG: /* DecodeArray */1, 114 | _0: len$1, 115 | _1: new Array(len$1) 116 | }; 117 | continue ; 118 | } 119 | if (header < 192) { 120 | var len$2 = header & 31; 121 | _cursor = cursor$1; 122 | _state = { 123 | TAG: /* DecodeString */0, 124 | _0: len$2 125 | }; 126 | continue ; 127 | } 128 | switch (header) { 129 | case 192 : 130 | _cursor = cursor$1; 131 | _state = { 132 | TAG: /* Done */5, 133 | _0: null 134 | }; 135 | continue ; 136 | case 193 : 137 | break; 138 | case 194 : 139 | _cursor = cursor$1; 140 | _state = { 141 | TAG: /* Done */5, 142 | _0: false 143 | }; 144 | continue ; 145 | case 195 : 146 | _cursor = cursor$1; 147 | _state = { 148 | TAG: /* Done */5, 149 | _0: true 150 | }; 151 | continue ; 152 | case 196 : 153 | var len$3 = view.getUint8(cursor$1); 154 | _cursor = cursor$1 + 1 | 0; 155 | _state = { 156 | TAG: /* DecodeBinary */3, 157 | _0: len$3 158 | }; 159 | continue ; 160 | case 197 : 161 | var len$4 = view.getUint16(cursor$1); 162 | _cursor = cursor$1 + 2 | 0; 163 | _state = { 164 | TAG: /* DecodeBinary */3, 165 | _0: len$4 166 | }; 167 | continue ; 168 | case 198 : 169 | var len$5 = view.getUint32(cursor$1); 170 | _cursor = cursor$1 + 4 | 0; 171 | _state = { 172 | TAG: /* DecodeBinary */3, 173 | _0: len$5 174 | }; 175 | continue ; 176 | case 199 : 177 | var len$6 = view.getUint8(cursor$1); 178 | var type_ = view.getInt8(cursor$1 + 1 | 0); 179 | if (type_ === timestampExt.type) { 180 | _cursor = cursor$1 + 2 | 0; 181 | _state = { 182 | TAG: /* DecodeExt */4, 183 | _0: len$6, 184 | _1: timestampExt 185 | }; 186 | continue ; 187 | } 188 | var ext = Js_dict.get(extensions, String(type_)); 189 | if (ext === undefined) { 190 | return Js_exn.raiseError("Unknown extension type " + String(type_)); 191 | } 192 | _cursor = cursor$1 + 2 | 0; 193 | _state = { 194 | TAG: /* DecodeExt */4, 195 | _0: len$6, 196 | _1: ext 197 | }; 198 | continue ; 199 | case 200 : 200 | var len$7 = view.getUint16(cursor$1); 201 | var type_$1 = view.getInt8(cursor$1 + 2 | 0); 202 | var ext$1 = Js_dict.get(extensions, String(type_$1)); 203 | if (ext$1 === undefined) { 204 | return Js_exn.raiseError("Unknown extension type " + String(type_$1)); 205 | } 206 | _cursor = cursor$1 + 2 | 0; 207 | _state = { 208 | TAG: /* DecodeExt */4, 209 | _0: len$7, 210 | _1: ext$1 211 | }; 212 | continue ; 213 | case 201 : 214 | var len$8 = view.getUint32(cursor$1); 215 | var type_$2 = view.getInt8(cursor$1 + 4 | 0); 216 | var ext$2 = Js_dict.get(extensions, String(type_$2)); 217 | if (ext$2 === undefined) { 218 | return Js_exn.raiseError("Unknown extension type " + String(type_$2)); 219 | } 220 | _cursor = cursor$1 + 4 | 0; 221 | _state = { 222 | TAG: /* DecodeExt */4, 223 | _0: len$8, 224 | _1: ext$2 225 | }; 226 | continue ; 227 | case 202 : 228 | var num = view.getFloat32(cursor$1); 229 | _cursor = cursor$1 + 4 | 0; 230 | _state = { 231 | TAG: /* Done */5, 232 | _0: num 233 | }; 234 | continue ; 235 | case 203 : 236 | var num$1 = view.getFloat64(cursor$1); 237 | _cursor = cursor$1 + 8 | 0; 238 | _state = { 239 | TAG: /* Done */5, 240 | _0: num$1 241 | }; 242 | continue ; 243 | case 204 : 244 | var num$2 = view.getUint8(cursor$1); 245 | _cursor = cursor$1 + 1 | 0; 246 | _state = { 247 | TAG: /* Done */5, 248 | _0: num$2 249 | }; 250 | continue ; 251 | case 205 : 252 | var num$3 = view.getUint16(cursor$1); 253 | _cursor = cursor$1 + 2 | 0; 254 | _state = { 255 | TAG: /* Done */5, 256 | _0: num$3 257 | }; 258 | continue ; 259 | case 206 : 260 | var num$4 = view.getUint32(cursor$1); 261 | _cursor = cursor$1 + 4 | 0; 262 | _state = { 263 | TAG: /* Done */5, 264 | _0: num$4 265 | }; 266 | continue ; 267 | case 207 : 268 | var hi = view.getUint32(cursor$1); 269 | var lo = view.getUint32(cursor$1 + 4 | 0); 270 | var num$5 = hi * Math.pow(256.0, 4.0) + lo; 271 | _cursor = cursor$1 + 8 | 0; 272 | _state = { 273 | TAG: /* Done */5, 274 | _0: num$5 275 | }; 276 | continue ; 277 | case 208 : 278 | var num$6 = view.getInt8(cursor$1); 279 | _cursor = cursor$1 + 1 | 0; 280 | _state = { 281 | TAG: /* Done */5, 282 | _0: num$6 283 | }; 284 | continue ; 285 | case 209 : 286 | var num$7 = view.getInt16(cursor$1); 287 | _cursor = cursor$1 + 2 | 0; 288 | _state = { 289 | TAG: /* Done */5, 290 | _0: num$7 291 | }; 292 | continue ; 293 | case 210 : 294 | var num$8 = view.getInt32(cursor$1); 295 | _cursor = cursor$1 + 4 | 0; 296 | _state = { 297 | TAG: /* Done */5, 298 | _0: num$8 299 | }; 300 | continue ; 301 | case 211 : 302 | flip64(binary.subarray(cursor$1, cursor$1 + 9 | 0)); 303 | var hi$1 = view.getUint32(cursor$1); 304 | var lo$1 = view.getUint32(cursor$1 + 4 | 0); 305 | var num$9 = hi$1 * Math.pow(256.0, 4.0) + lo$1; 306 | _cursor = cursor$1 + 8 | 0; 307 | _state = { 308 | TAG: /* Done */5, 309 | _0: 0.0 - num$9 310 | }; 311 | continue ; 312 | case 212 : 313 | var type_$3 = view.getInt8(cursor$1); 314 | var ext$3 = Js_dict.get(extensions, String(type_$3)); 315 | if (ext$3 === undefined) { 316 | return Js_exn.raiseError("Unknown extension type " + String(type_$3)); 317 | } 318 | _cursor = cursor$1 + 1 | 0; 319 | _state = { 320 | TAG: /* DecodeExt */4, 321 | _0: 1, 322 | _1: ext$3 323 | }; 324 | continue ; 325 | case 213 : 326 | var type_$4 = view.getInt8(cursor$1); 327 | var ext$4 = Js_dict.get(extensions, String(type_$4)); 328 | if (ext$4 === undefined) { 329 | return Js_exn.raiseError("Unknown extension type " + String(type_$4)); 330 | } 331 | _cursor = cursor$1 + 1 | 0; 332 | _state = { 333 | TAG: /* DecodeExt */4, 334 | _0: 2, 335 | _1: ext$4 336 | }; 337 | continue ; 338 | case 214 : 339 | var type_$5 = view.getInt8(cursor$1); 340 | if (type_$5 === timestampExt.type) { 341 | _cursor = cursor$1 + 1 | 0; 342 | _state = { 343 | TAG: /* DecodeExt */4, 344 | _0: 4, 345 | _1: timestampExt 346 | }; 347 | continue ; 348 | } 349 | var ext$5 = Js_dict.get(extensions, String(type_$5)); 350 | if (ext$5 === undefined) { 351 | return Js_exn.raiseError("Unknown extension type " + String(type_$5)); 352 | } 353 | _cursor = cursor$1 + 1 | 0; 354 | _state = { 355 | TAG: /* DecodeExt */4, 356 | _0: 4, 357 | _1: ext$5 358 | }; 359 | continue ; 360 | case 215 : 361 | var type_$6 = view.getInt8(cursor$1); 362 | if (type_$6 === timestampExt.type) { 363 | _cursor = cursor$1 + 1 | 0; 364 | _state = { 365 | TAG: /* DecodeExt */4, 366 | _0: 8, 367 | _1: timestampExt 368 | }; 369 | continue ; 370 | } 371 | var ext$6 = Js_dict.get(extensions, String(type_$6)); 372 | if (ext$6 === undefined) { 373 | return Js_exn.raiseError("Unknown extension type " + String(type_$6)); 374 | } 375 | _cursor = cursor$1 + 1 | 0; 376 | _state = { 377 | TAG: /* DecodeExt */4, 378 | _0: 8, 379 | _1: ext$6 380 | }; 381 | continue ; 382 | case 216 : 383 | var type_$7 = view.getInt8(cursor$1); 384 | var ext$7 = Js_dict.get(extensions, String(type_$7)); 385 | if (ext$7 === undefined) { 386 | return Js_exn.raiseError("Unknown extension type " + String(type_$7)); 387 | } 388 | _cursor = cursor$1 + 1 | 0; 389 | _state = { 390 | TAG: /* DecodeExt */4, 391 | _0: 16, 392 | _1: ext$7 393 | }; 394 | continue ; 395 | case 217 : 396 | var len$9 = view.getUint8(cursor$1); 397 | _cursor = cursor$1 + 1 | 0; 398 | _state = { 399 | TAG: /* DecodeString */0, 400 | _0: len$9 401 | }; 402 | continue ; 403 | case 218 : 404 | var len$10 = view.getUint16(cursor$1); 405 | _cursor = cursor$1 + 2 | 0; 406 | _state = { 407 | TAG: /* DecodeString */0, 408 | _0: len$10 409 | }; 410 | continue ; 411 | case 219 : 412 | var len$11 = view.getUint32(cursor$1); 413 | _cursor = cursor$1 + 4 | 0; 414 | _state = { 415 | TAG: /* DecodeString */0, 416 | _0: len$11 417 | }; 418 | continue ; 419 | case 220 : 420 | var len$12 = view.getUint16(cursor$1); 421 | _cursor = cursor$1 + 2 | 0; 422 | _state = { 423 | TAG: /* DecodeArray */1, 424 | _0: len$12, 425 | _1: new Array(len$12) 426 | }; 427 | continue ; 428 | case 221 : 429 | var len$13 = view.getUint32(cursor$1); 430 | _cursor = cursor$1 + 4 | 0; 431 | _state = { 432 | TAG: /* DecodeArray */1, 433 | _0: len$13, 434 | _1: new Array(len$13) 435 | }; 436 | continue ; 437 | case 222 : 438 | var len$14 = view.getUint16(cursor$1); 439 | _cursor = cursor$1 + 2 | 0; 440 | _state = { 441 | TAG: /* DecodeMap */2, 442 | _0: len$14, 443 | _1: {} 444 | }; 445 | continue ; 446 | case 223 : 447 | var len$15 = view.getUint32(cursor$1); 448 | _cursor = cursor$1 + 4 | 0; 449 | _state = { 450 | TAG: /* DecodeMap */2, 451 | _0: len$15, 452 | _1: {} 453 | }; 454 | continue ; 455 | default: 456 | 457 | } 458 | if (header >= 256) { 459 | return Js_exn.raiseError("Unknown header " + String(header)); 460 | } 461 | var num$10 = Pervasives.lnot(header ^ 255); 462 | _cursor = cursor$1; 463 | _state = { 464 | TAG: /* Done */5, 465 | _0: num$10 466 | }; 467 | continue ; 468 | } 469 | switch (state.TAG | 0) { 470 | case /* DecodeString */0 : 471 | var len$16 = state._0; 472 | var view$1 = binary.subarray(cursor, cursor + len$16 | 0); 473 | var text = decode2(textDecoder, view$1); 474 | _cursor = cursor + len$16 | 0; 475 | _state = { 476 | TAG: /* Done */5, 477 | _0: text 478 | }; 479 | continue ; 480 | case /* DecodeArray */1 : 481 | var array = state._1; 482 | var len$17 = state._0; 483 | if (len$17 !== 0) { 484 | var match = decode$1(binary, /* ExpectHeader */0, cursor); 485 | var index = array.length - len$17 | 0; 486 | array[index] = match[0]; 487 | _cursor = match[1]; 488 | _state = { 489 | TAG: /* DecodeArray */1, 490 | _0: len$17 - 1 | 0, 491 | _1: array 492 | }; 493 | continue ; 494 | } 495 | _state = { 496 | TAG: /* Done */5, 497 | _0: array 498 | }; 499 | continue ; 500 | case /* DecodeMap */2 : 501 | var map = state._1; 502 | var len$18 = state._0; 503 | if (len$18 !== 0) { 504 | var match$1 = decode$1(binary, /* ExpectHeader */0, cursor); 505 | var key = match$1[0]; 506 | if (typeof key !== "string") { 507 | return Js_exn.raiseError("Unexpected key type. Expected string, but got " + typeof key); 508 | } 509 | var match$2 = decode$1(binary, /* ExpectHeader */0, match$1[1]); 510 | map[key] = match$2[0]; 511 | _cursor = match$2[1]; 512 | _state = { 513 | TAG: /* DecodeMap */2, 514 | _0: len$18 - 1 | 0, 515 | _1: map 516 | }; 517 | continue ; 518 | } 519 | _state = { 520 | TAG: /* Done */5, 521 | _0: map 522 | }; 523 | continue ; 524 | case /* DecodeBinary */3 : 525 | var len$19 = state._0; 526 | var copy = binary.slice(cursor, cursor + len$19 | 0); 527 | _cursor = cursor + len$19 | 0; 528 | _state = { 529 | TAG: /* Done */5, 530 | _0: copy 531 | }; 532 | continue ; 533 | case /* DecodeExt */4 : 534 | var len$20 = state._0; 535 | var copy$1 = binary.slice(cursor, cursor + len$20 | 0); 536 | _cursor = cursor + len$20 | 0; 537 | _state = { 538 | TAG: /* Done */5, 539 | _0: state._1.decode(copy$1, len$20) 540 | }; 541 | continue ; 542 | case /* Done */5 : 543 | return [ 544 | state._0, 545 | cursor 546 | ]; 547 | 548 | } 549 | }; 550 | }; 551 | var match = decode$1(binary$1, /* ExpectHeader */0, 0); 552 | var readLength = match[1]; 553 | var inputLength = binary$1.length; 554 | if (inputLength !== readLength) { 555 | Js_exn.raiseError("Invalid input length, expected " + String(inputLength) + ", but got " + String(readLength)); 556 | } 557 | return match[0]; 558 | } 559 | 560 | export { 561 | make , 562 | decode , 563 | 564 | } 565 | -------------------------------------------------------------------------------- /packages/msgpack/src/decoder.res: -------------------------------------------------------------------------------- 1 | open Js 2 | open TypedArray2 3 | 4 | module TextDecoder = { 5 | type t 6 | 7 | @new external make: unit => t = "TextDecoder" 8 | @send external decode: (t, Uint8Array.t) => string = "decode" 9 | 10 | /** 11 | * Borrowing from https://github.com/msgpack/msgpack-javascript/blob/c58b7e2/src/utils/utf8.ts#L48-L89 12 | * 13 | * Note: 14 | * The Node.js builtin TextDecoder is seriously slow. 15 | * This custom decoder is 10~12x faster than the builtin 16 | * 17 | * See benchmarks/utf8-decode.js 18 | */ 19 | let decode2: (t, Uint8Array.t) => string = %raw(`function (_t, bytes) { 20 | let offset = 0; 21 | const end = bytes.length; 22 | 23 | const units = []; 24 | let result = ""; 25 | while (offset < end) { 26 | const byte1 = bytes[offset++]; 27 | if ((byte1 & 0x80) === 0) { 28 | // 1 byte 29 | units.push(byte1); 30 | } else if ((byte1 & 0xe0) === 0xc0) { 31 | // 2 bytes 32 | const byte2 = bytes[offset++] & 0x3f; 33 | units.push(((byte1 & 0x1f) << 6) | byte2); 34 | } else if ((byte1 & 0xf0) === 0xe0) { 35 | // 3 bytes 36 | const byte2 = bytes[offset++] & 0x3f; 37 | const byte3 = bytes[offset++] & 0x3f; 38 | units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); 39 | } else if ((byte1 & 0xf8) === 0xf0) { 40 | // 4 bytes 41 | const byte2 = bytes[offset++] & 0x3f; 42 | const byte3 = bytes[offset++] & 0x3f; 43 | const byte4 = bytes[offset++] & 0x3f; 44 | let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; 45 | if (unit > 0xffff) { 46 | unit -= 0x10000; 47 | units.push(((unit >>> 10) & 0x3ff) | 0xd800); 48 | unit = 0xdc00 | (unit & 0x3ff); 49 | } 50 | units.push(unit); 51 | } else { 52 | units.push(byte1); 53 | } 54 | 55 | if (units.length >= 0x1_000) { 56 | result += String.fromCharCode(...units); 57 | units.length = 0; 58 | } 59 | } 60 | 61 | if (units.length > 0) { 62 | result += String.fromCharCode(...units); 63 | } 64 | 65 | return result; 66 | }`) 67 | } 68 | 69 | type result 70 | external result: 'a => result = "%identity" 71 | external toString: result => string = "%identity" 72 | 73 | @new external makeSizedArray: int => array = "Array" 74 | 75 | let flip64: Uint8Array.t => unit = %raw(`function(binary) { 76 | let carry = 1; 77 | for (let i = 7; i >= 0; i--) { 78 | const v = (binary[i] ^ 0xff) + carry; 79 | binary[i] = v & 0xff; 80 | carry = v >> 8; 81 | } 82 | }`) 83 | 84 | type ext = { 85 | \"type": int, 86 | decode: (. Uint8Array.t, int) => result, 87 | } 88 | 89 | @module("./ext/TimestampDecoder") external timestampExt: ext = "timestamDecoder" 90 | 91 | type t = { 92 | textDecoder: TextDecoder.t, 93 | extensions: Dict.t, 94 | } 95 | 96 | let make = (~extensions) => { 97 | let textDecoder = TextDecoder.make() 98 | let extensions = extensions->Js.Dict.fromArray 99 | { 100 | textDecoder: textDecoder, 101 | extensions: extensions, 102 | } 103 | } 104 | 105 | type state = 106 | | ExpectHeader 107 | | DecodeString(int) 108 | | DecodeArray(int, array) 109 | | DecodeMap(int, Dict.t) 110 | | DecodeBinary(int) 111 | | DecodeExt(int, ext) 112 | | Done(result) 113 | 114 | let decode = (t, binary) => { 115 | let {textDecoder, extensions} = t 116 | let binary = binary->Uint8Array.copy 117 | let view = binary->Uint8Array.buffer->DataView.fromBuffer 118 | let rec decode = (binary, ~state, ~cursor) => { 119 | switch state { 120 | | ExpectHeader => { 121 | let header = view->DataView.getUint8(cursor) 122 | let cursor = cursor + 1 123 | switch header { 124 | | header if header < 0x80 => binary->decode(~state=Done(header->result), ~cursor) 125 | | header if header < 0x90 => { 126 | let len = header->land(0xf) 127 | binary->decode(~state=DecodeMap(len, Dict.empty()), ~cursor) 128 | } 129 | | header if header < 0xa0 => { 130 | let len = header->land(0xf) 131 | binary->decode(~state=DecodeArray(len, makeSizedArray(len)), ~cursor) 132 | } 133 | | header if header < 0xc0 => { 134 | let len = header->land(0x1f) 135 | binary->decode(~state=DecodeString(len), ~cursor) 136 | } 137 | | 0xc0 => binary->decode(~state=Done(null->result), ~cursor) 138 | | 0xc2 => binary->decode(~state=Done(false->result), ~cursor) 139 | | 0xc3 => binary->decode(~state=Done(true->result), ~cursor) 140 | | 0xc4 => { 141 | let len = view->DataView.getUint8(cursor) 142 | binary->decode(~state=DecodeBinary(len), ~cursor=cursor + 1) 143 | } 144 | | 0xc5 => { 145 | let len = view->DataView.getUint16(cursor) 146 | binary->decode(~state=DecodeBinary(len), ~cursor=cursor + 2) 147 | } 148 | | 0xc6 => { 149 | let len = view->DataView.getUint32(cursor) 150 | binary->decode(~state=DecodeBinary(len), ~cursor=cursor + 4) 151 | } 152 | | 0xc7 => { 153 | let len = view->DataView.getUint8(cursor) 154 | let type_ = view->DataView.getInt8(cursor + 1) 155 | if type_ == timestampExt.\"type" { 156 | binary->decode(~state=DecodeExt(len, timestampExt), ~cursor=cursor + 2) 157 | } else { 158 | switch extensions->Dict.get(type_->Belt.Int.toString) { 159 | | Some(ext) => binary->decode(~state=DecodeExt(len, ext), ~cursor=cursor + 2) 160 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 161 | } 162 | } 163 | } 164 | | 0xc8 => { 165 | let len = view->DataView.getUint16(cursor) 166 | let type_ = view->DataView.getInt8(cursor + 2) 167 | switch extensions->Dict.get(type_->Belt.Int.toString) { 168 | | Some(ext) => binary->decode(~state=DecodeExt(len, ext), ~cursor=cursor + 2) 169 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 170 | } 171 | } 172 | | 0xc9 => { 173 | let len = view->DataView.getUint32(cursor) 174 | let type_ = view->DataView.getInt8(cursor + 4) 175 | switch extensions->Dict.get(type_->Belt.Int.toString) { 176 | | Some(ext) => binary->decode(~state=DecodeExt(len, ext), ~cursor=cursor + 4) 177 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 178 | } 179 | } 180 | | 0xca => { 181 | let num = view->DataView.getFloat32(cursor) 182 | binary->decode(~state=Done(num->result), ~cursor=cursor + 4) 183 | } 184 | | 0xcb => { 185 | let num = view->DataView.getFloat64(cursor) 186 | binary->decode(~state=Done(num->result), ~cursor=cursor + 8) 187 | } 188 | | 0xcc => { 189 | let num = view->DataView.getUint8(cursor) 190 | binary->decode(~state=Done(num->result), ~cursor=cursor + 1) 191 | } 192 | | 0xcd => { 193 | let num = view->DataView.getUint16(cursor) 194 | binary->decode(~state=Done(num->result), ~cursor=cursor + 2) 195 | } 196 | | 0xce => { 197 | let num = view->DataView.getUint32(cursor) 198 | binary->decode(~state=Done(num->result), ~cursor=cursor + 4) 199 | } 200 | | 0xcf => { 201 | let hi = view->DataView.getUint32(cursor)->Belt.Int.toFloat 202 | let lo = view->DataView.getUint32(cursor + 4)->Belt.Int.toFloat 203 | let num = hi *. Math.pow_float(~base=256.0, ~exp=4.0) +. lo 204 | binary->decode(~state=Done(num->result), ~cursor=cursor + 8) 205 | } 206 | | 0xd0 => { 207 | let num = view->DataView.getInt8(cursor) 208 | binary->decode(~state=Done(num->result), ~cursor=cursor + 1) 209 | } 210 | | 0xd1 => { 211 | let num = view->DataView.getInt16(cursor) 212 | binary->decode(~state=Done(num->result), ~cursor=cursor + 2) 213 | } 214 | | 0xd2 => { 215 | let num = view->DataView.getInt32(cursor) 216 | binary->decode(~state=Done(num->result), ~cursor=cursor + 4) 217 | } 218 | | 0xd3 => { 219 | binary->Uint8Array.subarray(~start=cursor, ~end_=cursor + 9)->flip64 220 | let hi = view->DataView.getUint32(cursor)->Belt.Int.toFloat 221 | let lo = view->DataView.getUint32(cursor + 4)->Belt.Int.toFloat 222 | let num = hi *. Math.pow_float(~base=256.0, ~exp=4.0) +. lo 223 | binary->decode(~state=Done((0.0 -. num)->result), ~cursor=cursor + 8) 224 | } 225 | | 0xd4 => { 226 | let type_ = view->DataView.getInt8(cursor) 227 | switch extensions->Dict.get(type_->Belt.Int.toString) { 228 | | Some(ext) => binary->decode(~state=DecodeExt(1, ext), ~cursor=cursor + 1) 229 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 230 | } 231 | } 232 | | 0xd5 => { 233 | let type_ = view->DataView.getInt8(cursor) 234 | switch extensions->Dict.get(type_->Belt.Int.toString) { 235 | | Some(ext) => binary->decode(~state=DecodeExt(2, ext), ~cursor=cursor + 1) 236 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 237 | } 238 | } 239 | | 0xd6 => { 240 | let type_ = view->DataView.getInt8(cursor) 241 | if type_ == timestampExt.\"type" { 242 | binary->decode(~state=DecodeExt(4, timestampExt), ~cursor=cursor + 1) 243 | } else { 244 | switch extensions->Dict.get(type_->Belt.Int.toString) { 245 | | Some(ext) => binary->decode(~state=DecodeExt(4, ext), ~cursor=cursor + 1) 246 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 247 | } 248 | } 249 | } 250 | | 0xd7 => { 251 | let type_ = view->DataView.getInt8(cursor) 252 | if type_ == timestampExt.\"type" { 253 | binary->decode(~state=DecodeExt(8, timestampExt), ~cursor=cursor + 1) 254 | } else { 255 | switch extensions->Dict.get(type_->Belt.Int.toString) { 256 | | Some(ext) => binary->decode(~state=DecodeExt(8, ext), ~cursor=cursor + 1) 257 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 258 | } 259 | } 260 | } 261 | | 0xd8 => { 262 | let type_ = view->DataView.getInt8(cursor) 263 | switch extensions->Dict.get(type_->Belt.Int.toString) { 264 | | Some(ext) => binary->decode(~state=DecodeExt(16, ext), ~cursor=cursor + 1) 265 | | None => Exn.raiseError(`Unknown extension type ${type_->Belt.Int.toString}`) 266 | } 267 | } 268 | | 0xd9 => { 269 | let len = view->DataView.getUint8(cursor) 270 | binary->decode(~state=DecodeString(len), ~cursor=cursor + 1) 271 | } 272 | | 0xda => { 273 | let len = view->DataView.getUint16(cursor) 274 | binary->decode(~state=DecodeString(len), ~cursor=cursor + 2) 275 | } 276 | | 0xdb => { 277 | let len = view->DataView.getUint32(cursor) 278 | binary->decode(~state=DecodeString(len), ~cursor=cursor + 4) 279 | } 280 | | 0xdc => { 281 | let len = view->DataView.getUint16(cursor) 282 | binary->decode(~state=DecodeArray(len, makeSizedArray(len)), ~cursor=cursor + 2) 283 | } 284 | | 0xdd => { 285 | let len = view->DataView.getUint32(cursor) 286 | binary->decode(~state=DecodeArray(len, makeSizedArray(len)), ~cursor=cursor + 4) 287 | } 288 | | 0xde => { 289 | let len = view->DataView.getUint16(cursor) 290 | binary->decode(~state=DecodeMap(len, Dict.empty()), ~cursor=cursor + 2) 291 | } 292 | | 0xdf => { 293 | let len = view->DataView.getUint32(cursor) 294 | binary->decode(~state=DecodeMap(len, Dict.empty()), ~cursor=cursor + 4) 295 | } 296 | | header if header < 0x100 => { 297 | let num = header->lxor(255)->lnot 298 | binary->decode(~state=Done(num->result), ~cursor) 299 | } 300 | | header => Exn.raiseError(`Unknown header ${header->Belt.Int.toString}`) 301 | } 302 | } 303 | | DecodeString(len) => { 304 | let view = binary->Uint8Array.subarray(~start=cursor, ~end_=cursor + len) 305 | let text = textDecoder->TextDecoder.decode2(view) 306 | binary->decode(~state=Done(text->result), ~cursor=cursor + len) 307 | } 308 | | DecodeArray(len, array) => 309 | switch len { 310 | | 0 => binary->decode(~state=Done(array->result), ~cursor) 311 | | len => { 312 | let (item, cursor) = binary->decode(~state=ExpectHeader, ~cursor) 313 | let index = array->Array2.length - len 314 | array->Array2.unsafe_set(index, item) 315 | binary->decode(~state=DecodeArray(len - 1, array), ~cursor) 316 | } 317 | } 318 | | DecodeMap(len, map) => 319 | switch len { 320 | | 0 => binary->decode(~state=Done(map->result), ~cursor) 321 | | len => { 322 | let (key, cursor) = binary->decode(~state=ExpectHeader, ~cursor) 323 | if typeof(key) == "string" { 324 | let (value, cursor) = binary->decode(~state=ExpectHeader, ~cursor) 325 | map->Dict.set(key->toString, value) 326 | binary->decode(~state=DecodeMap(len - 1, map), ~cursor) 327 | } else { 328 | Exn.raiseError(`Unexpected key type. Expected string, but got ${typeof(key)}`) 329 | } 330 | } 331 | } 332 | | DecodeBinary(len) => { 333 | let copy = binary->Uint8Array.slice(~start=cursor, ~end_=cursor + len) 334 | binary->decode(~state=Done(copy->result), ~cursor=cursor + len) 335 | } 336 | | DecodeExt(len, ext) => { 337 | let copy = binary->Uint8Array.slice(~start=cursor, ~end_=cursor + len) 338 | binary->decode(~state=Done(ext.decode(. copy, len)), ~cursor=cursor + len) 339 | } 340 | | Done(result) => (result, cursor) 341 | } 342 | } 343 | 344 | let (result, readLength) = binary->decode(~state=ExpectHeader, ~cursor=0) 345 | 346 | let inputLength = binary->Uint8Array.length 347 | if inputLength != readLength { 348 | Exn.raiseError( 349 | `Invalid input length, expected ${inputLength->Belt.Int.toString}, but got ${readLength->Belt.Int.toString}`, 350 | ) 351 | } 352 | 353 | result 354 | } 355 | -------------------------------------------------------------------------------- /packages/msgpack/src/decoder.ts: -------------------------------------------------------------------------------- 1 | import type { Input } from './types.ts'; 2 | import type { DecoderExtension } from './ext/types.ts'; 3 | 4 | // @ts-ignore 5 | import { make as makeDecoder, decode } from './decoder.bs.js'; 6 | 7 | type DecodeFn = (dataArray: Uint8Array) => Input; 8 | 9 | type DecoderOptions = { 10 | decoderExtensions?: Array>, 11 | }; 12 | 13 | export function makeMessagePackDecoder({ 14 | decoderExtensions = [], 15 | }: DecoderOptions = {}): { 16 | decode: DecodeFn, 17 | } { 18 | let decoder = makeDecoder(decoderExtensions); 19 | return { 20 | decode: input => decode(decoder, input), 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/msgpack/src/encoder.ts: -------------------------------------------------------------------------------- 1 | import type { Input } from './types.ts'; 2 | import { isFloat } from './utils.ts'; 3 | import type { EncoderExtension } from './ext/types.ts'; 4 | import { timestampEncoder } from './ext/TimestampEncoder.ts'; 5 | 6 | let uint16min = 0x100; 7 | let uint32min = 0x10000; 8 | let uint64min = 0x100000000; 9 | 10 | type EncodeFn = (input: InputType) => Uint8Array; 11 | 12 | type EncoderOptions = { 13 | encoderExtensions?: Array>, 14 | }; 15 | 16 | export function makeMessagePackEncoder({ 17 | encoderExtensions = [], 18 | }: EncoderOptions = {}): { 19 | encode: EncodeFn>, 20 | } { 21 | let textEncoder = new TextEncoder(); 22 | 23 | const encodeFloat = (input: number, force64 = false) => { 24 | let is64 = force64 || Math.fround(input) !== input; 25 | let array = new Uint8Array(is64 ? 9 : 5); 26 | let view = new DataView(array.buffer); 27 | if (is64) { 28 | array[0] = 0xcb; 29 | view.setFloat64(1, input, false); 30 | } else { 31 | array[0] = 0xca; 32 | view.setFloat32(1, input, false); 33 | } 34 | return array; 35 | }; 36 | 37 | const encodeInteger = (input: number) => { 38 | if (input === 0) { 39 | return new Uint8Array([0]); 40 | 41 | } else if (input > 0) { 42 | if (input < 128) { 43 | return numberUint8Array(input, 8); 44 | } else if (input < uint16min) { 45 | return numberUint8Array(input, 8, 0xcc); 46 | } else if (input < uint32min) { 47 | return numberUint8Array(input, 16, 0xcd); 48 | } else if (input < uint64min) { 49 | return numberUint8Array(input, 32, 0xce); 50 | } else if (input <= Number.MAX_SAFE_INTEGER) { 51 | return numberUint8Array(input, 64, 0xcf); 52 | } else { 53 | throw new Error('number is lager than 2^53, try bigint'); 54 | } 55 | 56 | } else { 57 | if (input >= -32) { 58 | return numberUint8Array((uint16min + input), 8); 59 | } else if (input >= -uint16min / 2) { 60 | return numberUint8Array(input, 8, 0xd0); 61 | } else if (input >= -uint32min / 2) { 62 | return numberUint8Array(input, 16, 0xd1); 63 | } else if (input >= -uint64min / 2) { 64 | return numberUint8Array(input, 32, 0xd2); 65 | } else if (input >= Number.MIN_SAFE_INTEGER) { 66 | let absArray = numberUint8Array(Math.abs(input), 64, 0xd3); 67 | let i = absArray.length; 68 | 69 | while (i-- > 1) { 70 | if (absArray[i] !== 0) { 71 | absArray[i] = (absArray[i] ^ 0xff) + 1; 72 | break; 73 | } 74 | } 75 | 76 | while (i-- > 1) { 77 | absArray[i] = absArray[i] ^ 0xff; 78 | } 79 | 80 | return absArray; 81 | } else { 82 | throw new Error('number is smaller than -2^53, try bigint'); 83 | } 84 | } 85 | }; 86 | 87 | const encodeBigInt = (input: bigint) => { 88 | if (input === BigInt(0)) { 89 | // zero is zero 90 | return new Uint8Array([0]); 91 | 92 | } else if (input > 0) { 93 | // treat positive bigint as unsigned int64 94 | 95 | let array = new Uint8Array(9); 96 | array[0] = 0xcf; 97 | 98 | let view = new DataView(array.buffer, 1); 99 | view.setBigUint64(0, input, false); 100 | 101 | return array; 102 | } else { 103 | // treat negative bigint as signed int64 104 | 105 | let array = new Uint8Array(9); 106 | array[0] = 0xd3; 107 | 108 | let view = new DataView(array.buffer, 1); 109 | view.setBigInt64(0, input, false); 110 | 111 | return array; 112 | } 113 | }; 114 | 115 | const encodeString = (input: string) => { 116 | let array: Uint8Array; 117 | let buffer = textEncoder.encode(input); 118 | let len = buffer.length; 119 | 120 | if (len < 32) { 121 | array = new Uint8Array(1 + len); 122 | array[0] = 0xa0 | len; 123 | array.set(buffer, 1); 124 | } else if (len < 256) { 125 | array = new Uint8Array(2 + len); 126 | array[0] = 0xd9; 127 | array[1] = len; 128 | array.set(buffer, 2); 129 | } else if (len < 65536) { 130 | array = new Uint8Array(3 + len); 131 | array[0] = 0xda; 132 | array[1] = 0xff & (len >> 8); 133 | array[2] = 0xff & len; 134 | array.set(buffer, 3); 135 | } else if (len < uint64min) { 136 | array = new Uint8Array(5 + len); 137 | array[0] = 0xdb; 138 | array[1] = 0xff & (len >> 24); 139 | array[2] = 0xff & (len >> 16); 140 | array[3] = 0xff & (len >> 8); 141 | array[4] = 0xff & len; 142 | array.set(buffer, 5); 143 | } else { 144 | array = new Uint8Array(); 145 | } 146 | return array; 147 | }; 148 | 149 | const encodeBinary = (input: Uint8Array) => { 150 | let buf: Uint8Array; 151 | let len = input.length; 152 | if (len < 256) { 153 | buf = new Uint8Array(2 + len); 154 | buf[0] = 0xc4; 155 | buf[1] = len; 156 | buf.set(input, 2); 157 | } else if (len < 65536) { 158 | buf = new Uint8Array(3 + len); 159 | buf[0] = 0xc5; 160 | buf[1] = len >> 8; 161 | buf[2] = 0xff & len; 162 | buf.set(input, 3); 163 | } else if (len < uint64min) { 164 | buf = new Uint8Array(5 + len); 165 | buf[0] = 0xc6; 166 | buf[1] = 0xff & (len >> 24); 167 | buf[2] = 0xff & (len >> 16); 168 | buf[3] = 0xff & (len >> 8); 169 | buf[4] = 0xff & len; 170 | buf.set(input, 5); 171 | } else { 172 | buf = new Uint8Array(); 173 | } 174 | return buf; 175 | }; 176 | 177 | const encodeArray = (items: Input[]) => { 178 | let itemLen = items.length; 179 | let bufLen = 0; 180 | let cache = Array(itemLen); 181 | for (let i = 0; i < itemLen; i++) { 182 | let buf = encode(items[i]); 183 | cache[i] = buf; 184 | bufLen += buf.length; 185 | } 186 | 187 | let array: Uint8Array; 188 | let offset = 0; 189 | if (itemLen < 16) { 190 | offset = 1; 191 | array = new Uint8Array(offset + bufLen); 192 | array[0] = 0x90 | itemLen; 193 | } else if (itemLen < 65536) { 194 | offset = 3; 195 | array = new Uint8Array(offset + bufLen); 196 | array[0] = 0xdc; 197 | array[1] = 0xff & (itemLen >> 8); 198 | array[2] = 0xff & itemLen; 199 | } else if (itemLen < 4294967296) { 200 | offset = 5; 201 | array = new Uint8Array(offset + bufLen); 202 | array[0] = 0xdd; 203 | array[1] = 0xff & (itemLen >> 24); 204 | array[2] = 0xff & (itemLen >> 16); 205 | array[3] = 0xff & (itemLen >> 8); 206 | array[4] = 0xff & itemLen; 207 | } else { 208 | throw new Error('array length is too long'); 209 | } 210 | 211 | for (let subarray of cache) { 212 | for (let i = 0; i < subarray.length; i++) { 213 | array[offset++] = subarray[i]; 214 | } 215 | } 216 | 217 | return array; 218 | }; 219 | 220 | const encodeMap = (input: { [key: string]: Input } | ExtensionType) => { 221 | let entries = Object.entries(input); 222 | let entriesLen = entries.length; 223 | let keyCache = Array(entriesLen); 224 | let valCache = Array(entriesLen); 225 | let bufLen = 0; 226 | for (let i = 0; i < entriesLen; i++) { 227 | let [key, value] = entries[i]; 228 | 229 | let keyBuf = encodeString(key); 230 | keyCache[i] = keyBuf; 231 | 232 | let valueBuf = encode(value); 233 | valCache[i] = valueBuf; 234 | 235 | bufLen += keyBuf.length + valueBuf.length; 236 | } 237 | 238 | let array: Uint8Array; 239 | let offset = 0; 240 | if (entriesLen < 16) { 241 | offset = 1; 242 | array = new Uint8Array(offset + bufLen); 243 | array[0] = 0x80 | entriesLen; 244 | } else if (entriesLen < 65536) { 245 | offset = 3; 246 | array = new Uint8Array(offset + bufLen); 247 | array[0] = 0xde; 248 | array[1] = 0xff & (entriesLen >> 8); 249 | array[2] = 0xff & entriesLen; 250 | } else if (entriesLen < 4294967296) { 251 | offset = 5; 252 | array = new Uint8Array(offset + bufLen); 253 | array[0] = 0xdf; 254 | array[1] = 0xff & (entriesLen >> 24); 255 | array[2] = 0xff & (entriesLen >> 16); 256 | array[3] = 0xff & (entriesLen >> 8); 257 | array[4] = 0xff & entriesLen; 258 | } else { 259 | throw new Error('map size is too big'); 260 | } 261 | 262 | for (let i = 0; i < entriesLen; i++) { 263 | array.set(keyCache[i], offset); 264 | offset += keyCache[i].length; 265 | 266 | array.set(valCache[i], offset); 267 | offset += valCache[i].length; 268 | } 269 | 270 | return array; 271 | }; 272 | 273 | let encode = (input: Input) => { 274 | if (typeof input === 'string') { 275 | return encodeString(input); 276 | } 277 | 278 | if (Array.isArray(input)) { 279 | return encodeArray(input); 280 | } 281 | 282 | if (input instanceof Uint8Array) { 283 | return encodeBinary(input); 284 | } else if (input === null) { 285 | return new Uint8Array([0xc0]); 286 | } else if (typeof input === 'object') { 287 | if (timestampEncoder.check(input)) { 288 | return timestampEncoder.encode(input); 289 | } 290 | for (let ext of encoderExtensions) { 291 | if (ext.check(input)) { 292 | return ext.encode(input); 293 | } 294 | } 295 | return encodeMap(input); 296 | } 297 | 298 | if (input === false) { 299 | return new Uint8Array([0xc2]); 300 | } 301 | 302 | if (input === true) { 303 | return new Uint8Array([0xc3]); 304 | } 305 | 306 | if (typeof input === 'number') { 307 | if (isFloat(input)) { 308 | return encodeFloat(input); 309 | } else { 310 | return encodeInteger(input); 311 | } 312 | } 313 | 314 | if (typeof input === 'bigint') { 315 | return encodeBigInt(input); 316 | } 317 | 318 | return new Uint8Array(); 319 | }; 320 | 321 | return { encode }; 322 | } 323 | 324 | let numberUint8Array = (input: number, bits: 8 | 16 | 32 | 64, header?: number) => { 325 | let array = new Uint8Array((bits >> 3) + (header ? 1 : 0)); 326 | let cursor = 0; 327 | 328 | if (header) { 329 | array[cursor++] = header; 330 | } 331 | 332 | if (bits < 64) { 333 | for (let i = bits - 8; i >= 0; i -= 8) { 334 | array[cursor++] = 0xff & (input >> i); 335 | } 336 | } else { 337 | let lo = input % uint64min; 338 | let hi = input / uint64min | 0; 339 | 340 | for (let i = 24; i >= 0; i -= 8) { 341 | array[cursor++] = 0xff & (hi >> i); 342 | } 343 | 344 | for (let i = 24; i >= 0; i -= 8) { 345 | array[cursor++] = 0xff & (lo >> i); 346 | } 347 | } 348 | 349 | return array; 350 | }; 351 | -------------------------------------------------------------------------------- /packages/msgpack/src/ext/TimestampDecoder.ts: -------------------------------------------------------------------------------- 1 | import type { DecoderExtension } from './types.ts'; 2 | 3 | export const timestampDecoder: DecoderExtension = { 4 | type: -1, 5 | // almost copy-pated from msgpack5's DateCodec implementation 6 | // https://github.com/mcollina/msgpack5/blob/master/lib/codecs/DateCodec.js 7 | decode(dataArray, byteLength) { 8 | let view = new DataView(dataArray.buffer); 9 | switch (byteLength) { 10 | case 4: { 11 | let seconds = view.getUint32(0, false); 12 | let millis = seconds / 1000 | 0; 13 | return new Date(millis); 14 | } 15 | case 8: { 16 | let upper = view.getUint32(0); 17 | let lower = view.getUint32(4); 18 | let nanos = upper / 4; 19 | let seconds = ((upper & 3) * (2 ** 32)) + lower; 20 | let millis = seconds * 1000 + Math.round(nanos / 1e6); 21 | return new Date(millis); 22 | } 23 | case 12: 24 | throw new Error(`timestamp96 is not supported yet`); 25 | default: 26 | throw new Error(`invalid byteLength ${byteLength}`); 27 | } 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/msgpack/src/ext/TimestampEncoder.ts: -------------------------------------------------------------------------------- 1 | import type { EncoderExtension } from './types.ts'; 2 | 3 | let uint64bound = 0x100000000; 4 | 5 | export const timestampEncoder: EncoderExtension = { 6 | type: -1, 7 | 8 | check(input): input is Date { 9 | return input instanceof Date; 10 | }, 11 | // almost copy-pated from msgpack5's DateCodec implementation 12 | // https://github.com/mcollina/msgpack5/blob/master/lib/codecs/DateCodec.js 13 | encode(input) { 14 | let millis = input.getTime(); 15 | let seconds = millis / 1000 | 0; 16 | let nanos = (millis - (seconds * 1000)) * 1e6; 17 | let bound = uint64bound - 1; 18 | 19 | if (nanos || seconds > bound) { 20 | let array = new Uint8Array(10); 21 | let view = new DataView(array.buffer); 22 | let upperNanos = nanos * 4; 23 | let upperSeconds = seconds / uint64bound; 24 | let upper = (upperNanos + upperSeconds) & bound; 25 | let lower = seconds & bound; 26 | view.setUint8(0, 0xd7); 27 | view.setInt8(1, -1); 28 | view.setUint32(2, upper, false); 29 | view.setUint32(6, lower, false); 30 | return array; 31 | } else { 32 | let array = new Uint8Array(6); 33 | let view = new DataView(array.buffer); 34 | view.setUint8(0, 0xd6); 35 | view.setInt8(1, -1); 36 | view.setUint32(2, millis / 1000 | 0, false); 37 | return array; 38 | } 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/msgpack/src/ext/types.ts: -------------------------------------------------------------------------------- 1 | export interface EncoderExtension { 2 | type: number; 3 | check(input: object): input is T; 4 | encode(input: T): Uint8Array; 5 | } 6 | 7 | export interface DecoderExtension { 8 | type: number; 9 | decode(dataArray: Uint8Array, length: number): T; 10 | } 11 | -------------------------------------------------------------------------------- /packages/msgpack/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encoder.ts'; 2 | export * from './decoder.ts'; 3 | 4 | export type { EncoderExtension, DecoderExtension } from './ext/types.ts'; 5 | -------------------------------------------------------------------------------- /packages/msgpack/src/types.ts: -------------------------------------------------------------------------------- 1 | export type Input = ( 2 | | null 3 | | undefined 4 | | number 5 | | bigint 6 | | boolean 7 | | string 8 | | Uint8Array 9 | | Array> 10 | | { [key: string]: Input } 11 | | Date 12 | | ExtensionType 13 | ); 14 | -------------------------------------------------------------------------------- /packages/msgpack/src/utils.ts: -------------------------------------------------------------------------------- 1 | export let isFloat = (num: number) => num % 1 !== 0; 2 | -------------------------------------------------------------------------------- /packages/msgpack/tests/decode-complex.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { makeMessagePackDecoder } from '@urlpack/msgpack'; 5 | 6 | const { decode } = makeMessagePackDecoder(); 7 | 8 | const complex = new Uint8Array([0x88, 0xa3, 0x69, 0x6e, 0x74, 0x1, 0xa5, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0xcb, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa7, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0xc3, 0xa4, 0x6e, 0x75, 0x6c, 0x6c, 0xc0, 0xa6, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa7, 0x66, 0x6f, 0x6f, 0x20, 0x62, 0x61, 0x72, 0xa5, 0x61, 0x72, 0x72, 0x61, 0x79, 0x92, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72, 0xa6, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x82, 0xa3, 0x66, 0x6f, 0x6f, 0x1, 0xa3, 0x62, 0x61, 0x7a, 0xcb, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa4, 0x64, 0x61, 0x74, 0x65, 0xd7, 0xff, 0xbe, 0x7f, 0x17, 0x0, 0x60, 0xf8, 0x3c, 0x5f]); 9 | 10 | test('decoding complex', () => { 11 | assert.equal(decode(complex), { 12 | 'int': 1, 13 | 'float': 0.5, 14 | 'boolean': true, 15 | 'null': null, 16 | 'string': 'foo bar', 17 | 'array': [ 18 | 'foo', 19 | 'bar', 20 | ], 21 | 'object': { 22 | 'foo': 1, 23 | 'baz': 0.5, 24 | }, 25 | 'date': new Date(1626881119799), 26 | }); 27 | }); 28 | 29 | test.run(); 30 | -------------------------------------------------------------------------------- /packages/msgpack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib", 6 | "allowJs": true 7 | }, 8 | "include": [ 9 | "src" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /packages/qrjson/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | -------------------------------------------------------------------------------- /packages/qrjson/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urlpack/qrjson 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - f47c286: New codecs for QR Codes URL (See https://huonw.github.io/blog/2024/03/qr-base10-base64/) 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies [f47c286] 12 | - @urlpack/base10@1.0.0 13 | -------------------------------------------------------------------------------- /packages/qrjson/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Danggeun Market Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/qrjson/README.md: -------------------------------------------------------------------------------- 1 | # @urlpack/qrjson 2 | 3 | [![Package Version](https://img.shields.io/npm/v/@urlpack/qrjson)](https://npm.im/@urlpack/qrjson) 4 | [![License](https://img.shields.io/npm/l/@urlpack/qrjson)](#License) 5 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@urlpack/qrjson)](https://bundlephobia.com/package/@urlpack/qrjson) 6 | 7 | Compress JSON data into compact & optimized to URL for QR Codes with numeric mode encoding 8 | 9 | - ES Modules & Browser compatible 10 | - Compact output using [MessagePack](https://msgpack.org/) 11 | - Use Base10 encoding to get clear QR Code (mode=numeric) image 12 | 13 | ## Usage 14 | 15 | ```ts 16 | import { makeQrJsonEncoder } from '@urlpack/qrjson'; 17 | 18 | const encoder = makeQrJsonEncoder(); 19 | 20 | encoder.encode({ 21 | href: 'http://daangn.com', 22 | uid: 1234567, 23 | context: { 24 | foo: 'bar', 25 | baz: [1, 2, 3, 4, 5], 26 | }, 27 | }); 28 | // => '1605288693315933041592216384647639863862606035591552983841613971370651694842366403819686780144511394090067728031488880352135548504776147881624581' 29 | ``` 30 | 31 | ## LICENSE 32 | 33 | MIT 34 | -------------------------------------------------------------------------------- /packages/qrjson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urlpack/qrjson", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "homepage": "https://github.com/daangn/urlpack/tree/main/packages/qrjson", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/daangn/urlpack.git", 9 | "directory": "packages/qrjson" 10 | }, 11 | "source": "./src/index.ts", 12 | "type": "module", 13 | "main": "./src/index.ts", 14 | "module": "./lib/index.mjs", 15 | "types": "./lib/index.d.ts", 16 | "exports": { 17 | ".": { 18 | "types": "./lib/index.d.ts", 19 | "import": "./lib/index.mjs", 20 | "require": "./lib/index.cjs" 21 | }, 22 | "./package.json": "./package.json" 23 | }, 24 | "publishConfig": { 25 | "access": "public", 26 | "main": "./lib/index.mjs" 27 | }, 28 | "files": [ 29 | "src", 30 | "lib" 31 | ], 32 | "scripts": { 33 | "prepack": "yarn build", 34 | "build": "nanobundle build", 35 | "test": "uvu -r tsm", 36 | "test:watch": "yarn test || true && watchlist src tests -- yarn test" 37 | }, 38 | "dependencies": { 39 | "@urlpack/base10": "workspace:^1.0.0", 40 | "@urlpack/msgpack": "workspace:^2.0.0" 41 | }, 42 | "devDependencies": { 43 | "@urlpack/base-codec": "workspace:^2.0.0", 44 | "nanobundle": "^2.0.0", 45 | "tsm": "^2.3.0", 46 | "typescript": "^5.4.3", 47 | "uvu": "^0.5.6", 48 | "watchlist": "^0.3.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/qrjson/src/decoder.ts: -------------------------------------------------------------------------------- 1 | import { decode as decodeBase10 } from '@urlpack/base10'; 2 | import { makeMessagePackDecoder } from '@urlpack/msgpack'; 3 | 4 | export function makeQrJsonDecoder(): { 5 | decode: (str: string) => Data, 6 | } { 7 | const decodeString = decodeBase10; 8 | const decodeBinary = makeMessagePackDecoder().decode; 9 | return { 10 | decode: str => decodeBinary(decodeString(str)) as Data, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /packages/qrjson/src/encoder.ts: -------------------------------------------------------------------------------- 1 | import { encode as encodeToBase10 } from '@urlpack/base10'; 2 | import { makeMessagePackEncoder } from '@urlpack/msgpack'; 3 | 4 | export function makeQrJsonEncoder(): { 5 | encode: (data: Data) => string, 6 | } { 7 | const encodeData = makeMessagePackEncoder().encode; 8 | const encodeBinary = encodeToBase10; 9 | return { 10 | encode: data => encodeBinary(encodeData(data as any)), 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /packages/qrjson/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encoder.ts'; 2 | export * from './decoder.ts'; 3 | -------------------------------------------------------------------------------- /packages/qrjson/tests/codec.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as assert from 'uvu/assert'; 3 | 4 | import { makeBaseEncoder, makeBaseDecoder } from '@urlpack/base-codec'; 5 | import { makeQrJsonEncoder, makeQrJsonDecoder } from '@urlpack/qrjson'; 6 | 7 | test('pack json', () => { 8 | const data = { 9 | href: 'http://daangn.com', 10 | uid: 1234567, 11 | context: { 12 | foo: 'bar', 13 | baz: [1, 2, 3, 4, 5], 14 | }, 15 | }; 16 | 17 | const { encode } = makeQrJsonEncoder(); 18 | const { decode } = makeQrJsonDecoder(); 19 | 20 | const stored = encode(data); 21 | console.log(stored); 22 | 23 | assert.equal(decode(stored), data); 24 | }); 25 | 26 | test.run(); 27 | -------------------------------------------------------------------------------- /packages/qrjson/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "allowImportingTsExtensions": true, 7 | "strict": true, 8 | "composite": true, 9 | "incremental": true, 10 | "noEmit": true, 11 | "skipLibCheck": true 12 | } 13 | } 14 | --------------------------------------------------------------------------------