├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
├── PULL_REQUEST_TEMPLATE.md
├── SECURITY.md
└── workflows
│ ├── browser.yml
│ ├── ci.yml
│ ├── release-please.yml
│ └── stale-issues.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .npmrc
├── .prettierignore
├── .vscode
├── extensions.json
└── tasks.json
├── AUTHORS
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── README_js.md
├── bundlewatch.config.json
├── eslint.config.mjs
├── examples
├── benchmark
│ ├── README.md
│ ├── benchmark.html
│ ├── benchmark.js
│ ├── browser.js
│ ├── node.js
│ └── package.json
├── browser-esmodules
│ ├── README.md
│ ├── example.html
│ ├── example.js
│ └── package.json
├── browser-rollup
│ ├── README.md
│ ├── example-all.html
│ ├── example-all.js
│ ├── example-v1.html
│ ├── example-v1.js
│ ├── example-v4.html
│ ├── example-v4.js
│ ├── example-v7.html
│ ├── example-v7.js
│ ├── example.html
│ ├── package.json
│ ├── rollup.config.js
│ ├── size-v1.js
│ ├── size-v3.js
│ ├── size-v4.js
│ ├── size-v5.js
│ ├── size-v6.js
│ └── size-v7.js
├── browser-webpack
│ ├── README.md
│ ├── example-all-require.html
│ ├── example-all-require.js
│ ├── example-all.html
│ ├── example-all.js
│ ├── example-v1.html
│ ├── example-v1.js
│ ├── example-v4.html
│ ├── example-v4.js
│ ├── example-v7.html
│ ├── example-v7.js
│ ├── example.html
│ ├── package.json
│ ├── size-v1.js
│ ├── size-v3.js
│ ├── size-v4.js
│ ├── size-v5.js
│ ├── size-v6.js
│ ├── size-v7.js
│ └── webpack.config.js
├── node-commonjs
│ ├── README.md
│ ├── example.js
│ └── package.json
├── node-esmodules
│ ├── README.md
│ ├── example.mjs
│ ├── package.json
│ └── package.mjs
├── node-jest
│ ├── README.md
│ ├── jsdom.test.js
│ ├── node.test.js
│ └── package.json
├── node-webpack
│ ├── README.md
│ ├── example-all.js
│ ├── example-v1.js
│ ├── example-v4.js
│ ├── example-v7.js
│ ├── package.json
│ └── webpack.config.js
├── typescript
│ ├── README.md
│ ├── buffer.test.ts
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── utils
│ └── testpage.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── scripts
├── build.sh
└── iodd
├── src
├── bin
│ └── uuid
├── index.ts
├── max.ts
├── md5-browser.ts
├── md5.ts
├── native-browser.ts
├── native.ts
├── nil.ts
├── parse.ts
├── regex.ts
├── rng-browser.ts
├── rng.ts
├── sha1-browser.ts
├── sha1.ts
├── stringify.ts
├── test
│ ├── parse.test.ts
│ ├── rng.test.ts
│ ├── stringify.test.ts
│ ├── test_constants.ts
│ ├── v1.test.ts
│ ├── v35.test.ts
│ ├── v4.test.ts
│ ├── v6.test.ts
│ ├── v7.test.ts
│ ├── validate.test.ts
│ └── version.test.ts
├── types.ts
├── uuid-bin.ts
├── v1.ts
├── v1ToV6.ts
├── v3.ts
├── v35.ts
├── v4.ts
├── v5.ts
├── v6.ts
├── v6ToV1.ts
├── v7.ts
├── validate.ts
└── version.ts
├── test
└── browser
│ └── browser.spec.js
├── tsconfig.base.json
├── tsconfig.cjs.json
├── tsconfig.esm.json
├── tsconfig.json
└── wdio.conf.js
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [broofa, ctavan]
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: File a bug against the `uuid` project
3 | labels: ['bug']
4 | title: '[BUG]
'
5 |
6 | body:
7 | - type: checkboxes
8 | attributes:
9 | label: Before you begin...
10 | options:
11 | - label: I have searched the existing issues
12 | required: true
13 | - label: My issue title is descriptive and specific to the problem (i.e. search-engine friendly)
14 | required: true
15 | - label: I understand what an "MRE" is, and why providing one is important. (If not, [read this](https://stackoverflow.com/help/minimal-reproducible-example))
16 | required: true
17 |
18 | - type: textarea
19 | attributes:
20 | label: MRE and Description
21 | description: '**IMPORTANT**: Failure to provide an MRE is likely to result in your issue being closed without comment.'
22 | render: bash
23 | validations:
24 | required: false
25 |
26 | - type: textarea
27 | attributes:
28 | label: Environment
29 | description: 'Output of `npx envinfo --system --browsers --npmPackages --binaries` goes here:'
30 | validations:
31 | required: false
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for this project
3 | labels: ['feature']
4 |
5 | body:
6 | - type: textarea
7 | attributes:
8 | label: Feature description
9 |
10 | - type: textarea
11 | attributes:
12 | label: Additional information
13 | description: E.g. alternatives you've considered, examples, screenshots, or anything else that may be helpful
14 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | For issues related to `uuid` security please email the module maintainers. Their email addresses are available via `npm owner ls uuid`.
2 |
--------------------------------------------------------------------------------
/.github/workflows/browser.yml:
--------------------------------------------------------------------------------
1 | name: Browser
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | pull_request_target:
7 | types: [labeled]
8 |
9 | permissions:
10 | contents: read
11 |
12 | env:
13 | HUSKY: 0
14 |
15 | jobs:
16 | browser:
17 | if: github.repository == 'uuidjs/uuid' && (contains(github.event.pull_request.labels.*.name, 'safe to test') || github.event_name == 'push')
18 | runs-on: ubuntu-latest
19 | timeout-minutes: 30
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 | with:
24 | fetch-depth: 10
25 | - name: Use Node.js 20.x
26 | uses: actions/setup-node@v4
27 | with:
28 | node-version: 20.x
29 | - run: npm ci
30 | - name: Test Browser
31 | run: npm run test:browser
32 | env:
33 | CI: true
34 | BROWSERSTACK_USER: ${{ secrets.BROWSERSTACK_USER }}
35 | BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
36 | - run: npx bundlewatch --config bundlewatch.config.json
37 | env:
38 | BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
39 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | permissions:
6 | contents: read
7 |
8 | env:
9 | HUSKY: 0
10 |
11 | jobs:
12 | lint:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: Use Node.js
17 | uses: actions/setup-node@v4
18 | with:
19 | node-version: 22.x
20 |
21 | - run: npm ci
22 | - run: npm run lint
23 | - run: npm run docs:diff
24 |
25 | test:
26 | runs-on: ubuntu-latest
27 | strategy:
28 | fail-fast: false
29 | matrix:
30 | node-version: [16.x, 18.x, 20.x, 22.x]
31 | steps:
32 | - uses: actions/checkout@v4
33 | - name: Use Node.js ${{ matrix.node-version }}
34 | uses: actions/setup-node@v4
35 | with:
36 | node-version: ${{ matrix.node-version }}
37 | cache: npm
38 |
39 | - run: npm ci
40 | - run: npm run test
41 | - run: npm run test:node
42 |
--------------------------------------------------------------------------------
/.github/workflows/release-please.yml:
--------------------------------------------------------------------------------
1 | # Relevent docs:
2 | # - https://github.com/googleapis/release-please
3 | # - https://github.com/googleapis/release-please-action
4 |
5 | on:
6 | workflow_dispatch:
7 |
8 | push:
9 | branches:
10 | - main
11 |
12 | permissions:
13 | contents: write
14 | pull-requests: write
15 |
16 | name: release-please
17 |
18 | jobs:
19 | release-please:
20 | runs-on: ubuntu-latest
21 | steps:
22 | - uses: googleapis/release-please-action@v4
23 | id: release
24 | with:
25 | token: ${{ secrets.UUID_RELEASE_PLEASE_TOKEN }}
26 | release-type: node
27 |
28 | - run: echo "Release created?... ${{ steps.release.outputs.release_created }}"
29 |
30 | # Steps below handle publication to NPM
31 | - uses: actions/checkout@v4
32 | if: ${{ steps.release.outputs.release_created }}
33 | - uses: actions/setup-node@v4
34 | with:
35 | node-version: 20
36 | registry-url: 'https://registry.npmjs.org'
37 | if: ${{ steps.release.outputs.release_created }}
38 |
39 | - run: npm ci
40 | if: ${{ steps.release.outputs.release_created }}
41 |
42 | - run: npm test
43 | if: ${{ steps.release.outputs.release_created }}
44 |
45 | - run: npm publish
46 | env:
47 | NODE_AUTH_TOKEN: ${{secrets.UUID_NPM_RELEASE_TOKEN}}
48 | if: ${{ steps.release.outputs.release_created }}
49 |
--------------------------------------------------------------------------------
/.github/workflows/stale-issues.yml:
--------------------------------------------------------------------------------
1 | name: Close inactive issues
2 | on:
3 | schedule:
4 | - cron: '45 2 * * *'
5 |
6 | jobs:
7 | close-issues:
8 | runs-on: ubuntu-latest
9 | permissions:
10 | issues: write
11 | pull-requests: write
12 | steps:
13 | - uses: actions/stale@v7
14 | with:
15 | close-issue-message: 'Closing issue due to 30 days since being marked as stale.'
16 | days-before-issue-close: 30
17 | days-before-issue-stale: 90
18 | days-before-pr-close: -1
19 | days-before-pr-stale: -1
20 | exempt-issue-labels: 'stale-exempt'
21 | exempt-pr-labels: 'stale-exempt'
22 | repo-token: ${{ secrets.GITHUB_TOKEN }}
23 | stale-issue-label: 'stale'
24 | stale-issue-message: 'Marking as stale due to 90 days with no activity.'
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.tgz
2 | browserstack.err
3 | dist/
4 | .build/
5 | local.log
6 | logs/
7 | node_modules/
8 | examples/**/package-lock.json
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | npx --no-install commitlint --edit $1
3 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | npx --no-install lint-staged
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | tag-version-prefix="v"
2 | save-prefix=""
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | README.md
4 | CHANGELOG.md
5 | *.sh
6 | .gitignore
7 | .prettierignore
8 | .husky
9 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "ms-vscode.vscode-typescript-next",
5 | "esbenp.prettier-vscode"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "Build watcher",
6 | "group": "build",
7 | "type": "shell",
8 | "command": "npm run build:watch",
9 | "runOptions": {
10 | "runOn": "folderOpen"
11 | }
12 | },
13 | {
14 | "label": "Test watcher",
15 | "group": "build",
16 | "type": "shell",
17 | "command": "npm run test:watch",
18 | "windows": {
19 | "command": "npm run test:watch"
20 | },
21 | "presentation": {
22 | "reveal": "always",
23 | "panel": "new"
24 | },
25 | "runOptions": {
26 | "runOn": "folderOpen"
27 | }
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Robert Kieffer
2 | Christoph Tavan
3 | AJ ONeal
4 | Vincent Voyer
5 | Roman Shtylman
6 | Patrick McCarren
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Development
4 |
5 | 1. Clone this repo
6 | 2. `npm install` to install dev dependencies
7 | 3. VSCode is the recommended dev environment
8 |
9 | - Includes "Build Watcher" and "Test Watcher" tasks (Terminal pane)
10 | - (optional) Install the recommended extensions (Extensions sidebar)
11 |
12 | 4. Before submitting your PR, make sure tests pass:
13 |
14 | - `npm test && npm run test:node`
15 |
16 | ## README updates
17 |
18 | **Do not edit README.md manually**. To make changes to the README:
19 |
20 | 1. Edit README_js.md
21 | 2. Run `npm run docs` to regenerate README.md
22 | 3. If using VSCode, it's
23 |
24 | ## Testing
25 |
26 | ```shell
27 | npm test
28 | ```
29 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2010-2020 Robert Kieffer and other contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # uuid [](https://github.com/uuidjs/uuid/actions?query=workflow%3ACI) [](https://github.com/uuidjs/uuid/actions/workflows/browser.yml)
6 |
7 | For the creation of [RFC9562](https://www.rfc-editor.org/rfc/rfc9562.html) (formerly [RFC4122](https://www.rfc-editor.org/rfc/rfc4122.html)) UUIDs
8 |
9 | - **Complete** - Support for all RFC9562 UUID versions
10 | - **Cross-platform** - Support for...
11 | - ESM & Common JS
12 | - [Typescript](#support)
13 | - [Chrome, Safari, Firefox, and Edge](#support)
14 | - [NodeJS](#support)
15 | - [React Native / Expo](#react-native--expo)
16 | - **Secure** - Uses modern `crypto` API for random values
17 | - **Compact** - Zero-dependency, [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking)
18 | - **CLI** - [`uuid` command line](#command-line) utility
19 |
20 |
21 | > [!NOTE]
22 | > `uuid@11` is now available: See the [CHANGELOG](./CHANGELOG.md) for details. TL;DR:
23 | > * TypeScript support is now included (remove `@types/uuid` from your dependencies)
24 | > * Subtle changes to how the `options` arg is interpreted for `v1()`, `v6()`, and `v7()`. [See details](#options-handling-for-timestamp-uuids)
25 | > * Binary UUIDs are now `Uint8Array`s. (May impact callers of `parse()`, `stringify()`, or that pass an `option#buf` argument to `v1()`-`v7()`.)
26 |
27 | ## Quickstart
28 |
29 | **1. Install**
30 |
31 | ```shell
32 | npm install uuid
33 | ```
34 |
35 | **2. Create a UUID**
36 |
37 | ESM-syntax (must use named exports):
38 |
39 | ```javascript
40 | import { v4 as uuidv4 } from 'uuid';
41 | uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
42 | ```
43 |
44 | ... CommonJS:
45 |
46 | ```javascript
47 | const { v4: uuidv4 } = require('uuid');
48 | uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
49 | ```
50 |
51 | For timestamp UUIDs, namespace UUIDs, and other options read on ...
52 |
53 | ## API Summary
54 |
55 | | | | |
56 | | --- | --- | --- |
57 | | [`uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | New in `uuid@8.3` |
58 | | [`uuid.MAX`](#uuidmax) | The max UUID string (all ones) | New in `uuid@9.1` |
59 | | [`uuid.parse()`](#uuidparsestr) | Convert UUID string to array of bytes | New in `uuid@8.3` |
60 | | [`uuid.stringify()`](#uuidstringifyarr-offset) | Convert array of bytes to UUID string | New in `uuid@8.3` |
61 | | [`uuid.v1()`](#uuidv1options-buffer-offset) | Create a version 1 (timestamp) UUID | |
62 | | [`uuid.v1ToV6()`](#uuidv1tov6uuid) | Create a version 6 UUID from a version 1 UUID | New in `uuid@10` |
63 | | [`uuid.v3()`](#uuidv3name-namespace-buffer-offset) | Create a version 3 (namespace w/ MD5) UUID | |
64 | | [`uuid.v4()`](#uuidv4options-buffer-offset) | Create a version 4 (random) UUID | |
65 | | [`uuid.v5()`](#uuidv5name-namespace-buffer-offset) | Create a version 5 (namespace w/ SHA-1) UUID | |
66 | | [`uuid.v6()`](#uuidv6options-buffer-offset) | Create a version 6 (timestamp, reordered) UUID | New in `uuid@10` |
67 | | [`uuid.v6ToV1()`](#uuidv6tov1uuid) | Create a version 1 UUID from a version 6 UUID | New in `uuid@10` |
68 | | [`uuid.v7()`](#uuidv7options-buffer-offset) | Create a version 7 (Unix Epoch time-based) UUID | New in `uuid@10` |
69 | | ~~[`uuid.v8()`](#uuidv8)~~ | "Intentionally left blank" | |
70 | | [`uuid.validate()`](#uuidvalidatestr) | Test a string to see if it is a valid UUID | New in `uuid@8.3` |
71 | | [`uuid.version()`](#uuidversionstr) | Detect RFC version of a UUID | New in `uuid@8.3` |
72 |
73 | ## API
74 |
75 | ### uuid.NIL
76 |
77 | The nil UUID string (all zeros).
78 |
79 | Example:
80 |
81 | ```javascript
82 | import { NIL as NIL_UUID } from 'uuid';
83 |
84 | NIL_UUID; // ⇨ '00000000-0000-0000-0000-000000000000'
85 | ```
86 |
87 | ### uuid.MAX
88 |
89 | The max UUID string (all ones).
90 |
91 | Example:
92 |
93 | ```javascript
94 | import { MAX as MAX_UUID } from 'uuid';
95 |
96 | MAX_UUID; // ⇨ 'ffffffff-ffff-ffff-ffff-ffffffffffff'
97 | ```
98 |
99 | ### uuid.parse(str)
100 |
101 | Convert UUID string to array of bytes
102 |
103 | | | |
104 | | --------- | ---------------------------------------- |
105 | | `str` | A valid UUID `String` |
106 | | _returns_ | `Uint8Array[16]` |
107 | | _throws_ | `TypeError` if `str` is not a valid UUID |
108 |
109 |
110 | > [!NOTE]
111 | > Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
112 |
113 | Example:
114 |
115 | ```javascript
116 | import { parse as uuidParse } from 'uuid';
117 |
118 | // Parse a UUID
119 | uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨
120 | // Uint8Array(16) [
121 | // 110, 192, 189, 127, 17,
122 | // 192, 67, 218, 151, 94,
123 | // 42, 138, 217, 235, 174,
124 | // 11
125 | // ]
126 | ```
127 |
128 | ### uuid.stringify(arr[, offset])
129 |
130 | Convert array of bytes to UUID string
131 |
132 | | | |
133 | | -------------- | ---------------------------------------------------------------------------- |
134 | | `arr` | `Array`-like collection of 16 values (starting from `offset`) between 0-255. |
135 | | [`offset` = 0] | `Number` Starting index in the Array |
136 | | _returns_ | `String` |
137 | | _throws_ | `TypeError` if a valid UUID string cannot be generated |
138 |
139 |
140 | > [!NOTE]
141 | > Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
142 |
143 | Example:
144 |
145 | ```javascript
146 | import { stringify as uuidStringify } from 'uuid';
147 |
148 | const uuidBytes = Uint8Array.of(
149 | 0x6e,
150 | 0xc0,
151 | 0xbd,
152 | 0x7f,
153 | 0x11,
154 | 0xc0,
155 | 0x43,
156 | 0xda,
157 | 0x97,
158 | 0x5e,
159 | 0x2a,
160 | 0x8a,
161 | 0xd9,
162 | 0xeb,
163 | 0xae,
164 | 0x0b
165 | );
166 |
167 | uuidStringify(uuidBytes); // ⇨ '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'
168 | ```
169 |
170 | ### uuid.v1([options[, buffer[, offset]]])
171 |
172 | Create an RFC version 1 (timestamp) UUID
173 |
174 | | | |
175 | | --- | --- |
176 | | [`options`] | `Object` with one or more of the following properties: |
177 | | [`options.node = (random)` ] | RFC "node" field as an `Array[6]` of byte values (per 4.1.6) |
178 | | [`options.clockseq = (random)`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff |
179 | | [`options.msecs = (current time)`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) |
180 | | [`options.nsecs = 0`] | RFC "timestamp" field (`Number` of nanoseconds to add to `msecs`, should be 0-10,000) |
181 | | [`options.random = (random)`] | `Array` of 16 random bytes (0-255) used to generate other fields, above |
182 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
183 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
184 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
185 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
186 | | _throws_ | `Error` if more than 10M UUIDs/sec are requested |
187 |
188 |
189 | > [!NOTE]
190 | > The default [node id](https://datatracker.ietf.org/doc/html/rfc9562#section-5.1) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process.
191 |
192 |
193 | > [!NOTE]
194 | > `options.random` and `options.rng` are only meaningful on the very first call to `v1()`, where they may be passed to initialize the internal `node` and `clockseq` fields.
195 |
196 | Example:
197 |
198 | ```javascript
199 | import { v1 as uuidv1 } from 'uuid';
200 |
201 | uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-9bdd-2b0d7b3dcb6d'
202 | ```
203 |
204 | Example using `options`:
205 |
206 | ```javascript
207 | import { v1 as uuidv1 } from 'uuid';
208 |
209 | const options = {
210 | node: Uint8Array.of(0x01, 0x23, 0x45, 0x67, 0x89, 0xab),
211 | clockseq: 0x1234,
212 | msecs: new Date('2011-11-01').getTime(),
213 | nsecs: 5678,
214 | };
215 | uuidv1(options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'
216 | ```
217 |
218 | ### uuid.v1ToV6(uuid)
219 |
220 | Convert a UUID from version 1 to version 6
221 |
222 | ```javascript
223 | import { v1ToV6 } from 'uuid';
224 |
225 | v1ToV6('92f62d9e-22c4-11ef-97e9-325096b39f47'); // ⇨ '1ef22c49-2f62-6d9e-97e9-325096b39f47'
226 | ```
227 |
228 | ### uuid.v3(name, namespace[, buffer[, offset]])
229 |
230 | Create an RFC version 3 (namespace w/ MD5) UUID
231 |
232 | API is identical to `v5()`, but uses "v3" instead.
233 |
234 |
235 | > [!IMPORTANT]
236 | > Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_."
237 |
238 | ### uuid.v4([options[, buffer[, offset]]])
239 |
240 | Create an RFC version 4 (random) UUID
241 |
242 | | | |
243 | | --- | --- |
244 | | [`options`] | `Object` with one or more of the following properties: |
245 | | [`options.random`] | `Array` of 16 random bytes (0-255) |
246 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
247 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
248 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
249 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
250 |
251 | Example:
252 |
253 | ```javascript
254 | import { v4 as uuidv4 } from 'uuid';
255 |
256 | uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
257 | ```
258 |
259 | Example using predefined `random` values:
260 |
261 | ```javascript
262 | import { v4 as uuidv4 } from 'uuid';
263 |
264 | const v4options = {
265 | random: Uint8Array.of(
266 | 0x10,
267 | 0x91,
268 | 0x56,
269 | 0xbe,
270 | 0xc4,
271 | 0xfb,
272 | 0xc1,
273 | 0xea,
274 | 0x71,
275 | 0xb4,
276 | 0xef,
277 | 0xe1,
278 | 0x67,
279 | 0x1c,
280 | 0x58,
281 | 0x36
282 | ),
283 | };
284 | uuidv4(v4options); // ⇨ '109156be-c4fb-41ea-b1b4-efe1671c5836'
285 | ```
286 |
287 | ### uuid.v5(name, namespace[, buffer[, offset]])
288 |
289 | Create an RFC version 5 (namespace w/ SHA-1) UUID
290 |
291 | | | |
292 | | --- | --- |
293 | | `name` | `String \| Array` |
294 | | `namespace` | `String \| Array[16]` Namespace UUID |
295 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
296 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
297 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
298 |
299 |
300 | > [!NOTE]
301 | > The RFC `DNS` and `URL` namespaces are available as `v5.DNS` and `v5.URL`.
302 |
303 | Example with custom namespace:
304 |
305 | ```javascript
306 | import { v5 as uuidv5 } from 'uuid';
307 |
308 | // Define a custom namespace. Readers, create your own using something like
309 | // https://www.uuidgenerator.net/
310 | const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
311 |
312 | uuidv5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681'
313 | ```
314 |
315 | Example with RFC `URL` namespace:
316 |
317 | ```javascript
318 | import { v5 as uuidv5 } from 'uuid';
319 |
320 | uuidv5('https://www.w3.org/', uuidv5.URL); // ⇨ 'c106a26a-21bb-5538-8bf2-57095d1976c1'
321 | ```
322 |
323 | ### uuid.v6([options[, buffer[, offset]]])
324 |
325 | Create an RFC version 6 (timestamp, reordered) UUID
326 |
327 | This method takes the same arguments as uuid.v1().
328 |
329 | ```javascript
330 | import { v6 as uuidv6 } from 'uuid';
331 |
332 | uuidv6(); // ⇨ '1e940672-c5ea-64c0-9b5d-ab8dfbbd4bed'
333 | ```
334 |
335 | Example using `options`:
336 |
337 | ```javascript
338 | import { v6 as uuidv6 } from 'uuid';
339 |
340 | const options = {
341 | node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
342 | clockseq: 0x1234,
343 | msecs: new Date('2011-11-01').getTime(),
344 | nsecs: 5678,
345 | };
346 | uuidv6(options); // ⇨ '1e1041c7-10b9-662e-9234-0123456789ab'
347 | ```
348 |
349 | ### uuid.v6ToV1(uuid)
350 |
351 | Convert a UUID from version 6 to version 1
352 |
353 | ```javascript
354 | import { v6ToV1 } from 'uuid';
355 |
356 | v6ToV1('1ef22c49-2f62-6d9e-97e9-325096b39f47'); // ⇨ '92f62d9e-22c4-11ef-97e9-325096b39f47'
357 | ```
358 |
359 | ### uuid.v7([options[, buffer[, offset]]])
360 |
361 | Create an RFC version 7 (random) UUID
362 |
363 | | | |
364 | | --- | --- |
365 | | [`options`] | `Object` with one or more of the following properties: |
366 | | [`options.msecs = (current time)`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) |
367 | | [`options.random = (random)`] | `Array` of 16 random bytes (0-255) used to generate other fields, above |
368 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
369 | | [`options.seq = (random)`] | 32-bit sequence `Number` between 0 - 0xffffffff. This may be provided to help ensure uniqueness for UUIDs generated within the same millisecond time interval. Default = random value. |
370 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
371 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
372 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
373 |
374 | Example:
375 |
376 | ```javascript
377 | import { v7 as uuidv7 } from 'uuid';
378 |
379 | uuidv7(); // ⇨ '01695553-c90c-705a-b56d-778dfbbd4bed'
380 | ```
381 |
382 | ### ~~uuid.v8()~~
383 |
384 | **_"Intentionally left blank"_**
385 |
386 |
387 | > [!NOTE]
388 | > Version 8 (experimental) UUIDs are "[for experimental or vendor-specific use cases](https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-8)". The RFC does not define a creation algorithm for them, which is why this package does not offer a `v8()` method. The `validate()` and `version()` methods do work with such UUIDs, however.
389 |
390 | ### uuid.validate(str)
391 |
392 | Test a string to see if it is a valid UUID
393 |
394 | | | |
395 | | --------- | --------------------------------------------------- |
396 | | `str` | `String` to validate |
397 | | _returns_ | `true` if string is a valid UUID, `false` otherwise |
398 |
399 | Example:
400 |
401 | ```javascript
402 | import { validate as uuidValidate } from 'uuid';
403 |
404 | uuidValidate('not a UUID'); // ⇨ false
405 | uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ true
406 | ```
407 |
408 | Using `validate` and `version` together it is possible to do per-version validation, e.g. validate for only v4 UUIds.
409 |
410 | ```javascript
411 | import { version as uuidVersion } from 'uuid';
412 | import { validate as uuidValidate } from 'uuid';
413 |
414 | function uuidValidateV4(uuid) {
415 | return uuidValidate(uuid) && uuidVersion(uuid) === 4;
416 | }
417 |
418 | const v1Uuid = 'd9428888-122b-11e1-b85c-61cd3cbb3210';
419 | const v4Uuid = '109156be-c4fb-41ea-b1b4-efe1671c5836';
420 |
421 | uuidValidateV4(v4Uuid); // ⇨ true
422 | uuidValidateV4(v1Uuid); // ⇨ false
423 | ```
424 |
425 | ### uuid.version(str)
426 |
427 | Detect RFC version of a UUID
428 |
429 | | | |
430 | | --------- | ---------------------------------------- |
431 | | `str` | A valid UUID `String` |
432 | | _returns_ | `Number` The RFC version of the UUID |
433 | | _throws_ | `TypeError` if `str` is not a valid UUID |
434 |
435 | Example:
436 |
437 | ```javascript
438 | import { version as uuidVersion } from 'uuid';
439 |
440 | uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // ⇨ 1
441 | uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ 4
442 | ```
443 |
444 |
445 | > [!NOTE]
446 | > This method returns `0` for the `NIL` UUID, and `15` for the `MAX` UUID.
447 |
448 | ## Command Line
449 |
450 | UUIDs can be generated from the command line using `uuid`.
451 |
452 | ```shell
453 | $ npx uuid
454 | ddeb27fb-d9a0-4624-be4d-4615062daed4
455 | ```
456 |
457 | The default is to generate version 4 UUIDS, however the other versions are supported. Type `uuid --help` for details:
458 |
459 | ```shell
460 | $ npx uuid --help
461 |
462 | Usage:
463 | uuid
464 | uuid v1
465 | uuid v3
466 | uuid v4
467 | uuid v5
468 | uuid v7
469 | uuid --help
470 |
471 | Note: may be "URL" or "DNS" to use the corresponding UUIDs
472 | defined by RFC9562
473 | ```
474 |
475 | ## `options` Handling for Timestamp UUIDs
476 |
477 | Prior to `uuid@11`, it was possible for `options` state to interfere with the internal state used to ensure uniqueness of timestamp-based UUIDs (the `v1()`, `v6()`, and `v7()` methods). Starting with `uuid@11`, this issue has been addressed by using the presence of the `options` argument as a flag to select between two possible behaviors:
478 |
479 | - Without `options`: Internal state is utilized to improve UUID uniqueness.
480 | - With `options`: Internal state is **NOT** used and, instead, appropriate defaults are applied as needed.
481 |
482 | ## Support
483 |
484 | **Browsers**: `uuid` [builds are tested](/uuidjs/uuid/blob/main/wdio.conf.js) against the latest version of desktop Chrome, Safari, Firefox, and Edge. Mobile versions of these same browsers are expected to work but aren't currently tested.
485 |
486 | **Node**: `uuid` [builds are tested](https://github.com/uuidjs/uuid/blob/main/.github/workflows/ci.yml#L26-L27) against node ([LTS releases](https://github.com/nodejs/Release)), plus one prior. E.g. `node@18` is in maintainence mode, and `node@22` is the current LTS release. So `uuid` supports `node@16`-`node@22`.
487 |
488 | **Typescript**: TS versions released within the past two years are supported. [source](https://github.com/microsoft/TypeScript/issues/49088#issuecomment-2468723715)
489 |
490 | ## Known issues
491 |
492 |
493 |
494 | ### "getRandomValues() not supported"
495 |
496 | This error occurs in environments where the standard [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) API is not supported. This issue can be resolved by adding an appropriate polyfill:
497 |
498 | #### React Native / Expo
499 |
500 | 1. Install [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values#readme)
501 | 1. Import it _before_ `uuid`. Since `uuid` might also appear as a transitive dependency of some other imports it's safest to just import `react-native-get-random-values` as the very first thing in your entry point:
502 |
503 | ```javascript
504 | import 'react-native-get-random-values';
505 | import { v4 as uuidv4 } from 'uuid';
506 | ```
507 |
508 | ---
509 |
510 | Markdown generated from [README_js.md](README_js.md) by
511 |
--------------------------------------------------------------------------------
/README_js.md:
--------------------------------------------------------------------------------
1 | ```javascript --hide
2 | runmd.onRequire = (path) => {
3 | if (path == 'rng') return fun;
4 | return path.replace(/^uuid/, './dist/cjs/');
5 | };
6 |
7 | // Shim Date and crypto so generated ids are consistent across doc revisions
8 | runmd.Date.now = () => 1551914748172;
9 |
10 | let seed = 0xdefaced;
11 | require('crypto').randomFillSync = function (a) {
12 | for (let i = 0; i < 16; i++) a[i] = (seed = (seed * 0x41a7) & 0x7fffffff) & 0xff;
13 | return a;
14 | };
15 |
16 | // Prevent usage of native randomUUID implementation to ensure deterministic UUIDs
17 | require('crypto').randomUUID = undefined;
18 | ```
19 |
20 | # uuid [](https://github.com/uuidjs/uuid/actions?query=workflow%3ACI) [](https://github.com/uuidjs/uuid/actions/workflows/browser.yml)
21 |
22 | For the creation of [RFC9562](https://www.rfc-editor.org/rfc/rfc9562.html) (formerly [RFC4122](https://www.rfc-editor.org/rfc/rfc4122.html)) UUIDs
23 |
24 | - **Complete** - Support for all RFC9562 UUID versions
25 | - **Cross-platform** - Support for...
26 | - ESM & Common JS
27 | - [Typescript](#support)
28 | - [Chrome, Safari, Firefox, and Edge](#support)
29 | - [NodeJS](#support)
30 | - [React Native / Expo](#react-native--expo)
31 | - **Secure** - Uses modern `crypto` API for random values
32 | - **Compact** - Zero-dependency, [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking)
33 | - **CLI** - [`uuid` command line](#command-line) utility
34 |
35 |
36 | > [!NOTE]
37 | > `uuid@11` is now available: See the [CHANGELOG](./CHANGELOG.md) for details. TL;DR:
38 | > * TypeScript support is now included (remove `@types/uuid` from your dependencies)
39 | > * Subtle changes to how the `options` arg is interpreted for `v1()`, `v6()`, and `v7()`. [See details](#options-handling-for-timestamp-uuids)
40 | > * Binary UUIDs are now `Uint8Array`s. (May impact callers of `parse()`, `stringify()`, or that pass an `option#buf` argument to `v1()`-`v7()`.)
41 |
42 | ## Quickstart
43 |
44 | **1. Install**
45 |
46 | ```shell
47 | npm install uuid
48 | ```
49 |
50 | **2. Create a UUID**
51 |
52 | ESM-syntax (must use named exports):
53 |
54 | ```javascript --run
55 | import { v4 as uuidv4 } from 'uuid';
56 | uuidv4(); // RESULT
57 | ```
58 |
59 | ... CommonJS:
60 |
61 | ```javascript --run
62 | const { v4: uuidv4 } = require('uuid');
63 | uuidv4(); // RESULT
64 | ```
65 |
66 | For timestamp UUIDs, namespace UUIDs, and other options read on ...
67 |
68 | ## API Summary
69 |
70 | | | | |
71 | | --- | --- | --- |
72 | | [`uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | New in `uuid@8.3` |
73 | | [`uuid.MAX`](#uuidmax) | The max UUID string (all ones) | New in `uuid@9.1` |
74 | | [`uuid.parse()`](#uuidparsestr) | Convert UUID string to array of bytes | New in `uuid@8.3` |
75 | | [`uuid.stringify()`](#uuidstringifyarr-offset) | Convert array of bytes to UUID string | New in `uuid@8.3` |
76 | | [`uuid.v1()`](#uuidv1options-buffer-offset) | Create a version 1 (timestamp) UUID | |
77 | | [`uuid.v1ToV6()`](#uuidv1tov6uuid) | Create a version 6 UUID from a version 1 UUID | New in `uuid@10` |
78 | | [`uuid.v3()`](#uuidv3name-namespace-buffer-offset) | Create a version 3 (namespace w/ MD5) UUID | |
79 | | [`uuid.v4()`](#uuidv4options-buffer-offset) | Create a version 4 (random) UUID | |
80 | | [`uuid.v5()`](#uuidv5name-namespace-buffer-offset) | Create a version 5 (namespace w/ SHA-1) UUID | |
81 | | [`uuid.v6()`](#uuidv6options-buffer-offset) | Create a version 6 (timestamp, reordered) UUID | New in `uuid@10` |
82 | | [`uuid.v6ToV1()`](#uuidv6tov1uuid) | Create a version 1 UUID from a version 6 UUID | New in `uuid@10` |
83 | | [`uuid.v7()`](#uuidv7options-buffer-offset) | Create a version 7 (Unix Epoch time-based) UUID | New in `uuid@10` |
84 | | ~~[`uuid.v8()`](#uuidv8)~~ | "Intentionally left blank" | |
85 | | [`uuid.validate()`](#uuidvalidatestr) | Test a string to see if it is a valid UUID | New in `uuid@8.3` |
86 | | [`uuid.version()`](#uuidversionstr) | Detect RFC version of a UUID | New in `uuid@8.3` |
87 |
88 | ## API
89 |
90 | ### uuid.NIL
91 |
92 | The nil UUID string (all zeros).
93 |
94 | Example:
95 |
96 | ```javascript --run
97 | import { NIL as NIL_UUID } from 'uuid';
98 |
99 | NIL_UUID; // RESULT
100 | ```
101 |
102 | ### uuid.MAX
103 |
104 | The max UUID string (all ones).
105 |
106 | Example:
107 |
108 | ```javascript --run
109 | import { MAX as MAX_UUID } from 'uuid';
110 |
111 | MAX_UUID; // RESULT
112 | ```
113 |
114 | ### uuid.parse(str)
115 |
116 | Convert UUID string to array of bytes
117 |
118 | | | |
119 | | --------- | ---------------------------------------- |
120 | | `str` | A valid UUID `String` |
121 | | _returns_ | `Uint8Array[16]` |
122 | | _throws_ | `TypeError` if `str` is not a valid UUID |
123 |
124 |
125 | > [!NOTE]
126 | > Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
127 |
128 | Example:
129 |
130 | ```javascript --run
131 | import { parse as uuidParse } from 'uuid';
132 |
133 | // Parse a UUID
134 | uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT
135 | ```
136 |
137 | ### uuid.stringify(arr[, offset])
138 |
139 | Convert array of bytes to UUID string
140 |
141 | | | |
142 | | -------------- | ---------------------------------------------------------------------------- |
143 | | `arr` | `Array`-like collection of 16 values (starting from `offset`) between 0-255. |
144 | | [`offset` = 0] | `Number` Starting index in the Array |
145 | | _returns_ | `String` |
146 | | _throws_ | `TypeError` if a valid UUID string cannot be generated |
147 |
148 |
149 | > [!NOTE]
150 | > Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
151 |
152 | Example:
153 |
154 | ```javascript --run
155 | import { stringify as uuidStringify } from 'uuid';
156 |
157 | const uuidBytes = Uint8Array.of(
158 | 0x6e,
159 | 0xc0,
160 | 0xbd,
161 | 0x7f,
162 | 0x11,
163 | 0xc0,
164 | 0x43,
165 | 0xda,
166 | 0x97,
167 | 0x5e,
168 | 0x2a,
169 | 0x8a,
170 | 0xd9,
171 | 0xeb,
172 | 0xae,
173 | 0x0b
174 | );
175 |
176 | uuidStringify(uuidBytes); // RESULT
177 | ```
178 |
179 | ### uuid.v1([options[, buffer[, offset]]])
180 |
181 | Create an RFC version 1 (timestamp) UUID
182 |
183 | | | |
184 | | --- | --- |
185 | | [`options`] | `Object` with one or more of the following properties: |
186 | | [`options.node = (random)` ] | RFC "node" field as an `Array[6]` of byte values (per 4.1.6) |
187 | | [`options.clockseq = (random)`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff |
188 | | [`options.msecs = (current time)`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) |
189 | | [`options.nsecs = 0`] | RFC "timestamp" field (`Number` of nanoseconds to add to `msecs`, should be 0-10,000) |
190 | | [`options.random = (random)`] | `Array` of 16 random bytes (0-255) used to generate other fields, above |
191 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
192 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
193 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
194 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
195 | | _throws_ | `Error` if more than 10M UUIDs/sec are requested |
196 |
197 |
198 | > [!NOTE]
199 | > The default [node id](https://datatracker.ietf.org/doc/html/rfc9562#section-5.1) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process.
200 |
201 |
202 | > [!NOTE]
203 | > `options.random` and `options.rng` are only meaningful on the very first call to `v1()`, where they may be passed to initialize the internal `node` and `clockseq` fields.
204 |
205 | Example:
206 |
207 | ```javascript --run
208 | import { v1 as uuidv1 } from 'uuid';
209 |
210 | uuidv1(); // RESULT
211 | ```
212 |
213 | Example using `options`:
214 |
215 | ```javascript --run
216 | import { v1 as uuidv1 } from 'uuid';
217 |
218 | const options = {
219 | node: Uint8Array.of(0x01, 0x23, 0x45, 0x67, 0x89, 0xab),
220 | clockseq: 0x1234,
221 | msecs: new Date('2011-11-01').getTime(),
222 | nsecs: 5678,
223 | };
224 | uuidv1(options); // RESULT
225 | ```
226 |
227 | ### uuid.v1ToV6(uuid)
228 |
229 | Convert a UUID from version 1 to version 6
230 |
231 | ```javascript --run
232 | import { v1ToV6 } from 'uuid';
233 |
234 | v1ToV6('92f62d9e-22c4-11ef-97e9-325096b39f47'); // RESULT
235 | ```
236 |
237 | ### uuid.v3(name, namespace[, buffer[, offset]])
238 |
239 | Create an RFC version 3 (namespace w/ MD5) UUID
240 |
241 | API is identical to `v5()`, but uses "v3" instead.
242 |
243 |
244 | > [!IMPORTANT]
245 | > Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_."
246 |
247 | ### uuid.v4([options[, buffer[, offset]]])
248 |
249 | Create an RFC version 4 (random) UUID
250 |
251 | | | |
252 | | --- | --- |
253 | | [`options`] | `Object` with one or more of the following properties: |
254 | | [`options.random`] | `Array` of 16 random bytes (0-255) |
255 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
256 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
257 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
258 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
259 |
260 | Example:
261 |
262 | ```javascript --run
263 | import { v4 as uuidv4 } from 'uuid';
264 |
265 | uuidv4(); // RESULT
266 | ```
267 |
268 | Example using predefined `random` values:
269 |
270 | ```javascript --run
271 | import { v4 as uuidv4 } from 'uuid';
272 |
273 | const v4options = {
274 | random: Uint8Array.of(
275 | 0x10,
276 | 0x91,
277 | 0x56,
278 | 0xbe,
279 | 0xc4,
280 | 0xfb,
281 | 0xc1,
282 | 0xea,
283 | 0x71,
284 | 0xb4,
285 | 0xef,
286 | 0xe1,
287 | 0x67,
288 | 0x1c,
289 | 0x58,
290 | 0x36
291 | ),
292 | };
293 | uuidv4(v4options); // RESULT
294 | ```
295 |
296 | ### uuid.v5(name, namespace[, buffer[, offset]])
297 |
298 | Create an RFC version 5 (namespace w/ SHA-1) UUID
299 |
300 | | | |
301 | | --- | --- |
302 | | `name` | `String \| Array` |
303 | | `namespace` | `String \| Array[16]` Namespace UUID |
304 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
305 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
306 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
307 |
308 |
309 | > [!NOTE]
310 | > The RFC `DNS` and `URL` namespaces are available as `v5.DNS` and `v5.URL`.
311 |
312 | Example with custom namespace:
313 |
314 | ```javascript --run
315 | import { v5 as uuidv5 } from 'uuid';
316 |
317 | // Define a custom namespace. Readers, create your own using something like
318 | // https://www.uuidgenerator.net/
319 | const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
320 |
321 | uuidv5('Hello, World!', MY_NAMESPACE); // RESULT
322 | ```
323 |
324 | Example with RFC `URL` namespace:
325 |
326 | ```javascript --run
327 | import { v5 as uuidv5 } from 'uuid';
328 |
329 | uuidv5('https://www.w3.org/', uuidv5.URL); // RESULT
330 | ```
331 |
332 | ### uuid.v6([options[, buffer[, offset]]])
333 |
334 | Create an RFC version 6 (timestamp, reordered) UUID
335 |
336 | This method takes the same arguments as uuid.v1().
337 |
338 | ```javascript --run
339 | import { v6 as uuidv6 } from 'uuid';
340 |
341 | uuidv6(); // RESULT
342 | ```
343 |
344 | Example using `options`:
345 |
346 | ```javascript --run
347 | import { v6 as uuidv6 } from 'uuid';
348 |
349 | const options = {
350 | node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
351 | clockseq: 0x1234,
352 | msecs: new Date('2011-11-01').getTime(),
353 | nsecs: 5678,
354 | };
355 | uuidv6(options); // RESULT
356 | ```
357 |
358 | ### uuid.v6ToV1(uuid)
359 |
360 | Convert a UUID from version 6 to version 1
361 |
362 | ```javascript --run
363 | import { v6ToV1 } from 'uuid';
364 |
365 | v6ToV1('1ef22c49-2f62-6d9e-97e9-325096b39f47'); // RESULT
366 | ```
367 |
368 | ### uuid.v7([options[, buffer[, offset]]])
369 |
370 | Create an RFC version 7 (random) UUID
371 |
372 | | | |
373 | | --- | --- |
374 | | [`options`] | `Object` with one or more of the following properties: |
375 | | [`options.msecs = (current time)`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) |
376 | | [`options.random = (random)`] | `Array` of 16 random bytes (0-255) used to generate other fields, above |
377 | | [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) |
378 | | [`options.seq = (random)`] | 32-bit sequence `Number` between 0 - 0xffffffff. This may be provided to help ensure uniqueness for UUIDs generated within the same millisecond time interval. Default = random value. |
379 | | [`buffer`] | `Uint8Array` or `Uint8Array` subtype (e.g. Node.js `Buffer`). If provided, binary UUID is written into the array, starting at `offset` |
380 | | [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` |
381 | | _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` |
382 |
383 | Example:
384 |
385 | ```javascript --run
386 | import { v7 as uuidv7 } from 'uuid';
387 |
388 | uuidv7(); // RESULT
389 | ```
390 |
391 | ### ~~uuid.v8()~~
392 |
393 | **_"Intentionally left blank"_**
394 |
395 |
396 | > [!NOTE]
397 | > Version 8 (experimental) UUIDs are "[for experimental or vendor-specific use cases](https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-8)". The RFC does not define a creation algorithm for them, which is why this package does not offer a `v8()` method. The `validate()` and `version()` methods do work with such UUIDs, however.
398 |
399 | ### uuid.validate(str)
400 |
401 | Test a string to see if it is a valid UUID
402 |
403 | | | |
404 | | --------- | --------------------------------------------------- |
405 | | `str` | `String` to validate |
406 | | _returns_ | `true` if string is a valid UUID, `false` otherwise |
407 |
408 | Example:
409 |
410 | ```javascript --run
411 | import { validate as uuidValidate } from 'uuid';
412 |
413 | uuidValidate('not a UUID'); // RESULT
414 | uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT
415 | ```
416 |
417 | Using `validate` and `version` together it is possible to do per-version validation, e.g. validate for only v4 UUIds.
418 |
419 | ```javascript --run
420 | import { version as uuidVersion } from 'uuid';
421 | import { validate as uuidValidate } from 'uuid';
422 |
423 | function uuidValidateV4(uuid) {
424 | return uuidValidate(uuid) && uuidVersion(uuid) === 4;
425 | }
426 |
427 | const v1Uuid = 'd9428888-122b-11e1-b85c-61cd3cbb3210';
428 | const v4Uuid = '109156be-c4fb-41ea-b1b4-efe1671c5836';
429 |
430 | uuidValidateV4(v4Uuid); // RESULT
431 | uuidValidateV4(v1Uuid); // RESULT
432 | ```
433 |
434 | ### uuid.version(str)
435 |
436 | Detect RFC version of a UUID
437 |
438 | | | |
439 | | --------- | ---------------------------------------- |
440 | | `str` | A valid UUID `String` |
441 | | _returns_ | `Number` The RFC version of the UUID |
442 | | _throws_ | `TypeError` if `str` is not a valid UUID |
443 |
444 | Example:
445 |
446 | ```javascript --run
447 | import { version as uuidVersion } from 'uuid';
448 |
449 | uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // RESULT
450 | uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // RESULT
451 | ```
452 |
453 |
454 | > [!NOTE]
455 | > This method returns `0` for the `NIL` UUID, and `15` for the `MAX` UUID.
456 |
457 | ## Command Line
458 |
459 | UUIDs can be generated from the command line using `uuid`.
460 |
461 | ```shell
462 | $ npx uuid
463 | ddeb27fb-d9a0-4624-be4d-4615062daed4
464 | ```
465 |
466 | The default is to generate version 4 UUIDS, however the other versions are supported. Type `uuid --help` for details:
467 |
468 | ```shell
469 | $ npx uuid --help
470 |
471 | Usage:
472 | uuid
473 | uuid v1
474 | uuid v3
475 | uuid v4
476 | uuid v5
477 | uuid v7
478 | uuid --help
479 |
480 | Note: may be "URL" or "DNS" to use the corresponding UUIDs
481 | defined by RFC9562
482 | ```
483 |
484 | ## `options` Handling for Timestamp UUIDs
485 |
486 | Prior to `uuid@11`, it was possible for `options` state to interfere with the internal state used to ensure uniqueness of timestamp-based UUIDs (the `v1()`, `v6()`, and `v7()` methods). Starting with `uuid@11`, this issue has been addressed by using the presence of the `options` argument as a flag to select between two possible behaviors:
487 |
488 | - Without `options`: Internal state is utilized to improve UUID uniqueness.
489 | - With `options`: Internal state is **NOT** used and, instead, appropriate defaults are applied as needed.
490 |
491 | ## Support
492 |
493 | **Browsers**: `uuid` [builds are tested](/uuidjs/uuid/blob/main/wdio.conf.js) against the latest version of desktop Chrome, Safari, Firefox, and Edge. Mobile versions of these same browsers are expected to work but aren't currently tested.
494 |
495 | **Node**: `uuid` [builds are tested](https://github.com/uuidjs/uuid/blob/main/.github/workflows/ci.yml#L26-L27) against node ([LTS releases](https://github.com/nodejs/Release)), plus one prior. E.g. `node@18` is in maintainence mode, and `node@22` is the current LTS release. So `uuid` supports `node@16`-`node@22`.
496 |
497 | **Typescript**: TS versions released within the past two years are supported. [source](https://github.com/microsoft/TypeScript/issues/49088#issuecomment-2468723715)
498 |
499 | ## Known issues
500 |
501 |
502 |
503 | ### "getRandomValues() not supported"
504 |
505 | This error occurs in environments where the standard [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) API is not supported. This issue can be resolved by adding an appropriate polyfill:
506 |
507 | #### React Native / Expo
508 |
509 | 1. Install [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values#readme)
510 | 1. Import it _before_ `uuid`. Since `uuid` might also appear as a transitive dependency of some other imports it's safest to just import `react-native-get-random-values` as the very first thing in your entry point:
511 |
512 | ```javascript
513 | import 'react-native-get-random-values';
514 | import { v4 as uuidv4 } from 'uuid';
515 | ```
516 |
--------------------------------------------------------------------------------
/bundlewatch.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "ci": {
3 | "repoBranchBase": "main",
4 | "trackBranches": ["main"]
5 | },
6 | "files": [
7 | { "path": "./examples/browser-rollup/dist/v1-size.js", "maxSize": "1.0 kB" },
8 | { "path": "./examples/browser-rollup/dist/v3-size.js", "maxSize": "2.1 kB" },
9 | { "path": "./examples/browser-rollup/dist/v4-size.js", "maxSize": "0.7 kB" },
10 | { "path": "./examples/browser-rollup/dist/v5-size.js", "maxSize": "1.5 kB" },
11 | { "path": "./examples/browser-rollup/dist/v6-size.js", "maxSize": "1.6 kB" },
12 | { "path": "./examples/browser-rollup/dist/v7-size.js", "maxSize": "0.8 kB" },
13 | { "path": "./examples/browser-webpack/dist/v1-size.js", "maxSize": "1.0 kB" },
14 | { "path": "./examples/browser-webpack/dist/v3-size.js", "maxSize": "2.1 kB" },
15 | { "path": "./examples/browser-webpack/dist/v4-size.js", "maxSize": "0.7 kB" },
16 | { "path": "./examples/browser-webpack/dist/v5-size.js", "maxSize": "1.5 kB" },
17 | { "path": "./examples/browser-webpack/dist/v6-size.js", "maxSize": "1.6 kB" },
18 | { "path": "./examples/browser-webpack/dist/v7-size.js", "maxSize": "0.8 kB" }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
3 | import globals from 'globals';
4 | import neostandard from 'neostandard';
5 | import tseslint from 'typescript-eslint';
6 |
7 | const neostandardConfig = neostandard({ semi: true, noStyle: true });
8 |
9 | export default [
10 | js.configs.recommended,
11 | ...tseslint.configs.recommended,
12 | ...neostandardConfig,
13 | eslintPluginPrettierRecommended,
14 | {
15 | languageOptions: {
16 | ecmaVersion: 'latest',
17 | sourceType: 'module',
18 | globals: {
19 | ...globals.browser,
20 | ...globals.commonjs,
21 | ...globals.jest,
22 | ...globals.node,
23 | },
24 | },
25 | },
26 | {
27 | rules: {
28 | '@typescript-eslint/no-redeclare': 'error',
29 | '@typescript-eslint/no-require-imports': 'off',
30 | 'no-redeclare': 'off',
31 | 'no-var': ['error'],
32 | curly: ['error', 'all'],
33 | },
34 | },
35 | {
36 | ignores: ['eslint.config.cjs', '**/dist/', 'node_modules/'],
37 | },
38 | ];
39 |
--------------------------------------------------------------------------------
/examples/benchmark/README.md:
--------------------------------------------------------------------------------
1 | # uuid Benchmark
2 |
3 | ```
4 | npm install
5 | ```
6 |
7 | ## Node.js
8 |
9 | To run the benchmark in Node.js, run `npm test`.
10 |
11 | ## Browser
12 |
13 | To run the benchmark in the browser run `npm run start`, open `benchmark.html`, and check the console.
14 |
15 | Example output (`uuid@8.0.0`, MacBook Pro (Retina, 13-inch, Early 2015), 3.1 GHz Dual-Core Intel Core i7):
16 |
17 | ```
18 | Starting. Tests take ~1 minute to run ...
19 | uuidv1() x 1,306,861 ops/sec ±2.62% (85 runs sampled)
20 | uuidv1() fill existing array x 4,750,515 ops/sec ±2.76% (88 runs sampled)
21 | uuidv4() x 302,174 ops/sec ±3.06% (81 runs sampled)
22 | uuidv4() fill existing array x 359,703 ops/sec ±3.67% (82 runs sampled)
23 | uuidv3() x 105,667 ops/sec ±3.84% (79 runs sampled)
24 | uuidv5() x 110,886 ops/sec ±2.55% (81 runs sampled)
25 | Fastest is uuidv1() fill existing array
26 | ```
27 |
--------------------------------------------------------------------------------
/examples/benchmark/benchmark.html:
--------------------------------------------------------------------------------
1 |
2 | UUID Benchmark
3 | Please open the Developer Console to view output
4 |
5 |
--------------------------------------------------------------------------------
/examples/benchmark/benchmark.js:
--------------------------------------------------------------------------------
1 | export default function benchmark(uuid, Benchmark) {
2 | console.log('Starting. Tests take ~1 minute to run ...');
3 |
4 | function testParseAndStringify() {
5 | const suite = new Benchmark.Suite({
6 | onError(event) {
7 | console.error(event.target.error);
8 | },
9 | });
10 |
11 | const BYTES = [
12 | 0x0f, 0x5a, 0xbc, 0xd1, 0xc1, 0x94, 0x47, 0xf3, 0x90, 0x5b, 0x2d, 0xf7, 0x26, 0x3a, 0x08,
13 | 0x4b,
14 | ];
15 |
16 | suite
17 | .add('uuid.stringify()', function () {
18 | uuid.stringify(BYTES);
19 | })
20 | .add('uuid.parse()', function () {
21 | uuid.parse('0f5abcd1-c194-47f3-905b-2df7263a084b');
22 | })
23 | .on('cycle', function (event) {
24 | console.log(event.target.toString());
25 | })
26 | .on('complete', function () {
27 | console.log('---\n');
28 | })
29 | .run();
30 | }
31 |
32 | function testGeneration() {
33 | const array = new Array(16);
34 |
35 | const suite = new Benchmark.Suite({
36 | onError(event) {
37 | console.error(event.target.error);
38 | },
39 | });
40 |
41 | suite
42 | .add('uuid.v1()', function () {
43 | uuid.v1();
44 | })
45 | .add('uuid.v1() fill existing array', function () {
46 | try {
47 | uuid.v1(null, array, 0);
48 | } catch {
49 | // The spec (https://datatracker.ietf.org/doc/html/rfc9562#name-timestamp-considerations) defines that only 10M/s v1
50 | // UUIDs can be generated on a single node. This library throws an error if we hit that limit
51 | // (which can happen on modern hardware and modern Node.js versions).
52 | }
53 | })
54 | .add('uuid.v4()', function () {
55 | uuid.v4();
56 | })
57 | .add('uuid.v4() fill existing array', function () {
58 | uuid.v4(null, array, 0);
59 | })
60 | .add('uuid.v4() without native generation', function () {
61 | uuid.v4({}); // passing an object instead of null bypasses native.randomUUID
62 | })
63 | .add('uuid.v3()', function () {
64 | uuid.v3('hello.example.com', uuid.v3.DNS);
65 | })
66 | .add('uuid.v5()', function () {
67 | uuid.v5('hello.example.com', uuid.v5.DNS);
68 | })
69 | .add('uuid.v6()', function () {
70 | uuid.v6();
71 | })
72 | .add('uuid.v7()', function () {
73 | uuid.v7();
74 | })
75 | .add('uuid.v7() fill existing array', function () {
76 | uuid.v7(null, array, 0);
77 | })
78 | .add('uuid.v7() with defined time', function () {
79 | uuid.v7({
80 | msecs: 1645557742000,
81 | });
82 | })
83 | .on('cycle', function (event) {
84 | console.log(event.target.toString());
85 | })
86 | .on('complete', function () {
87 | console.log('Fastest is ' + this.filter('fastest').map('name'));
88 | console.log('---\n');
89 | })
90 | .run();
91 | }
92 |
93 | function testV6Conversion() {
94 | const suite = new Benchmark.Suite({
95 | onError(event) {
96 | console.error(event.target.error);
97 | },
98 | });
99 |
100 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
101 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
102 |
103 | suite
104 | .add('uuid.v1ToV6()', function () {
105 | uuid.v1ToV6(V1_ID);
106 | })
107 | .add('uuid.v6ToV1()', function () {
108 | uuid.v6ToV1(V6_ID);
109 | })
110 | .on('cycle', function (event) {
111 | console.log(event.target.toString());
112 | })
113 | .run();
114 | }
115 |
116 | testParseAndStringify();
117 | testGeneration();
118 | testV6Conversion();
119 | }
120 |
--------------------------------------------------------------------------------
/examples/benchmark/browser.js:
--------------------------------------------------------------------------------
1 | import * as uuid from './node_modules/uuid/dist/esm-browser/index.js';
2 | import './node_modules/lodash/lodash.js';
3 | import './node_modules/benchmark/benchmark.js';
4 |
5 | import benchmark from './benchmark.js';
6 |
7 | benchmark(uuid, window.Benchmark);
8 |
--------------------------------------------------------------------------------
/examples/benchmark/node.js:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 | import Benchmark from 'benchmark';
3 |
4 | import benchmark from './benchmark.js';
5 |
6 | benchmark(uuid, Benchmark);
7 |
--------------------------------------------------------------------------------
/examples/benchmark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-benchmark",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "true",
7 | "start": "npm run build && npx http-server . -o",
8 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
9 | "test": "node node.js"
10 | },
11 | "dependencies": {
12 | "uuid": "file:../../.build/uuid.tgz"
13 | },
14 | "devDependencies": {
15 | "benchmark": "^2.1.4"
16 | },
17 | "type": "module"
18 | }
19 |
--------------------------------------------------------------------------------
/examples/browser-esmodules/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Browser with native ECMAScript Modules
2 |
3 | ```
4 | npm install
5 | npm start
6 | ```
7 |
8 | Then navigate to `example.html`.
9 |
--------------------------------------------------------------------------------
/examples/browser-esmodules/example.html:
--------------------------------------------------------------------------------
1 |
2 | UUID esmodule native example
3 | Please open the Developer Console to view output
4 |
5 |
--------------------------------------------------------------------------------
/examples/browser-esmodules/example.js:
--------------------------------------------------------------------------------
1 | import * as uuid from './node_modules/uuid/dist/esm-browser/index.js';
2 | import {
3 | MAX as MAX_UUID,
4 | NIL as NIL_UUID,
5 | parse as uuidParse,
6 | stringify as uuidStringify,
7 | validate as uuidValidate,
8 | version as uuidVersion,
9 | v1 as uuidv1,
10 | v1ToV6 as uuidv1ToV6,
11 | v3 as uuidv3,
12 | v4 as uuidv4,
13 | v5 as uuidv5,
14 | v6 as uuidv6,
15 | v6ToV1 as uuidv6ToV1,
16 | v7 as uuidv7,
17 | } from './node_modules/uuid/dist/esm-browser/index.js';
18 |
19 | // Import attribute syntax is still awaiting finalization. In the meantime we
20 | // use dynamic import to allows to specifyg both "assert" and "with" clauses.
21 | // See https://github.com/tc39/proposal-import-attributes
22 | const pkg = await import('./node_modules/uuid/package.json', {
23 | assert: { type: 'json' },
24 | with: { type: 'json' },
25 | });
26 |
27 | console.log('pkg', pkg);
28 |
29 | console.log('uuidv1()', uuidv1());
30 |
31 | console.log('uuidv4()', uuidv4());
32 |
33 | console.log('uuidv7()', uuidv7());
34 |
35 | // ... using predefined DNS namespace (for domain names)
36 | console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
37 |
38 | // ... using predefined URL namespace (for, well, URLs)
39 | console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
40 |
41 | // ... using a custom namespace
42 | //
43 | // Note: Custom namespaces should be a UUID string specific to your application!
44 | // E.g. the one here was generated using this modules `uuid` CLI.
45 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
46 | console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
47 |
48 | // ... using predefined DNS namespace (for domain names)
49 | console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
50 |
51 | // ... using predefined URL namespace (for, well, URLs)
52 | console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
53 |
54 | // ... using a custom namespace
55 | //
56 | // Note: Custom namespaces should be a UUID string specific to your application!
57 | // E.g. the one here was generated using this modules `uuid` CLI.
58 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
59 | console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
60 |
61 | console.log('uuidv6()', uuidv6());
62 |
63 | // v6 <-> v1 conversion
64 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
65 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
66 | console.log('uuidv1ToV6()', uuidv1ToV6(V1_ID));
67 | console.log('uuidv6ToV1()', uuidv6ToV1(V6_ID));
68 |
69 | // Utility functions
70 | console.log('NIL_UUID', NIL_UUID);
71 | console.log('MAX_UUID', MAX_UUID);
72 | console.log('uuidParse()', uuidParse(MY_NAMESPACE));
73 | console.log('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
74 | console.log('uuidValidate()', uuidValidate(MY_NAMESPACE));
75 | console.log('uuidVersion()', uuidVersion(MY_NAMESPACE));
76 |
77 | console.log('Same with default export');
78 |
79 | console.log('uuid.v1()', uuid.v1());
80 | console.log('uuid.v4()', uuid.v4());
81 | console.log('uuid.v7()', uuid.v7());
82 | console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
83 | console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
84 | console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
85 | console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
86 | console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
87 | console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
88 | console.log('uuid.v6()', uuid.v6());
89 |
90 | console.log('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
91 | console.log('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
92 |
93 | console.log('uuid.NIL', uuid.NIL);
94 | console.log('uuid.MAX', uuid.MAX);
95 | console.log('uuid.parse()', uuid.parse(MY_NAMESPACE));
96 | console.log('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
97 | console.log('uuid.validate()', uuid.validate(MY_NAMESPACE));
98 | console.log('uuid.version()', uuid.version(MY_NAMESPACE));
99 |
100 | // Some tools like react-native need to introspect the package.json file
101 | console.log('pkg.name', pkg.name);
102 |
--------------------------------------------------------------------------------
/examples/browser-esmodules/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-browser-esmodules",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "true",
7 | "start": "npm run build && npx http-server . -o"
8 | },
9 | "dependencies": {
10 | "uuid": "file:../../.build/uuid.tgz"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/browser-rollup/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Browser with rollup.js
2 |
3 | ```
4 | npm install
5 | npm start
6 | ```
7 |
8 | Then navigate to `example-*.html`.
9 |
10 | The `example-v{1,4,7}.js` demonstrate that treeshaking works as expected:
11 |
12 | ```
13 | $ du -sh dist/*
14 | 20K dist/all.js
15 | 8.0K dist/v1.js
16 | 4.0K dist/v4.js
17 | 4.0K dist/v7.js
18 | ```
19 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-all.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-all.js:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 | import {
3 | MAX as MAX_UUID,
4 | NIL as NIL_UUID,
5 | parse as uuidParse,
6 | stringify as uuidStringify,
7 | validate as uuidValidate,
8 | version as uuidVersion,
9 | v1 as uuidv1,
10 | v1ToV6 as uuidv1ToV6,
11 | v3 as uuidv3,
12 | v4 as uuidv4,
13 | v5 as uuidv5,
14 | v6 as uuidv6,
15 | v6ToV1 as uuidv6ToV1,
16 | v7 as uuidv7,
17 | } from 'uuid';
18 |
19 | import testpage from '../utils/testpage';
20 |
21 | testpage(function (addTest, done) {
22 | addTest('Named exports');
23 |
24 | addTest('uuidv1()', uuidv1());
25 |
26 | addTest('uuidv4()', uuidv4());
27 |
28 | addTest('uuidv7()', uuidv7());
29 |
30 | // ... using predefined DNS namespace (for domain names)
31 | addTest('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
32 |
33 | // ... using predefined URL namespace (for, well, URLs)
34 | addTest('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
35 |
36 | // ... using a custom namespace
37 | //
38 | // Note: Custom namespaces should be a UUID string specific to your application!
39 | // E.g. the one here was generated using this modules `uuid` CLI.
40 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
41 | addTest('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
42 |
43 | // ... using predefined DNS namespace (for domain names)
44 | addTest('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
45 |
46 | // ... using predefined URL namespace (for, well, URLs)
47 | addTest('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
48 |
49 | // ... using a custom namespace
50 | //
51 | // Note: Custom namespaces should be a UUID string specific to your application!
52 | // E.g. the one here was generated using this modules `uuid` CLI.
53 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
54 | addTest('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
55 |
56 | addTest('uuidv6()', uuidv6());
57 |
58 | // v6 <-> v1 conversion
59 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
60 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
61 | addTest('uuidv1ToV6()', uuidv1ToV6(V1_ID));
62 | addTest('uuidv6ToV1()', uuidv6ToV1(V6_ID));
63 |
64 | // Utility functions
65 | addTest('NIL_UUID', NIL_UUID);
66 | addTest('MAX_UUID', MAX_UUID);
67 | addTest('uuidParse()', uuidParse(MY_NAMESPACE));
68 | addTest('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
69 | addTest('uuidValidate()', uuidValidate(MY_NAMESPACE));
70 | addTest('uuidVersion()', uuidVersion(MY_NAMESPACE));
71 |
72 | addTest('Default export');
73 |
74 | addTest('uuid.v1()', uuid.v1());
75 | addTest('uuid.v4()', uuid.v4());
76 | addTest('uuid.v7()', uuid.v7());
77 | addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
78 | addTest('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
79 | addTest('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
80 | addTest('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
81 | addTest('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
82 | addTest('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
83 | addTest('uuid.v6()', uuid.v6());
84 |
85 | addTest('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
86 | addTest('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
87 |
88 | addTest('uuid.NIL', uuid.NIL);
89 | addTest('uuid.MAX', uuid.MAX);
90 | addTest('uuid.parse()', uuid.parse(MY_NAMESPACE));
91 | addTest('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
92 | addTest('uuid.validate()', uuid.validate(MY_NAMESPACE));
93 | addTest('uuid.version()', uuid.version(MY_NAMESPACE));
94 |
95 | done();
96 | });
97 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v1.js:
--------------------------------------------------------------------------------
1 | import { v1 as uuidv1 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv1()', uuidv1());
7 | done();
8 | });
9 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v4.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv4()', uuidv4());
7 | done();
8 | });
9 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v7.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example-v7.js:
--------------------------------------------------------------------------------
1 | import { v7 as uuidv7 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv7()', uuidv7());
7 | done();
8 | });
9 |
--------------------------------------------------------------------------------
/examples/browser-rollup/example.html:
--------------------------------------------------------------------------------
1 |
2 | UUID esmodule webpack example
3 | Please open the Developer Console to view output
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/browser-rollup/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-browser-rollup",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "rm -fr node_modules && npm install --no-package-lock && rm -rf dist && rollup -c",
7 | "start": "npm run build && npx http-server . -o"
8 | },
9 | "dependencies": {
10 | "uuid": "file:../../.build/uuid.tgz"
11 | },
12 | "devDependencies": {
13 | "@rollup/plugin-node-resolve": "^15.2.3",
14 | "@rollup/plugin-terser": "0.4.4",
15 | "rollup": "^4.19.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/browser-rollup/rollup.config.js:
--------------------------------------------------------------------------------
1 | const { nodeResolve } = require('@rollup/plugin-node-resolve');
2 | const terser = require('@rollup/plugin-terser');
3 |
4 | const plugins = [nodeResolve({ browser: true }), terser()];
5 | module.exports = [
6 | {
7 | input: './example-all.js',
8 | output: {
9 | file: 'dist/all.js',
10 | format: 'iife',
11 | globals: { crypto: 'crypto' },
12 | },
13 | plugins,
14 | },
15 | {
16 | input: './example-v1.js',
17 | output: {
18 | file: 'dist/v1.js',
19 | format: 'iife',
20 | globals: { crypto: 'crypto' },
21 | },
22 | plugins,
23 | },
24 | {
25 | input: './example-v4.js',
26 | output: {
27 | file: 'dist/v4.js',
28 | format: 'iife',
29 | globals: { crypto: 'crypto' },
30 | },
31 | plugins,
32 | },
33 | {
34 | input: './example-v7.js',
35 | output: {
36 | file: 'dist/v7.js',
37 | format: 'iife',
38 | globals: { crypto: 'crypto' },
39 | },
40 | plugins,
41 | },
42 |
43 | {
44 | input: './size-v1.js',
45 | output: {
46 | file: 'dist/v1-size.js',
47 | format: 'cjs',
48 | },
49 | plugins,
50 | },
51 | {
52 | input: './size-v3.js',
53 | output: {
54 | file: 'dist/v3-size.js',
55 | format: 'cjs',
56 | },
57 | plugins,
58 | },
59 | {
60 | input: './size-v4.js',
61 | output: {
62 | file: 'dist/v4-size.js',
63 | format: 'cjs',
64 | },
65 | plugins,
66 | },
67 | {
68 | input: './size-v5.js',
69 | output: {
70 | file: 'dist/v5-size.js',
71 | format: 'cjs',
72 | },
73 | plugins,
74 | },
75 | {
76 | input: './size-v6.js',
77 | output: {
78 | file: 'dist/v6-size.js',
79 | format: 'cjs',
80 | },
81 | plugins,
82 | },
83 | {
84 | input: './size-v7.js',
85 | output: {
86 | file: 'dist/v7-size.js',
87 | format: 'cjs',
88 | },
89 | plugins,
90 | },
91 | ];
92 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v1.js:
--------------------------------------------------------------------------------
1 | import { v1 as uuidv1 } from 'uuid';
2 |
3 | uuidv1();
4 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v3.js:
--------------------------------------------------------------------------------
1 | import { v3 as uuidv3 } from 'uuid';
2 |
3 | uuidv3();
4 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v4.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 |
3 | uuidv4();
4 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v5.js:
--------------------------------------------------------------------------------
1 | import { v5 as uuidv5 } from 'uuid';
2 |
3 | uuidv5();
4 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v6.js:
--------------------------------------------------------------------------------
1 | import { v6 as uuidv6 } from 'uuid';
2 |
3 | uuidv6();
4 |
--------------------------------------------------------------------------------
/examples/browser-rollup/size-v7.js:
--------------------------------------------------------------------------------
1 | import { v7 as uuidv7 } from 'uuid';
2 |
3 | uuidv7();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Browser with Webpack
2 |
3 | ```
4 | npm install
5 | npm start
6 | ```
7 |
8 | Then navigate to `example-*.html`.
9 |
10 | The `example-v{1,4}.js` demonstrate that treeshaking works as expected (webpack output below):
11 |
12 | ```
13 | Asset Size Chunks Chunk Names
14 | all.js 8.54 KiB 0 [emitted] all
15 | v1.js 2.6 KiB 1 [emitted] v1
16 | v4.js 2 KiB 2 [emitted] v4
17 | ```
18 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-all-require.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-all-require.js:
--------------------------------------------------------------------------------
1 | const uuid = require('uuid');
2 | const {
3 | NIL: NIL_UUID,
4 | MAX: MAX_UUID,
5 | parse: uuidParse,
6 | stringify: uuidStringify,
7 | v1: uuidv1,
8 | v1ToV6: uuidv1ToV6,
9 | v3: uuidv3,
10 | v4: uuidv4,
11 | v5: uuidv5,
12 | v6: uuidv6,
13 | v6ToV1: uuidv6ToV1,
14 | v7: uuidv7,
15 | validate: uuidValidate,
16 | version: uuidVersion,
17 | } = uuid;
18 |
19 | const { default: testpage } = require('../utils/testpage');
20 |
21 | testpage(function (addTest, done) {
22 | addTest('Named exports');
23 |
24 | addTest('uuidv1()', uuidv1());
25 |
26 | addTest('uuidv4()', uuidv4());
27 |
28 | addTest('uuidv7()', uuidv7());
29 |
30 | // ... using predefined DNS namespace (for domain names)
31 | addTest('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
32 |
33 | // ... using predefined URL namespace (for, well, URLs)
34 | addTest('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
35 |
36 | // ... using a custom namespace
37 | //
38 | // Note: Custom namespaces should be a UUID string specific to your application!
39 | // E.g. the one here was generated using this modules `uuid` CLI.
40 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
41 | addTest('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
42 |
43 | // ... using predefined DNS namespace (for domain names)
44 | addTest('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
45 |
46 | // ... using predefined URL namespace (for, well, URLs)
47 | addTest('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
48 |
49 | // v6 <-> v1 conversion
50 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
51 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
52 | addTest('uuidv1ToV6()', uuidv1ToV6(V1_ID));
53 | addTest('uuidv6ToV1()', uuidv6ToV1(V6_ID));
54 |
55 | // ... using a custom namespace
56 | //
57 | // Note: Custom namespaces should be a UUID string specific to your application!
58 | // E.g. the one here was generated using this modules `uuid` CLI.
59 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
60 | addTest('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
61 |
62 | addTest('uuidv6()', uuidv6());
63 |
64 | // Utility functions
65 | addTest('NIL_UUID', NIL_UUID);
66 | addTest('MAX_UUID', MAX_UUID);
67 | addTest('uuidParse()', uuidParse(MY_NAMESPACE));
68 | addTest('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
69 | addTest('uuidValidate()', uuidValidate(MY_NAMESPACE));
70 | addTest('uuidVersion()', uuidVersion(MY_NAMESPACE));
71 |
72 | addTest('Default export');
73 |
74 | addTest('uuid.v1()', uuid.v1());
75 | addTest('uuid.v4()', uuid.v4());
76 | addTest('uuid.v7()', uuid.v7());
77 | addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
78 | addTest('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
79 | addTest('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
80 | addTest('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
81 | addTest('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
82 | addTest('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
83 | addTest('uuid.v6()', uuid.v6());
84 |
85 | addTest('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
86 | addTest('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
87 |
88 | addTest('uuid.NIL', uuid.NIL);
89 | addTest('uuid.MAX', uuid.MAX);
90 | addTest('uuid.parse()', uuid.parse(MY_NAMESPACE));
91 | addTest('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
92 | addTest('uuid.validate()', uuid.validate(MY_NAMESPACE));
93 | addTest('uuid.version()', uuid.version(MY_NAMESPACE));
94 |
95 | done();
96 | });
97 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-all.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-all.js:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 | import {
3 | MAX as MAX_UUID,
4 | NIL as NIL_UUID,
5 | parse as uuidParse,
6 | stringify as uuidStringify,
7 | validate as uuidValidate,
8 | version as uuidVersion,
9 | v1 as uuidv1,
10 | v1ToV6 as uuidv1ToV6,
11 | v3 as uuidv3,
12 | v4 as uuidv4,
13 | v5 as uuidv5,
14 | v6 as uuidv6,
15 | v6ToV1 as uuidv6ToV1,
16 | v7 as uuidv7,
17 | } from 'uuid';
18 |
19 | import testpage from '../utils/testpage';
20 |
21 | testpage(function (addTest, done) {
22 | addTest('Named exports');
23 |
24 | addTest('uuidv1()', uuidv1());
25 |
26 | addTest('uuidv4()', uuidv4());
27 |
28 | addTest('uuidv7()', uuidv7());
29 |
30 | // ... using predefined DNS namespace (for domain names)
31 | addTest('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
32 |
33 | // ... using predefined URL namespace (for, well, URLs)
34 | addTest('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
35 |
36 | // ... using a custom namespace
37 | //
38 | // Note: Custom namespaces should be a UUID string specific to your application!
39 | // E.g. the one here was generated using this modules `uuid` CLI.
40 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
41 | addTest('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
42 |
43 | // ... using predefined DNS namespace (for domain names)
44 | addTest('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
45 |
46 | // ... using predefined URL namespace (for, well, URLs)
47 | addTest('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
48 |
49 | // ... using a custom namespace
50 | //
51 | // Note: Custom namespaces should be a UUID string specific to your application!
52 | // E.g. the one here was generated using this modules `uuid` CLI.
53 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
54 | addTest('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
55 |
56 | addTest('uuidv6()', uuidv6());
57 |
58 | // v6 <-> v1 conversion
59 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
60 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
61 | addTest('uuidv1ToV6()', uuidv1ToV6(V1_ID));
62 | addTest('uuidv6ToV1()', uuidv6ToV1(V6_ID));
63 |
64 | // Utility functions
65 | addTest('NIL_UUID', NIL_UUID);
66 | addTest('MAX_UUID', MAX_UUID);
67 | addTest('uuidParse()', uuidParse(MY_NAMESPACE));
68 | addTest('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
69 | addTest('uuidValidate()', uuidValidate(MY_NAMESPACE));
70 | addTest('uuidVersion()', uuidVersion(MY_NAMESPACE));
71 |
72 | addTest('Default export');
73 |
74 | addTest('uuid.v1()', uuid.v1());
75 | addTest('uuid.v4()', uuid.v4());
76 | addTest('uuid.v7()', uuid.v7());
77 | addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
78 | addTest('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
79 | addTest('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
80 | addTest('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
81 | addTest('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
82 | addTest('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
83 | addTest('uuid.v6()', uuid.v6());
84 |
85 | addTest('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
86 | addTest('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
87 |
88 | addTest('uuid.NIL', uuid.NIL);
89 | addTest('uuid.MAX', uuid.MAX);
90 | addTest('uuid.parse()', uuid.parse(MY_NAMESPACE));
91 | addTest('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
92 | addTest('uuid.validate()', uuid.validate(MY_NAMESPACE));
93 | addTest('uuid.version()', uuid.version(MY_NAMESPACE));
94 |
95 | done();
96 | });
97 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v1.js:
--------------------------------------------------------------------------------
1 | import { v1 as uuidv1 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv1()', uuidv1());
7 |
8 | done();
9 | });
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v4.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv4()', uuidv4());
7 |
8 | done();
9 | });
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v7.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UUID esmodule webpack example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example-v7.js:
--------------------------------------------------------------------------------
1 | import { v7 as uuidv7 } from 'uuid';
2 |
3 | import testpage from '../utils/testpage';
4 |
5 | testpage(function (addTest, done) {
6 | addTest('uuidv7()', uuidv7());
7 |
8 | done();
9 | });
10 |
--------------------------------------------------------------------------------
/examples/browser-webpack/example.html:
--------------------------------------------------------------------------------
1 |
2 | UUID esmodule webpack example
3 | Please open the Developer Console to view output
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/browser-webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-browser-webpack",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "rm -fr node_modules && npm install --no-package-lock && rm -rf dist && webpack",
7 | "start": "npm run build && npx http-server . -o"
8 | },
9 | "dependencies": {
10 | "uuid": "file:../../.build/uuid.tgz"
11 | },
12 | "devDependencies": {
13 | "webpack": "5.93.0",
14 | "webpack-cli": "5.1.4"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v1.js:
--------------------------------------------------------------------------------
1 | import { v1 as uuidv1 } from 'uuid';
2 |
3 | uuidv1();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v3.js:
--------------------------------------------------------------------------------
1 | import { v3 as uuidv3 } from 'uuid';
2 |
3 | uuidv3();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v4.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 |
3 | uuidv4();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v5.js:
--------------------------------------------------------------------------------
1 | import { v5 as uuidv5 } from 'uuid';
2 |
3 | uuidv5();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v6.js:
--------------------------------------------------------------------------------
1 | import { v6 as uuidv6 } from 'uuid';
2 |
3 | uuidv6();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/size-v7.js:
--------------------------------------------------------------------------------
1 | import { v7 as uuidv7 } from 'uuid';
2 |
3 | uuidv7();
4 |
--------------------------------------------------------------------------------
/examples/browser-webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | resolve: {
3 | extensions: ['*', '.js'],
4 | fallback: { crypto: false },
5 | },
6 | entry: {
7 | all: './example-all.js',
8 | allRequire: './example-all-require.js',
9 | v1: './example-v1.js',
10 | v4: './example-v4.js',
11 | v7: './example-v7.js',
12 |
13 | 'v1-size': './size-v1.js',
14 | 'v3-size': './size-v3.js',
15 | 'v4-size': './size-v4.js',
16 | 'v5-size': './size-v5.js',
17 | 'v6-size': './size-v6.js',
18 | 'v7-size': './size-v7.js',
19 | },
20 | // Webpack now produces builds that are incompatible with IE11:
21 | // https://webpack.js.org/migrate/5/#turn-off-es2015-syntax-in-runtime-code-if-necessary
22 | target: ['web', 'es5'],
23 | output: {
24 | filename: '[name].js',
25 | },
26 | mode: 'production',
27 | };
28 |
--------------------------------------------------------------------------------
/examples/node-commonjs/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Node.js CommonJS
2 |
3 | ```
4 | npm install
5 | npm test
6 | ```
7 |
--------------------------------------------------------------------------------
/examples/node-commonjs/example.js:
--------------------------------------------------------------------------------
1 | const {
2 | NIL: NIL_UUID,
3 | MAX: MAX_UUID,
4 | parse: uuidParse,
5 | stringify: uuidStringify,
6 | v1: uuidv1,
7 | v1ToV6: uuidv1ToV6,
8 | v3: uuidv3,
9 | v4: uuidv4,
10 | v5: uuidv5,
11 | v6: uuidv6,
12 | v6ToV1: uuidv6ToV1,
13 | v7: uuidv7,
14 | validate: uuidValidate,
15 | version: uuidVersion,
16 | } = require('uuid');
17 | const uuid = require('uuid');
18 | const pkg = require('uuid/package.json');
19 |
20 | console.log('uuidv1()', uuidv1());
21 |
22 | console.log('uuidv4()', uuidv4());
23 |
24 | console.log('uuidv7()', uuidv7());
25 |
26 | // ... using predefined DNS namespace (for domain names)
27 | console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
28 |
29 | // ... using predefined URL namespace (for, well, URLs)
30 | console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
31 |
32 | // ... using a custom namespace
33 | //
34 | // Note: Custom namespaces should be a UUID string specific to your application!
35 | // E.g. the one here was generated using this modules `uuid` CLI.
36 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
37 | console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
38 |
39 | // ... using predefined DNS namespace (for domain names)
40 | console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
41 |
42 | // ... using predefined URL namespace (for, well, URLs)
43 | console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
44 |
45 | // ... using a custom namespace
46 | //
47 | // Note: Custom namespaces should be a UUID string specific to your application!
48 | // E.g. the one here was generated using this modules `uuid` CLI.
49 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
50 | console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
51 |
52 | console.log('uuidv6()', uuidv6());
53 |
54 | // v6 <-> v1 conversion
55 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
56 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
57 | console.log('uuidv1ToV6()', uuidv1ToV6(V1_ID));
58 | console.log('uuidv6ToV1()', uuidv6ToV1(V6_ID));
59 |
60 | // Utility functions
61 | console.log('NIL_UUID', NIL_UUID);
62 | console.log('MAX_UUID', MAX_UUID);
63 | console.log('uuidParse()', uuidParse(MY_NAMESPACE));
64 | console.log('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
65 | console.log('uuidValidate()', uuidValidate(MY_NAMESPACE));
66 | console.log('uuidVersion()', uuidVersion(MY_NAMESPACE));
67 |
68 | console.log('Same with default export');
69 |
70 | console.log('uuid.v1()', uuid.v1());
71 | console.log('uuid.v4()', uuid.v4());
72 | console.log('uuid.v7()', uuid.v7());
73 | console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
74 | console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
75 | console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
76 | console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
77 | console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
78 | console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
79 | console.log('uuid.v6()', uuid.v6());
80 |
81 | console.log('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
82 | console.log('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
83 |
84 | console.log('uuid.NIL', uuid.NIL);
85 | console.log('uuid.MAX', uuid.MAX);
86 | console.log('uuid.parse()', uuid.parse(MY_NAMESPACE));
87 | console.log('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
88 | console.log('uuid.validate()', uuid.validate(MY_NAMESPACE));
89 | console.log('uuid.version()', uuid.version(MY_NAMESPACE));
90 |
91 | // Some tools like react-native need to introspect the package.json file
92 | console.log('pkg.name', pkg.name);
93 |
--------------------------------------------------------------------------------
/examples/node-commonjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-node-commonjs",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
7 | "test": "node example.js"
8 | },
9 | "dependencies": {
10 | "uuid": "file:../../.build/uuid.tgz"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/node-esmodules/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Node.js ESModules
2 |
3 | ```
4 | npm install
5 | npm test
6 | ```
7 |
--------------------------------------------------------------------------------
/examples/node-esmodules/example.mjs:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 | import {
3 | MAX as MAX_UUID,
4 | NIL as NIL_UUID,
5 | parse as uuidParse,
6 | stringify as uuidStringify,
7 | validate as uuidValidate,
8 | version as uuidVersion,
9 | v1 as uuidv1,
10 | v1ToV6 as uuidv1ToV6,
11 | v3 as uuidv3,
12 | v4 as uuidv4,
13 | v5 as uuidv5,
14 | v6 as uuidv6,
15 | v6ToV1 as uuidv6ToV1,
16 | v7 as uuidv7,
17 | } from 'uuid';
18 |
19 | // Import attribute syntax is still awaiting finalization. In the meantime we
20 | // use dynamic import to allows to specifyg both "assert" and "with" clauses.
21 | // See https://github.com/tc39/proposal-import-attributes
22 | const pkg = await import('uuid/package.json', { assert: { type: 'json' }, with: { type: 'json' } });
23 |
24 | console.log('uuidv1()', uuidv1());
25 |
26 | console.log('uuidv4()', uuidv4());
27 |
28 | console.log('uuidv7()', uuidv7());
29 |
30 | // ... using predefined DNS namespace (for domain names)
31 | console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
32 |
33 | // ... using predefined URL namespace (for, well, URLs)
34 | console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
35 |
36 | // ... using a custom namespace
37 | //
38 | // Note: Custom namespaces should be a UUID string specific to your application!
39 | // E.g. the one here was generated using this modules `uuid` CLI.
40 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
41 | console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
42 |
43 | // ... using predefined DNS namespace (for domain names)
44 | console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
45 |
46 | // ... using predefined URL namespace (for, well, URLs)
47 | console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
48 |
49 | // ... using a custom namespace
50 | //
51 | // Note: Custom namespaces should be a UUID string specific to your application!
52 | // E.g. the one here was generated using this modules `uuid` CLI.
53 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
54 | console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
55 |
56 | console.log('uuidv6()', uuidv6());
57 |
58 | // v6 <-> v1 conversion
59 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
60 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
61 | console.log('uuidv1ToV6()', uuidv1ToV6(V1_ID));
62 | console.log('uuidv6ToV1()', uuidv6ToV1(V6_ID));
63 |
64 | // Utility functions
65 | console.log('NIL_UUID', NIL_UUID);
66 | console.log('MAX_UUID', MAX_UUID);
67 | console.log('uuidParse()', uuidParse(MY_NAMESPACE));
68 | console.log('uuidStringify()', uuidStringify(uuidParse(MY_NAMESPACE)));
69 | console.log('uuidValidate()', uuidValidate(MY_NAMESPACE));
70 | console.log('uuidVersion()', uuidVersion(MY_NAMESPACE));
71 |
72 | console.log('Same with default export');
73 |
74 | console.log('uuid.v1()', uuid.v1());
75 | console.log('uuid.v4()', uuid.v4());
76 | console.log('uuid.v7()', uuid.v7());
77 | console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
78 | console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
79 | console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
80 | console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
81 | console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
82 | console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
83 | console.log('uuid.v6()', uuid.v6());
84 |
85 | console.log('uuid.v1ToV6()', uuid.v1ToV6(V1_ID));
86 | console.log('uuid.v6ToV1()', uuid.v6ToV1(V6_ID));
87 |
88 | console.log('uuid.NIL', uuid.NIL);
89 | console.log('uuid.MAX', uuid.MAX);
90 | console.log('uuid.parse()', uuid.parse(MY_NAMESPACE));
91 | console.log('uuid.stringify()', uuid.stringify(uuid.parse(MY_NAMESPACE)));
92 | console.log('uuid.validate()', uuid.validate(MY_NAMESPACE));
93 | console.log('uuid.version()', uuid.version(MY_NAMESPACE));
94 |
95 | // Some tools like react-native need to introspect the package.json file
96 | console.log('pkg.name', pkg.default.name);
97 |
--------------------------------------------------------------------------------
/examples/node-esmodules/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-node-esmodules",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "test:package": "( node --version | grep -vq 'v16' ) || ( node --experimental-json-modules package.mjs )",
7 | "test:example": "node example.mjs",
8 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
9 | "test": "npm-run-all test:*"
10 | },
11 | "dependencies": {
12 | "uuid": "file:../../.build/uuid.tgz"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/node-esmodules/package.mjs:
--------------------------------------------------------------------------------
1 | import pkg from 'uuid/package.json' assert { type: 'json' };
2 |
3 | // Some tools like react-native need to introspect the package.json file
4 | console.log('pkg.name', pkg.name);
5 |
--------------------------------------------------------------------------------
/examples/node-jest/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Node.js Jest
2 |
3 | ```
4 | npm install
5 | npm test
6 | ```
7 |
--------------------------------------------------------------------------------
/examples/node-jest/jsdom.test.js:
--------------------------------------------------------------------------------
1 | /** @jest-environment jsdom */
2 |
3 | const uuid = require('uuid');
4 |
5 | test('uuidv4()', () => {
6 | const val = uuid.v4();
7 | expect(uuid.version(val)).toBe(4);
8 | });
9 |
10 | test('uuidv7()', () => {
11 | const val = uuid.v7();
12 | expect(uuid.version(val)).toBe(7);
13 | });
14 |
--------------------------------------------------------------------------------
/examples/node-jest/node.test.js:
--------------------------------------------------------------------------------
1 | const uuid = require('uuid');
2 |
3 | test('uuidv4()', () => {
4 | const val = uuid.v4();
5 | expect(uuid.version(val)).toBe(4);
6 | });
7 |
8 | test('uuidv7()', () => {
9 | const val = uuid.v7();
10 | expect(uuid.version(val)).toBe(7);
11 | });
12 |
--------------------------------------------------------------------------------
/examples/node-jest/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-node-jest",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "uuid": "file:../../.build/uuid.tgz"
11 | },
12 | "devDependencies": {
13 | "jest": "^29.7.0",
14 | "jest-environment-jsdom": "^29.7.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/node-webpack/README.md:
--------------------------------------------------------------------------------
1 | # uuid example Node.js with Webpack
2 |
3 | ```
4 | npm install
5 | npm test
6 | ```
7 |
8 | This will run webpack and execute the resulting bundles in `./dist`.
9 |
--------------------------------------------------------------------------------
/examples/node-webpack/example-all.js:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 | import { v1 as uuidv1, v3 as uuidv3, v4 as uuidv4, v5 as uuidv5 } from 'uuid';
3 |
4 | console.log('uuidv1()', uuidv1());
5 | console.log('uuidv4()', uuidv4());
6 |
7 | // ... using predefined DNS namespace (for domain names)
8 | console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
9 |
10 | // ... using predefined URL namespace (for, well, URLs)
11 | console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
12 |
13 | // ... using a custom namespace
14 | //
15 | // Note: Custom namespaces should be a UUID string specific to your application!
16 | // E.g. the one here was generated using this modules `uuid` CLI.
17 | const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
18 | console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
19 |
20 | // ... using predefined DNS namespace (for domain names)
21 | console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
22 |
23 | // ... using predefined URL namespace (for, well, URLs)
24 | console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
25 |
26 | // ... using a custom namespace
27 | //
28 | // Note: Custom namespaces should be a UUID string specific to your application!
29 | // E.g. the one here was generated using this modules `uuid` CLI.
30 | // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
31 | console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
32 |
33 | console.log('Same with default export');
34 |
35 | console.log('uuid.v1()', uuid.v1());
36 | console.log('uuid.v4()', uuid.v4());
37 | console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
38 | console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
39 | console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
40 | console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
41 | console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
42 | console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
43 |
--------------------------------------------------------------------------------
/examples/node-webpack/example-v1.js:
--------------------------------------------------------------------------------
1 | import { v1 as uuidv1 } from 'uuid';
2 |
3 | console.log('uuidv1()', uuidv1());
4 |
--------------------------------------------------------------------------------
/examples/node-webpack/example-v4.js:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid';
2 |
3 | console.log('uuidv4()', uuidv4());
4 |
--------------------------------------------------------------------------------
/examples/node-webpack/example-v7.js:
--------------------------------------------------------------------------------
1 | import { v7 as uuidv7 } from 'uuid';
2 |
3 | console.log('uuidv7()', uuidv7());
4 |
--------------------------------------------------------------------------------
/examples/node-webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid-example-node-webpack",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "rm -rf dist && webpack",
7 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
8 | "test": "npm run build && node dist/v1.js && node dist/v4.js && node dist/v7.js && node dist/all.js"
9 | },
10 | "dependencies": {
11 | "uuid": "file:../../.build/uuid.tgz"
12 | },
13 | "devDependencies": {
14 | "webpack": "^5.74.0",
15 | "webpack-cli": "^4.10.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/node-webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | resolve: {
3 | extensions: ['*', '.js'],
4 | },
5 | entry: {
6 | all: './example-all.js',
7 | v1: './example-v1.js',
8 | v4: './example-v4.js',
9 | v7: './example-v7.js',
10 | },
11 | output: {
12 | filename: '[name].js',
13 | },
14 | mode: 'production',
15 | target: 'node',
16 | };
17 |
--------------------------------------------------------------------------------
/examples/typescript/README.md:
--------------------------------------------------------------------------------
1 | # uuid test for typescript support (not really an example)
2 |
3 | ```
4 | npm install
5 | npm test
6 | ```
7 |
8 | This runs `tsc` using the oldest version of TypeScript supported by this project
--------------------------------------------------------------------------------
/examples/typescript/buffer.test.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/ban-ts-comment */
2 | import { v1 } from 'uuid';
3 |
4 | v1(undefined, new Uint8Array(16)) satisfies Uint8Array;
5 | v1(undefined, Buffer.alloc(16)) satisfies Buffer;
6 |
7 | // @ts-expect-error
8 | v1(undefined, new Uint8Array(16)) satisfies Buffer;
9 |
--------------------------------------------------------------------------------
/examples/typescript/index.ts:
--------------------------------------------------------------------------------
1 | import * as uuid from 'uuid';
2 |
3 | console.log(uuid);
4 |
--------------------------------------------------------------------------------
/examples/typescript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "uuid": "file:../../.build/uuid.tgz"
4 | },
5 | "scripts": {
6 | "pretest": "rm -fr node_modules && npm install --no-package-lock",
7 | "test": "npx -y --package=typescript@5.0.4 -- tsc --noEmit"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/examples/utils/testpage.js:
--------------------------------------------------------------------------------
1 | export default function test(callback) {
2 | const style = document.createElement('style');
3 | style.appendChild(
4 | document.createTextNode(
5 | [
6 | 'body {font-family: monospace;}',
7 | 'dt, dd {display: inline-block; margin: 0;}',
8 | 'dt {min-width: 15em;}',
9 | ].join('\n')
10 | )
11 | );
12 | document.body.appendChild(style);
13 |
14 | function addTest(title, result) {
15 | // join() result if it's array-like
16 | if (result instanceof Uint8Array || Array.isArray(result)) {
17 | result = Array.prototype.join.apply(result);
18 | }
19 |
20 | let el;
21 | if (result === undefined) {
22 | el = document.createElement('h2');
23 | el.innerHTML = title;
24 | } else {
25 | el = document.createElement('div');
26 | el.className = 'test_result';
27 | el.innerHTML = '' + title + ': ' + result + '';
28 | }
29 |
30 | document.body.appendChild(el);
31 | }
32 |
33 | function done() {
34 | const div = document.createElement('h2');
35 | div.id = 'done';
36 | document.body.appendChild(div);
37 | }
38 |
39 | window.onload = function () {
40 | callback(addTest, done);
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uuid",
3 | "version": "11.1.0",
4 | "description": "RFC9562 UUIDs",
5 | "type": "module",
6 | "funding": [
7 | "https://github.com/sponsors/broofa",
8 | "https://github.com/sponsors/ctavan"
9 | ],
10 | "commitlint": {
11 | "extends": [
12 | "@commitlint/config-conventional"
13 | ]
14 | },
15 | "keywords": [
16 | "uuid",
17 | "guid",
18 | "rfc4122",
19 | "rfc9562"
20 | ],
21 | "license": "MIT",
22 | "bin": {
23 | "uuid": "./dist/esm/bin/uuid"
24 | },
25 | "sideEffects": false,
26 | "main": "./dist/cjs/index.js",
27 | "exports": {
28 | ".": {
29 | "node": {
30 | "import": "./dist/esm/index.js",
31 | "require": "./dist/cjs/index.js"
32 | },
33 | "browser": {
34 | "import": "./dist/esm-browser/index.js",
35 | "require": "./dist/cjs-browser/index.js"
36 | },
37 | "default": "./dist/esm-browser/index.js"
38 | },
39 | "./package.json": "./package.json"
40 | },
41 | "module": "./dist/esm/index.js",
42 | "browser": {
43 | "./dist/esm/index.js": "./dist/esm-browser/index.js",
44 | "./dist/cjs/index.js": "./dist/cjs-browser/index.js"
45 | },
46 | "files": [
47 | "dist",
48 | "!dist/**/test"
49 | ],
50 | "devDependencies": {
51 | "@babel/eslint-parser": "7.27.1",
52 | "@commitlint/cli": "19.8.0",
53 | "@commitlint/config-conventional": "19.8.0",
54 | "@eslint/js": "9.26.0",
55 | "bundlewatch": "0.4.1",
56 | "commander": "13.1.0",
57 | "eslint": "9.26.0",
58 | "eslint-config-prettier": "10.1.2",
59 | "eslint-plugin-prettier": "5.4.0",
60 | "globals": "16.0.0",
61 | "husky": "9.1.7",
62 | "jest": "29.7.0",
63 | "lint-staged": "15.5.2",
64 | "neostandard": "0.12.1",
65 | "npm-run-all": "4.1.5",
66 | "prettier": "3.5.3",
67 | "release-please": "17.0.0",
68 | "runmd": "1.4.1",
69 | "standard-version": "9.5.0",
70 | "typescript": "5.0.4",
71 | "typescript-eslint": "8.32.0"
72 | },
73 | "optionalDevDependencies": {
74 | "@wdio/browserstack-service": "9.2.1",
75 | "@wdio/cli": "9.2.1",
76 | "@wdio/jasmine-framework": "9.2.1",
77 | "@wdio/local-runner": "9.2.1",
78 | "@wdio/spec-reporter": "9.1.3",
79 | "@wdio/static-server-service": "9.1.3"
80 | },
81 | "scripts": {
82 | "build": "./scripts/build.sh",
83 | "build:watch": "tsc --watch -p tsconfig.esm.json",
84 | "bundlewatch": "npm run pretest:browser && bundlewatch --config bundlewatch.config.json",
85 | "docs:diff": "npm run docs && git diff --quiet README.md",
86 | "docs": "npm run build && npx runmd --output=README.md README_js.md",
87 | "eslint:check": "eslint src/ test/ examples/ *.[jt]s",
88 | "eslint:fix": "eslint --fix src/ test/ examples/ *.[jt]s",
89 | "examples:browser:rollup:build": "cd examples/browser-rollup && npm run build",
90 | "examples:browser:webpack:build": "cd examples/browser-webpack && npm run build",
91 | "examples:node:commonjs:test": "cd examples/node-commonjs && npm test",
92 | "examples:node:esmodules:test": "cd examples/node-esmodules && npm test",
93 | "examples:node:jest:test": "cd examples/node-jest && npm test",
94 | "examples:node:typescript:test": "cd examples/typescript && npm test",
95 | "lint": "npm run eslint:check && npm run prettier:check",
96 | "md": "runmd --watch --output=README.md README_js.md",
97 | "prepack": "npm run build -- --no-pack",
98 | "prepare": "husky",
99 | "prepublishOnly": "npm run build",
100 | "pretest:benchmark": "npm run build",
101 | "pretest:browser": "./scripts/iodd && npm run build && npm-run-all --parallel examples:browser:**",
102 | "pretest:node": "npm run build",
103 | "pretest": "npm run build",
104 | "prettier:check": "prettier --check .",
105 | "prettier:fix": "prettier --write .",
106 | "release": "standard-version --no-verify",
107 | "test:benchmark": "cd examples/benchmark && npm test",
108 | "test:browser": "wdio run ./wdio.conf.js",
109 | "test:node": "npm-run-all --parallel examples:node:**",
110 | "test:watch": "node --test --enable-source-maps --watch dist/esm/test/*.js",
111 | "test": "node --test --enable-source-maps dist/esm/test/*.js"
112 | },
113 | "repository": {
114 | "type": "git",
115 | "url": "https://github.com/uuidjs/uuid.git"
116 | },
117 | "lint-staged": {
118 | "*": [
119 | "prettier --no-error-on-unmatched-pattern --write"
120 | ],
121 | "*.{js,jsx}": [
122 | "eslint --no-error-on-unmatched-pattern --fix"
123 | ]
124 | },
125 | "standard-version": {
126 | "scripts": {
127 | "postchangelog": "prettier --write CHANGELOG.md"
128 | }
129 | },
130 | "packageManager": "npm@11.3.0"
131 | }
132 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | arrowParens: 'always',
3 | printWidth: 100,
4 | proseWrap: 'never',
5 | singleQuote: true,
6 | trailingComma: 'es5',
7 | };
8 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eu
2 |
3 | # This script generates 4 builds, as follows:
4 | # - dist/esm: ESM build for Node.js
5 | # - dist/esm-browser: ESM build for the Browser
6 | # - dist/cjs: CommonJS build for Node.js
7 | # - dist/cjs-browser: CommonJS build for the Browser
8 | #
9 | # Note: that the "preferred" build for testing (local and CI) is the ESM build,
10 | # except where we specifically test the other builds
11 |
12 | set -e # exit on error
13 |
14 | # Change to project root
15 | ROOT="$(pwd)/$(dirname "$0")/.."
16 | cd "$ROOT" || exit 1
17 |
18 | # Prep TS output dir
19 | DIST_DIR="$ROOT/dist"
20 | rm -rf "$DIST_DIR"
21 | mkdir -p "$DIST_DIR"
22 |
23 | # Build each module type
24 | for MODULE_TYPE in esm cjs; do
25 | echo "Building ${MODULE_TYPE}"
26 |
27 | NODE_DIST_DIR="$DIST_DIR/${MODULE_TYPE}"
28 | BROWSER_DIST_DIR="$DIST_DIR/${MODULE_TYPE}-browser"
29 |
30 | tsc -p tsconfig.${MODULE_TYPE}.json
31 |
32 | # Clone files for browser builds
33 | cp -pr ${NODE_DIST_DIR} ${BROWSER_DIST_DIR}
34 |
35 | # Remove browser files from non-browser builds
36 | for FILE in ${NODE_DIST_DIR}/*-browser*;do
37 | rm -f $FILE
38 | done
39 |
40 | # Move browser files into place for browser builds
41 | (
42 | # Temporarily cd into BROWSER_DIST_DIR to avoid having to deal with
43 | # "-browser" appearing in both the dir name and file name of FILE's full
44 | # path
45 | cd ${BROWSER_DIST_DIR}
46 |
47 | for FILE in *-browser*;do
48 | mv $FILE ${FILE/-browser/}
49 | done
50 | )
51 |
52 | # esm/cjs-specific logic
53 | if [ "$MODULE_TYPE" = "esm" ]; then
54 | # ESM: copy bin files to dist
55 | cp -pr "$DIST_DIR/../src/bin" "$NODE_DIST_DIR"
56 | else
57 | # CJS: Add package.json that specifies type: commonjs
58 | echo "{\"type\":\"commonjs\"}" > "$NODE_DIST_DIR/package.json"
59 | echo "{\"type\":\"commonjs\"}" > "$BROWSER_DIST_DIR/package.json"
60 | fi
61 | done
62 |
63 | if [ "${1-}" != "--no-pack" ]; then
64 | # Prep tarball dir
65 | BUILD_DIR="$ROOT/.build"
66 | rm -rf "$BUILD_DIR"
67 | mkdir -p "$BUILD_DIR"
68 |
69 | # Create tarball for local installation (in tests and examples)
70 | echo "Packing tarball"
71 | npm pack --pack-destination "$BUILD_DIR" > /dev/null 2>&1
72 | mv $BUILD_DIR/uuid-*.tgz $BUILD_DIR/uuid.tgz
73 | fi
74 |
75 | echo "-- fin --"
--------------------------------------------------------------------------------
/scripts/iodd:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { program } from 'commander';
4 | import { spawn } from 'node:child_process';
5 | import fs from 'node:fs/promises';
6 | import path from 'node:path';
7 |
8 | program
9 | .name('iodd')
10 | .description(
11 | '(I)nstall (o)ptional (d)ev (d)ependencies from package.json#optionalDevDependencies'
12 | )
13 | .option('-v, --verbose', 'Output npm install output to stdout/stderr')
14 | .option('-r, --required', 'Exit with non-zero code if dependencies fail to install')
15 | .argument('[packagePath]', 'Path to package.json file', './package.json')
16 | .action(main);
17 |
18 | async function main(packagePath, options) {
19 | // Get list of optional dependencies from package.json
20 | const json = await fs.readFile(path.join(process.cwd(), packagePath));
21 | const packageJson = JSON.parse(json);
22 | const { optionalDevDependencies: deps } = packageJson;
23 |
24 | if (!deps) {
25 | console.error(`No optional dependencies found in ${packagePath}`);
26 | process.exit(1);
27 | }
28 |
29 | const packageRefs = Object.entries(deps).map(([name, version]) => `${name}@${version}`);
30 |
31 | // Install optional dependencies with child_process running npm
32 | const args = ['install', '--no-save', ...packageRefs];
33 | console.log('Running: ', 'npm', args.join(' '));
34 |
35 | const cp = spawn('npm', args);
36 |
37 | if (options.verbose) {
38 | cp.stdout.pipe(process.stdout);
39 | cp.stderr.pipe(process.stderr);
40 | }
41 |
42 | const exitCode = await new Promise((resolve) => {
43 | cp.on('close', resolve);
44 | });
45 |
46 | if (exitCode !== 0) {
47 | console.error('Dependencies failed to install');
48 |
49 | if (options.required) {
50 | process.exit(exitCode);
51 | }
52 | }
53 | }
54 |
55 | program.parseAsync();
56 |
--------------------------------------------------------------------------------
/src/bin/uuid:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | import '../uuid-bin.js';
3 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export type * from './types.js';
2 | export { default as MAX } from './max.js';
3 | export { default as NIL } from './nil.js';
4 | export { default as parse } from './parse.js';
5 | export { default as stringify } from './stringify.js';
6 | export { default as v1 } from './v1.js';
7 | export { default as v1ToV6 } from './v1ToV6.js';
8 | export { default as v3 } from './v3.js';
9 | export { default as v4 } from './v4.js';
10 | export { default as v5 } from './v5.js';
11 | export { default as v6 } from './v6.js';
12 | export { default as v6ToV1 } from './v6ToV1.js';
13 | export { default as v7 } from './v7.js';
14 | export { default as validate } from './validate.js';
15 | export { default as version } from './version.js';
16 |
--------------------------------------------------------------------------------
/src/max.ts:
--------------------------------------------------------------------------------
1 | export default 'ffffffff-ffff-ffff-ffff-ffffffffffff';
2 |
--------------------------------------------------------------------------------
/src/md5-browser.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Browser-compatible JavaScript MD5
3 | *
4 | * Modification of JavaScript MD5
5 | * https://github.com/blueimp/JavaScript-MD5
6 | *
7 | * Copyright 2011, Sebastian Tschan
8 | * https://blueimp.net
9 | *
10 | * Licensed under the MIT license:
11 | * https://opensource.org/licenses/MIT
12 | *
13 | * Based on
14 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
15 | * Digest Algorithm, as defined in RFC 1321.
16 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
17 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
18 | * Distributed under the BSD License
19 | * See http://pajhome.org.uk/crypt/md5 for more info.
20 | */
21 | function md5(bytes: Uint8Array) {
22 | const words = uint8ToUint32(bytes);
23 |
24 | const md5Bytes = wordsToMd5(words, bytes.length * 8);
25 | return uint32ToUint8(md5Bytes);
26 | }
27 |
28 | /*
29 | * Convert an array of little-endian words to an array of bytes
30 | */
31 | function uint32ToUint8(input: Uint32Array) {
32 | // Note: On little endian platforms we could simply return `new
33 | // Uint8Array(input.buffer)` here, but that that won't work on big-endian
34 | // systems. (That said, there's code below that appears to already assume
35 | // little-endian, so maybe this is a moot point? Either way, keeping the
36 | // existing code for now to be safe.)
37 | const bytes = new Uint8Array(input.length * 4);
38 | for (let i = 0; i < input.length * 4; i++) {
39 | bytes[i] = (input[i >> 2] >>> ((i % 4) * 8)) & 0xff;
40 | }
41 | return bytes;
42 | }
43 |
44 | /**
45 | * Calculate output length with padding and bit length
46 | */
47 | function getOutputLength(inputLength8: number) {
48 | return (((inputLength8 + 64) >>> 9) << 4) + 14 + 1;
49 | }
50 |
51 | /*
52 | * Calculate the MD5 of an array of little-endian words, and a bit length.
53 | */
54 | function wordsToMd5(x: Uint32Array, len: number) {
55 | /* append padding */
56 | const xpad = new Uint32Array(getOutputLength(len)).fill(0);
57 | xpad.set(x);
58 | xpad[len >> 5] |= 0x80 << len % 32;
59 | xpad[xpad.length - 1] = len;
60 | x = xpad;
61 |
62 | let a = 1732584193;
63 | let b = -271733879;
64 | let c = -1732584194;
65 | let d = 271733878;
66 |
67 | for (let i = 0; i < x.length; i += 16) {
68 | const olda = a;
69 | const oldb = b;
70 | const oldc = c;
71 | const oldd = d;
72 |
73 | a = md5ff(a, b, c, d, x[i], 7, -680876936);
74 | d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
75 | c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
76 | b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
77 | a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
78 | d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
79 | c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
80 | b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
81 | a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
82 | d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
83 | c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
84 | b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
85 | a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
86 | d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
87 | c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
88 | b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
89 |
90 | a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
91 | d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
92 | c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
93 | b = md5gg(b, c, d, a, x[i], 20, -373897302);
94 | a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
95 | d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
96 | c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
97 | b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
98 | a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
99 | d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
100 | c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
101 | b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
102 | a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
103 | d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
104 | c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
105 | b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
106 |
107 | a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
108 | d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
109 | c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
110 | b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
111 | a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
112 | d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
113 | c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
114 | b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
115 | a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
116 | d = md5hh(d, a, b, c, x[i], 11, -358537222);
117 | c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
118 | b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
119 | a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
120 | d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
121 | c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
122 | b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
123 |
124 | a = md5ii(a, b, c, d, x[i], 6, -198630844);
125 | d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
126 | c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
127 | b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
128 | a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
129 | d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
130 | c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
131 | b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
132 | a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
133 | d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
134 | c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
135 | b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
136 | a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
137 | d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
138 | c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
139 | b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
140 |
141 | a = safeAdd(a, olda);
142 | b = safeAdd(b, oldb);
143 | c = safeAdd(c, oldc);
144 | d = safeAdd(d, oldd);
145 | }
146 |
147 | return Uint32Array.of(a, b, c, d);
148 | }
149 |
150 | /*
151 | * Convert Uint8Array to Uint32 array (little-endian)
152 | */
153 | function uint8ToUint32(input: Uint8Array) {
154 | if (input.length === 0) {
155 | return new Uint32Array();
156 | }
157 |
158 | const output = new Uint32Array(getOutputLength(input.length * 8)).fill(0);
159 | for (let i = 0; i < input.length; i++) {
160 | output[i >> 2] |= (input[i] & 0xff) << ((i % 4) * 8);
161 | }
162 | return output;
163 | }
164 |
165 | /*
166 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
167 | * to work around bugs in some JS interpreters.
168 | */
169 | function safeAdd(x: number, y: number) {
170 | const lsw = (x & 0xffff) + (y & 0xffff);
171 | const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
172 | return (msw << 16) | (lsw & 0xffff);
173 | }
174 |
175 | /*
176 | * Bitwise rotate a 32-bit number to the left.
177 | */
178 | function bitRotateLeft(num: number, cnt: number) {
179 | return (num << cnt) | (num >>> (32 - cnt));
180 | }
181 |
182 | /*
183 | * These functions implement the four basic operations the algorithm uses.
184 | */
185 | function md5cmn(q: number, a: number, b: number, x: number, s: number, t: number) {
186 | return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
187 | }
188 |
189 | function md5ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
190 | return md5cmn((b & c) | (~b & d), a, b, x, s, t);
191 | }
192 |
193 | function md5gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
194 | return md5cmn((b & d) | (c & ~d), a, b, x, s, t);
195 | }
196 |
197 | function md5hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
198 | return md5cmn(b ^ c ^ d, a, b, x, s, t);
199 | }
200 |
201 | function md5ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
202 | return md5cmn(c ^ (b | ~d), a, b, x, s, t);
203 | }
204 |
205 | export default md5;
206 |
--------------------------------------------------------------------------------
/src/md5.ts:
--------------------------------------------------------------------------------
1 | import { createHash } from 'crypto';
2 |
3 | function md5(bytes: Uint8Array) {
4 | if (Array.isArray(bytes)) {
5 | bytes = Buffer.from(bytes);
6 | } else if (typeof bytes === 'string') {
7 | bytes = Buffer.from(bytes, 'utf8');
8 | }
9 |
10 | return createHash('md5').update(bytes).digest();
11 | }
12 |
13 | export default md5;
14 |
--------------------------------------------------------------------------------
/src/native-browser.ts:
--------------------------------------------------------------------------------
1 | const randomUUID =
2 | typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
3 |
4 | export default { randomUUID };
5 |
--------------------------------------------------------------------------------
/src/native.ts:
--------------------------------------------------------------------------------
1 | import { randomUUID } from 'crypto';
2 |
3 | export default { randomUUID };
4 |
--------------------------------------------------------------------------------
/src/nil.ts:
--------------------------------------------------------------------------------
1 | export default '00000000-0000-0000-0000-000000000000';
2 |
--------------------------------------------------------------------------------
/src/parse.ts:
--------------------------------------------------------------------------------
1 | import validate from './validate.js';
2 |
3 | function parse(uuid: string) {
4 | if (!validate(uuid)) {
5 | throw TypeError('Invalid UUID');
6 | }
7 |
8 | let v;
9 | return Uint8Array.of(
10 | (v = parseInt(uuid.slice(0, 8), 16)) >>> 24,
11 | (v >>> 16) & 0xff,
12 | (v >>> 8) & 0xff,
13 | v & 0xff,
14 |
15 | // Parse ........-####-....-....-............
16 | (v = parseInt(uuid.slice(9, 13), 16)) >>> 8,
17 | v & 0xff,
18 |
19 | // Parse ........-....-####-....-............
20 | (v = parseInt(uuid.slice(14, 18), 16)) >>> 8,
21 | v & 0xff,
22 |
23 | // Parse ........-....-....-####-............
24 | (v = parseInt(uuid.slice(19, 23), 16)) >>> 8,
25 | v & 0xff,
26 |
27 | // Parse ........-....-....-....-############
28 | // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
29 | ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff,
30 | (v / 0x100000000) & 0xff,
31 | (v >>> 24) & 0xff,
32 | (v >>> 16) & 0xff,
33 | (v >>> 8) & 0xff,
34 | v & 0xff
35 | );
36 | }
37 |
38 | export default parse;
39 |
--------------------------------------------------------------------------------
/src/regex.ts:
--------------------------------------------------------------------------------
1 | export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
2 |
--------------------------------------------------------------------------------
/src/rng-browser.ts:
--------------------------------------------------------------------------------
1 | // Unique ID creation requires a high quality random # generator. In the browser we therefore
2 | // require the crypto API and do not support built-in fallback to lower quality random number
3 | // generators (like Math.random()).
4 |
5 | let getRandomValues: typeof crypto.getRandomValues | undefined;
6 |
7 | const rnds8 = new Uint8Array(16);
8 |
9 | export default function rng() {
10 | // lazy load so that environments that need to polyfill have a chance to do so
11 | if (!getRandomValues) {
12 | if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
13 | throw new Error(
14 | 'crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'
15 | );
16 | }
17 |
18 | getRandomValues = crypto.getRandomValues.bind(crypto);
19 | }
20 |
21 | return getRandomValues(rnds8);
22 | }
23 |
--------------------------------------------------------------------------------
/src/rng.ts:
--------------------------------------------------------------------------------
1 | import { randomFillSync } from 'crypto';
2 |
3 | const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate
4 | let poolPtr = rnds8Pool.length;
5 |
6 | export default function rng() {
7 | if (poolPtr > rnds8Pool.length - 16) {
8 | randomFillSync(rnds8Pool);
9 | poolPtr = 0;
10 | }
11 | return rnds8Pool.slice(poolPtr, (poolPtr += 16));
12 | }
13 |
--------------------------------------------------------------------------------
/src/sha1-browser.ts:
--------------------------------------------------------------------------------
1 | // Adapted from Chris Veness' SHA1 code at
2 | // http://www.movable-type.co.uk/scripts/sha1.html
3 | function f(s: 0 | 1 | 2 | 3, x: number, y: number, z: number) {
4 | switch (s) {
5 | case 0:
6 | return (x & y) ^ (~x & z);
7 | case 1:
8 | return x ^ y ^ z;
9 | case 2:
10 | return (x & y) ^ (x & z) ^ (y & z);
11 | case 3:
12 | return x ^ y ^ z;
13 | }
14 | }
15 |
16 | function ROTL(x: number, n: number) {
17 | return (x << n) | (x >>> (32 - n));
18 | }
19 |
20 | function sha1(bytes: Uint8Array): Uint8Array {
21 | const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
22 | const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
23 |
24 | const newBytes = new Uint8Array(bytes.length + 1);
25 | newBytes.set(bytes);
26 | newBytes[bytes.length] = 0x80;
27 | bytes = newBytes;
28 |
29 | const l = bytes.length / 4 + 2;
30 | const N = Math.ceil(l / 16);
31 | const M: Uint32Array[] = new Array(N);
32 |
33 | for (let i = 0; i < N; ++i) {
34 | const arr = new Uint32Array(16);
35 |
36 | for (let j = 0; j < 16; ++j) {
37 | arr[j] =
38 | (bytes[i * 64 + j * 4] << 24) |
39 | (bytes[i * 64 + j * 4 + 1] << 16) |
40 | (bytes[i * 64 + j * 4 + 2] << 8) |
41 | bytes[i * 64 + j * 4 + 3];
42 | }
43 |
44 | M[i] = arr;
45 | }
46 |
47 | M[N - 1][14] = ((bytes.length - 1) * 8) / Math.pow(2, 32);
48 | M[N - 1][14] = Math.floor(M[N - 1][14]);
49 | M[N - 1][15] = ((bytes.length - 1) * 8) & 0xffffffff;
50 |
51 | for (let i = 0; i < N; ++i) {
52 | const W = new Uint32Array(80);
53 |
54 | for (let t = 0; t < 16; ++t) {
55 | W[t] = M[i][t];
56 | }
57 |
58 | for (let t = 16; t < 80; ++t) {
59 | W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
60 | }
61 |
62 | let a = H[0];
63 | let b = H[1];
64 | let c = H[2];
65 | let d = H[3];
66 | let e = H[4];
67 |
68 | for (let t = 0; t < 80; ++t) {
69 | const s = Math.floor(t / 20) as 0 | 1 | 2 | 3;
70 | const T = (ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t]) >>> 0;
71 | e = d;
72 | d = c;
73 | c = ROTL(b, 30) >>> 0;
74 | b = a;
75 | a = T;
76 | }
77 |
78 | H[0] = (H[0] + a) >>> 0;
79 | H[1] = (H[1] + b) >>> 0;
80 | H[2] = (H[2] + c) >>> 0;
81 | H[3] = (H[3] + d) >>> 0;
82 | H[4] = (H[4] + e) >>> 0;
83 | }
84 |
85 | // Note: Uint8Array.of() does `& 0xff` for each value
86 | return Uint8Array.of(
87 | H[0] >> 24,
88 | H[0] >> 16,
89 | H[0] >> 8,
90 | H[0],
91 | H[1] >> 24,
92 | H[1] >> 16,
93 | H[1] >> 8,
94 | H[1],
95 | H[2] >> 24,
96 | H[2] >> 16,
97 | H[2] >> 8,
98 | H[2],
99 | H[3] >> 24,
100 | H[3] >> 16,
101 | H[3] >> 8,
102 | H[3],
103 | H[4] >> 24,
104 | H[4] >> 16,
105 | H[4] >> 8,
106 | H[4]
107 | );
108 | }
109 |
110 | export default sha1;
111 |
--------------------------------------------------------------------------------
/src/sha1.ts:
--------------------------------------------------------------------------------
1 | import { createHash } from 'crypto';
2 |
3 | function sha1(bytes: Uint8Array) {
4 | if (Array.isArray(bytes)) {
5 | bytes = Buffer.from(bytes);
6 | } else if (typeof bytes === 'string') {
7 | bytes = Buffer.from(bytes, 'utf8');
8 | }
9 |
10 | return createHash('sha1').update(bytes).digest();
11 | }
12 |
13 | export default sha1;
14 |
--------------------------------------------------------------------------------
/src/stringify.ts:
--------------------------------------------------------------------------------
1 | import validate from './validate.js';
2 |
3 | /**
4 | * Convert array of 16 byte values to UUID string format of the form:
5 | * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
6 | */
7 | const byteToHex: string[] = [];
8 |
9 | for (let i = 0; i < 256; ++i) {
10 | byteToHex.push((i + 0x100).toString(16).slice(1));
11 | }
12 |
13 | export function unsafeStringify(arr: Uint8Array, offset = 0): string {
14 | // Note: Be careful editing this code! It's been tuned for performance
15 | // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
16 | //
17 | // Note to future-self: No, you can't remove the `toLowerCase()` call.
18 | // REF: https://github.com/uuidjs/uuid/pull/677#issuecomment-1757351351
19 | return (
20 | byteToHex[arr[offset + 0]] +
21 | byteToHex[arr[offset + 1]] +
22 | byteToHex[arr[offset + 2]] +
23 | byteToHex[arr[offset + 3]] +
24 | '-' +
25 | byteToHex[arr[offset + 4]] +
26 | byteToHex[arr[offset + 5]] +
27 | '-' +
28 | byteToHex[arr[offset + 6]] +
29 | byteToHex[arr[offset + 7]] +
30 | '-' +
31 | byteToHex[arr[offset + 8]] +
32 | byteToHex[arr[offset + 9]] +
33 | '-' +
34 | byteToHex[arr[offset + 10]] +
35 | byteToHex[arr[offset + 11]] +
36 | byteToHex[arr[offset + 12]] +
37 | byteToHex[arr[offset + 13]] +
38 | byteToHex[arr[offset + 14]] +
39 | byteToHex[arr[offset + 15]]
40 | ).toLowerCase();
41 | }
42 |
43 | function stringify(arr: Uint8Array, offset = 0) {
44 | const uuid = unsafeStringify(arr, offset);
45 |
46 | // Consistency check for valid UUID. If this throws, it's likely due to one
47 | // of the following:
48 | // - One or more input array values don't map to a hex octet (leading to
49 | // "undefined" in the uuid)
50 | // - Invalid input values for the RFC `version` or `variant` fields
51 | if (!validate(uuid)) {
52 | throw TypeError('Stringified UUID is invalid');
53 | }
54 |
55 | return uuid;
56 | }
57 |
58 | export default stringify;
59 |
--------------------------------------------------------------------------------
/src/test/parse.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import parse from '../parse.js';
4 | import stringify from '../stringify.js';
5 | import uuidv4 from '../v4.js';
6 |
7 | // Deterministic PRNG for reproducible tests
8 | // See https://stackoverflow.com/a/47593316/109538
9 | function splitmix32(a: number) {
10 | return function () {
11 | a |= 0;
12 | a = (a + 0x9e3779b9) | 0;
13 | let t = a ^ (a >>> 16);
14 | t = Math.imul(t, 0x21f0aaad);
15 | t = t ^ (t >>> 15);
16 | t = Math.imul(t, 0x735a2d97);
17 | return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;
18 | };
19 | }
20 | const rand = splitmix32(0x12345678);
21 |
22 | function rng(bytes = new Uint8Array(16)) {
23 | for (let i = 0; i < 16; i++) {
24 | bytes[i] = rand() * 256;
25 | }
26 |
27 | return bytes;
28 | }
29 |
30 | describe('parse', () => {
31 | test('String -> bytes parsing', () => {
32 | assert.deepStrictEqual(
33 | parse('0f5abcd1-c194-47f3-905b-2df7263a084b'),
34 | Uint8Array.from([
35 | 0x0f, 0x5a, 0xbc, 0xd1, 0xc1, 0x94, 0x47, 0xf3, 0x90, 0x5b, 0x2d, 0xf7, 0x26, 0x3a, 0x08,
36 | 0x4b,
37 | ])
38 | );
39 | });
40 |
41 | test('String -> bytes -> string symmetry for assorted uuids', () => {
42 | for (let i = 0; i < 1000; i++) {
43 | const uuid = uuidv4({ rng });
44 | assert.equal(stringify(parse(uuid)), uuid);
45 | }
46 | });
47 |
48 | test('Case neutrality', () => {
49 | // Verify upper/lower case neutrality
50 | assert.deepStrictEqual(
51 | parse('0f5abcd1-c194-47f3-905b-2df7263a084b'),
52 | parse('0f5abcd1-c194-47f3-905b-2df7263a084b'.toUpperCase())
53 | );
54 | });
55 |
56 | test('Null UUID case', () => {
57 | assert.deepStrictEqual(
58 | parse('00000000-0000-0000-0000-000000000000'),
59 | Uint8Array.from(new Array(16).fill(0))
60 | );
61 | });
62 |
63 | test('UUID validation', () => {
64 | // @ts-expect-error testing invalid input
65 | assert.throws(() => parse());
66 |
67 | assert.throws(() => parse('invalid uuid'));
68 | assert.throws(() => parse('zyxwvuts-rqpo-nmlk-jihg-fedcba000000'));
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/src/test/rng.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import rng from '../rng.js';
4 |
5 | describe('rng', () => {
6 | test('Node.js RNG', () => {
7 | const bytes = rng();
8 | assert.equal(bytes.length, 16);
9 |
10 | for (let i = 0; i < bytes.length; ++i) {
11 | assert.equal(typeof bytes[i], 'number');
12 | }
13 | });
14 |
15 | // Test of whatwgRNG missing for now since with esmodules we can no longer manipulate the
16 | // require.cache.
17 | });
18 |
--------------------------------------------------------------------------------
/src/test/stringify.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import stringify, { unsafeStringify } from '../stringify.js';
4 |
5 | const BYTES = Uint8Array.of(
6 | 0x0f,
7 | 0x5a,
8 | 0xbc,
9 | 0xd1,
10 | 0xc1,
11 | 0x94,
12 | 0x47,
13 | 0xf3,
14 | 0x90,
15 | 0x5b,
16 | 0x2d,
17 | 0xf7,
18 | 0x26,
19 | 0x3a,
20 | 0x08,
21 | 0x4b
22 | );
23 |
24 | describe('stringify', () => {
25 | test('Stringify Array (unsafe)', () => {
26 | assert.equal(unsafeStringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b');
27 | });
28 |
29 | test('Stringify w/ offset (unsafe)', () => {
30 | const bytes = new Uint8Array(19).fill(0);
31 | bytes.set(BYTES, 3);
32 | assert.equal(unsafeStringify(bytes, 3), '0f5abcd1-c194-47f3-905b-2df7263a084b');
33 | });
34 |
35 | test('Stringify Array (safe)', () => {
36 | assert.equal(stringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b');
37 | });
38 |
39 | test('Throws on not enough values (safe)', () => {
40 | const bytes = BYTES.slice(0, 15);
41 | assert.throws(() => stringify(bytes));
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/src/test/test_constants.ts:
--------------------------------------------------------------------------------
1 | import MAX from '../max.js';
2 | import NIL from '../nil.js';
3 |
4 | // Table of [uuid value, expected validate(), [expected version()]]
5 | export const TESTS = [
6 | // constants
7 | { value: NIL, expectedValidate: true, expectedVersion: 0 },
8 | { value: MAX, expectedValidate: true, expectedVersion: 15 },
9 |
10 | // each version, with either all 0's or all 1's in settable bits
11 | { value: '00000000-0000-1000-8000-000000000000', expectedValidate: true, expectedVersion: 1 },
12 | { value: 'ffffffff-ffff-1fff-8fff-ffffffffffff', expectedValidate: true, expectedVersion: 1 },
13 | { value: '00000000-0000-2000-8000-000000000000', expectedValidate: true, expectedVersion: 2 },
14 | { value: 'ffffffff-ffff-2fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 2 },
15 | { value: '00000000-0000-3000-8000-000000000000', expectedValidate: true, expectedVersion: 3 },
16 | { value: 'ffffffff-ffff-3fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 3 },
17 | { value: '00000000-0000-4000-8000-000000000000', expectedValidate: true, expectedVersion: 4 },
18 | { value: 'ffffffff-ffff-4fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 4 },
19 | { value: '00000000-0000-5000-8000-000000000000', expectedValidate: true, expectedVersion: 5 },
20 | { value: 'ffffffff-ffff-5fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 5 },
21 | { value: '00000000-0000-6000-8000-000000000000', expectedValidate: true, expectedVersion: 6 },
22 | { value: 'ffffffff-ffff-6fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 6 },
23 | { value: '00000000-0000-7000-8000-000000000000', expectedValidate: true, expectedVersion: 7 },
24 | { value: 'ffffffff-ffff-7fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 7 },
25 | { value: '00000000-0000-8000-8000-000000000000', expectedValidate: true, expectedVersion: 8 },
26 | { value: 'ffffffff-ffff-8fff-bfff-ffffffffffff', expectedValidate: true, expectedVersion: 8 },
27 | { value: '00000000-0000-9000-8000-000000000000', expectedValidate: false },
28 | { value: 'ffffffff-ffff-9fff-bfff-ffffffffffff', expectedValidate: false },
29 | { value: '00000000-0000-a000-8000-000000000000', expectedValidate: false },
30 | { value: 'ffffffff-ffff-afff-bfff-ffffffffffff', expectedValidate: false },
31 | { value: '00000000-0000-b000-8000-000000000000', expectedValidate: false },
32 | { value: 'ffffffff-ffff-bfff-bfff-ffffffffffff', expectedValidate: false },
33 | { value: '00000000-0000-c000-8000-000000000000', expectedValidate: false },
34 | { value: 'ffffffff-ffff-cfff-bfff-ffffffffffff', expectedValidate: false },
35 | { value: '00000000-0000-d000-8000-000000000000', expectedValidate: false },
36 | { value: 'ffffffff-ffff-dfff-bfff-ffffffffffff', expectedValidate: false },
37 | { value: '00000000-0000-e000-8000-000000000000', expectedValidate: false },
38 | { value: 'ffffffff-ffff-efff-bfff-ffffffffffff', expectedValidate: false },
39 |
40 | // selection of normal, valid UUIDs
41 | { value: 'd9428888-122b-11e1-b85c-61cd3cbb3210', expectedValidate: true, expectedVersion: 1 },
42 | { value: '000003e8-2363-21ef-b200-325096b39f47', expectedValidate: true, expectedVersion: 2 },
43 | { value: 'a981a0c2-68b1-35dc-bcfc-296e52ab01ec', expectedValidate: true, expectedVersion: 3 },
44 | { value: '109156be-c4fb-41ea-b1b4-efe1671c5836', expectedValidate: true, expectedVersion: 4 },
45 | { value: '90123e1c-7512-523e-bb28-76fab9f2f73d', expectedValidate: true, expectedVersion: 5 },
46 | { value: '1ef21d2f-1207-6660-8c4f-419efbd44d48', expectedValidate: true, expectedVersion: 6 },
47 | { value: '017f22e2-79b0-7cc3-98c4-dc0c0c07398f', expectedValidate: true, expectedVersion: 7 },
48 | { value: '0d8f23a0-697f-83ae-802e-48f3756dd581', expectedValidate: true, expectedVersion: 8 },
49 |
50 | // all variant octet values
51 | { value: '00000000-0000-1000-0000-000000000000', expectedValidate: false },
52 | { value: '00000000-0000-1000-1000-000000000000', expectedValidate: false },
53 | { value: '00000000-0000-1000-2000-000000000000', expectedValidate: false },
54 | { value: '00000000-0000-1000-3000-000000000000', expectedValidate: false },
55 | { value: '00000000-0000-1000-4000-000000000000', expectedValidate: false },
56 | { value: '00000000-0000-1000-5000-000000000000', expectedValidate: false },
57 | { value: '00000000-0000-1000-6000-000000000000', expectedValidate: false },
58 | { value: '00000000-0000-1000-7000-000000000000', expectedValidate: false },
59 | { value: '00000000-0000-1000-8000-000000000000', expectedValidate: true, expectedVersion: 1 },
60 | { value: '00000000-0000-1000-9000-000000000000', expectedValidate: true, expectedVersion: 1 },
61 | { value: '00000000-0000-1000-a000-000000000000', expectedValidate: true, expectedVersion: 1 },
62 | { value: '00000000-0000-1000-b000-000000000000', expectedValidate: true, expectedVersion: 1 },
63 | { value: '00000000-0000-1000-c000-000000000000', expectedValidate: false },
64 | { value: '00000000-0000-1000-d000-000000000000', expectedValidate: false },
65 | { value: '00000000-0000-1000-e000-000000000000', expectedValidate: false },
66 | { value: '00000000-0000-1000-f000-000000000000', expectedValidate: false },
67 |
68 | // invalid strings
69 | { value: '00000000000000000000000000000000', expectedValidate: false }, // unhyphenated NIL
70 | { value: '', expectedValidate: false },
71 | { value: 'invalid uuid string', expectedValidate: false },
72 | {
73 | value: '=Y00a-f*vb*-c-d#-p00f\b-g0h-#i^-j*3&-L00k-\nl---00n-fg000-00p-00r+',
74 | expectedValidate: false,
75 | },
76 |
77 | // invalid types
78 | { value: undefined, expectedValidate: false },
79 | { value: null, expectedValidate: false },
80 | { value: 123, expectedValidate: false },
81 | { value: /regex/, expectedValidate: false },
82 | { value: new Date(0), expectedValidate: false },
83 | { value: false, expectedValidate: false },
84 | ];
85 |
86 | // Add NIL and MAX UUIDs with 1-bit flipped in each position
87 | for (let charIndex = 0; charIndex < 36; charIndex++) {
88 | // Skip hyphens and version char
89 | if (
90 | charIndex === 8 ||
91 | charIndex === 13 ||
92 | charIndex === 14 || // version char
93 | charIndex === 18 ||
94 | charIndex === 23
95 | ) {
96 | continue;
97 | }
98 |
99 | const nilChars = NIL.split('');
100 | const maxChars = MAX.split('');
101 |
102 | for (let i = 0; i < 4; i++) {
103 | nilChars[charIndex] = (0x0 ^ (1 << i)).toString(16);
104 | // NIL UUIDs w/ a single 1-bit
105 | TESTS.push({ value: nilChars.join(''), expectedValidate: false });
106 |
107 | // MAX UUIDs w/ a single 0-bit
108 | maxChars[charIndex] = (0xf ^ (1 << i)).toString(16);
109 | TESTS.push({ value: maxChars.join(''), expectedValidate: false });
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/test/v1.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import parse from '../parse.js';
4 | import v1, { updateV1State } from '../v1.js';
5 |
6 | // Verify ordering of v1 ids created with explicit times
7 | const TIME = 1321644961388; // 2011-11-18 11:36:01.388-08:00
8 |
9 | // Fixture values for testing with the rfc v1 UUID example:
10 | // https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv1-value
11 | const RFC_V1 = 'c232ab00-9414-11ec-b3c8-9f68deced846';
12 | const RFC_V1_BYTES = parse(RFC_V1);
13 |
14 | // `options` for producing the above RFC UUID
15 | const RFC_OPTIONS = {
16 | msecs: 0x17f22e279b0,
17 | nsecs: 0,
18 | clockseq: 0x33c8,
19 | node: Uint8Array.of(0x9f, 0x68, 0xde, 0xce, 0xd8, 0x46),
20 | };
21 |
22 | // random bytes for producing the above RFC UUID
23 | const RFC_RANDOM = Uint8Array.of(
24 | // unused
25 | 0,
26 | 0,
27 | 0,
28 | 0,
29 | 0,
30 | 0,
31 | 0,
32 | 0,
33 |
34 | // clock seq
35 | RFC_OPTIONS.clockseq >> 8,
36 | RFC_OPTIONS.clockseq & 0xff,
37 |
38 | // node
39 | ...RFC_OPTIONS.node
40 | );
41 |
42 | // Compare v1 timestamp fields chronologically
43 | function compareV1TimeField(a: string, b: string) {
44 | a = a.split('-').slice(0, 3).reverse().join('');
45 | b = b.split('-').slice(0, 3).reverse().join('');
46 | return a < b ? -1 : a > b ? 1 : 0;
47 | }
48 |
49 | describe('v1', () => {
50 | test('v1 sort order (default)', () => {
51 | const ids = [v1(), v1(), v1(), v1(), v1()];
52 |
53 | const sorted = [...ids].sort(compareV1TimeField);
54 | assert.deepEqual(ids, sorted);
55 | });
56 |
57 | // Verify ordering of v1 ids created with explicit times
58 | test('v1 sort order (time option)', () => {
59 | const ids = [
60 | v1({ msecs: TIME - 10 * 3600 * 1000 }),
61 | v1({ msecs: TIME - 1 }),
62 | v1({ msecs: TIME }),
63 | v1({ msecs: TIME + 1 }),
64 | v1({ msecs: TIME + 28 * 24 * 3600 * 1000 }),
65 | ];
66 |
67 | const sorted = [...ids].sort(compareV1TimeField);
68 | assert.deepEqual(ids, sorted);
69 | });
70 |
71 | test('v1(options)', () => {
72 | assert.equal(v1({ msecs: RFC_OPTIONS.msecs, random: RFC_RANDOM }), RFC_V1, 'minimal options');
73 | assert.equal(v1(RFC_OPTIONS), RFC_V1, 'full options');
74 | });
75 |
76 | test('v1(options) equality', () => {
77 | assert.notEqual(v1({ msecs: TIME }), v1({ msecs: TIME }), 'UUIDs with minimal options differ');
78 | assert.equal(v1(RFC_OPTIONS), v1(RFC_OPTIONS), 'UUIDs with full options are identical');
79 | });
80 |
81 | test('fills one UUID into a buffer as expected', () => {
82 | const buffer = new Uint8Array(16);
83 | const result = v1(RFC_OPTIONS, buffer);
84 | assert.deepEqual(buffer, RFC_V1_BYTES);
85 | assert.strictEqual(buffer, result);
86 | });
87 |
88 | test('fills two UUIDs into a buffer as expected', () => {
89 | const buffer = new Uint8Array(32);
90 | v1(RFC_OPTIONS, buffer, 0);
91 | v1(RFC_OPTIONS, buffer, 16);
92 |
93 | const expectedBuf = new Uint8Array(32);
94 | expectedBuf.set(RFC_V1_BYTES);
95 | expectedBuf.set(RFC_V1_BYTES, 16);
96 |
97 | assert.deepEqual(buffer, expectedBuf);
98 | });
99 |
100 | test('v1() state transitions', () => {
101 | // Test fixture for internal state passed into updateV1State function
102 | const PRE_STATE = {
103 | msecs: 10,
104 | nsecs: 20,
105 | clockseq: 0x1234,
106 | node: Uint8Array.of(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc),
107 | };
108 |
109 | // Note: The test code, below, passes RFC_RANDOM as the `rnds` argument for
110 | // convenience. This allows us to test that fields have been initialized from
111 | // the rnds argument by testing for RFC_OPTIONS values in the output state.
112 |
113 | const tests = [
114 | {
115 | title: 'initial state',
116 | state: {},
117 | now: 10,
118 | expected: {
119 | msecs: 10, // -> now
120 | nsecs: 0, // -> init
121 | clockseq: RFC_OPTIONS.clockseq, // -> random
122 | node: RFC_OPTIONS.node, // -> random
123 | },
124 | },
125 | {
126 | title: 'same time interval',
127 | state: { ...PRE_STATE },
128 | now: PRE_STATE.msecs,
129 | expected: {
130 | ...PRE_STATE,
131 | nsecs: 21, // -> +1
132 | },
133 | },
134 | {
135 | title: 'new time interval',
136 | state: { ...PRE_STATE },
137 | now: PRE_STATE.msecs + 1,
138 | expected: {
139 | ...PRE_STATE,
140 | msecs: PRE_STATE.msecs + 1, // -> +1
141 | nsecs: 0, // -> init
142 | },
143 | },
144 | {
145 | title: 'same time interval (nsecs overflow)',
146 | state: { ...PRE_STATE, nsecs: 9999 },
147 | now: PRE_STATE.msecs,
148 | expected: {
149 | ...PRE_STATE,
150 | nsecs: 0, // -> init
151 | clockseq: RFC_OPTIONS.clockseq, // -> init
152 | node: RFC_OPTIONS.node, // -> init
153 | },
154 | },
155 | {
156 | title: 'time regression',
157 | state: { ...PRE_STATE },
158 | now: PRE_STATE.msecs - 1,
159 | expected: {
160 | ...PRE_STATE,
161 | msecs: PRE_STATE.msecs - 1, // -> now
162 | clockseq: RFC_OPTIONS.clockseq, // -> init
163 | node: RFC_OPTIONS.node, // -> init
164 | },
165 | },
166 | ];
167 | for (const { title, state, now, expected } of tests) {
168 | assert.deepStrictEqual(updateV1State(state, now, RFC_RANDOM), expected, `Failed: ${title}`);
169 | }
170 | });
171 |
172 | test('throws when option.random is too short', () => {
173 | const random = Uint8Array.of(16);
174 | const buffer = new Uint8Array(16).fill(0);
175 | assert.throws(() => {
176 | v1({ random }, buffer);
177 | });
178 | });
179 |
180 | test('throws when options.rng() is too short', () => {
181 | const buffer = new Uint8Array(16);
182 | const rng = () => Uint8Array.of(0); // length = 1
183 | assert.throws(() => {
184 | v1({ rng }, buffer);
185 | });
186 | });
187 |
188 | test('throws RangeError for out-of-range indexes', () => {
189 | const buf15 = new Uint8Array(15);
190 | const buf30 = new Uint8Array(30);
191 | assert.throws(() => v1({}, buf15));
192 | assert.throws(() => v1({}, buf30, -1));
193 | assert.throws(() => v1({}, buf30, 15));
194 | });
195 | });
196 |
--------------------------------------------------------------------------------
/src/test/v35.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import md5 from '../md5.js';
4 | import sha1 from '../sha1.js';
5 | import v3 from '../v3.js';
6 | import { stringToBytes } from '../v35.js';
7 | import v5 from '../v5.js';
8 |
9 | describe('v35', () => {
10 | const HASH_SAMPLES = [
11 | {
12 | input: stringToBytes(''),
13 | sha1: 'da39a3ee5e6b4b0d3255bfef95601890afd80709',
14 | md5: 'd41d8cd98f00b204e9800998ecf8427e',
15 | },
16 |
17 | // Extended ascii chars
18 | {
19 | input: stringToBytes(
20 | '\t\b\f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A8\u00A9\u00AA\u00AB\u00AC\u00AE\u00AF\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF'
21 | ),
22 | sha1: 'ca4a426a3d536f14cfd79011e79e10d64de950a0',
23 | md5: 'e8098ec21950f841731d28749129d3ee',
24 | },
25 |
26 | // A sampling from the Unicode BMP
27 | {
28 | input: stringToBytes(
29 | '\u00A5\u0104\u018F\u0256\u02B1o\u0315\u038E\u0409\u0500\u0531\u05E1\u05B6\u0920\u0903\u09A4\u0983\u0A20\u0A02\u0AA0\u0A83\u0B06\u0C05\u0C03\u1401\u16A0'
30 | ),
31 | sha1: 'f2753ebc390e5f637e333c2a4179644a93ae9f65',
32 | md5: '231b309e277b6be8bb3d6c688b7f098b',
33 | },
34 | ];
35 |
36 | function hashToHex(hash: Uint8Array) {
37 | const chars = new Array(hash.length);
38 | for (let i = 0; i < hash.length; i++) {
39 | chars[i] = hash[i].toString(16).padStart(2, '0');
40 | }
41 | return chars.join('');
42 | }
43 |
44 | HASH_SAMPLES.forEach(function (sample, i) {
45 | test(`sha1(node) HASH_SAMPLES[${i}]`, () => {
46 | assert.equal(hashToHex(sha1(sample.input)), sample.sha1);
47 | });
48 | });
49 |
50 | HASH_SAMPLES.forEach(function (sample, i) {
51 | test(`md5(node) HASH_SAMPLES[${i}]`, () => {
52 | assert.equal(hashToHex(md5(sample.input)), sample.md5);
53 | });
54 | });
55 |
56 | test('v3', () => {
57 | // Expect to get the same results as http://tools.adjet.org/uuid-v3
58 | assert.strictEqual(v3('hello.example.com', v3.DNS), '9125a8dc-52ee-365b-a5aa-81b0b3681cf6');
59 |
60 | assert.strictEqual(
61 | v3('http://example.com/hello', v3.URL),
62 | 'c6235813-3ba4-3801-ae84-e0a6ebb7d138'
63 | );
64 |
65 | assert.strictEqual(
66 | v3('hello', '0f5abcd1-c194-47f3-905b-2df7263a084b'),
67 | 'a981a0c2-68b1-35dc-bcfc-296e52ab01ec'
68 | );
69 | });
70 |
71 | test('v3 namespace.toUpperCase', () => {
72 | assert.strictEqual(
73 | v3('hello.example.com', v3.DNS.toUpperCase()),
74 | '9125a8dc-52ee-365b-a5aa-81b0b3681cf6'
75 | );
76 |
77 | assert.strictEqual(
78 | v3('http://example.com/hello', v3.URL.toUpperCase()),
79 | 'c6235813-3ba4-3801-ae84-e0a6ebb7d138'
80 | );
81 |
82 | assert.strictEqual(
83 | v3('hello', '0f5abcd1-c194-47f3-905b-2df7263a084b'.toUpperCase()),
84 | 'a981a0c2-68b1-35dc-bcfc-296e52ab01ec'
85 | );
86 | });
87 |
88 | test('v3 namespace string validation', () => {
89 | assert.throws(() => {
90 | v3('hello.example.com', 'zyxwvuts-rqpo-nmlk-jihg-fedcba000000');
91 | });
92 |
93 | assert.throws(() => {
94 | v3('hello.example.com', 'invalid uuid value');
95 | });
96 |
97 | assert.ok(v3('hello.example.com', '00000000-0000-0000-0000-000000000000'));
98 | });
99 |
100 | test('v3 namespace buffer validation', () => {
101 | assert.throws(() => {
102 | v3('hello.example.com', new Uint8Array(15));
103 | });
104 |
105 | assert.throws(() => {
106 | v3('hello.example.com', new Uint8Array(17));
107 | });
108 |
109 | assert.ok(v3('hello.example.com', new Uint8Array(16).fill(0)));
110 | });
111 |
112 | test('v3 fill buffer', () => {
113 | let buf = new Uint8Array(16);
114 |
115 | const expectedUuid = Uint8Array.of(
116 | 0x91,
117 | 0x25,
118 | 0xa8,
119 | 0xdc,
120 | 0x52,
121 | 0xee,
122 | 0x36,
123 | 0x5b,
124 | 0xa5,
125 | 0xaa,
126 | 0x81,
127 | 0xb0,
128 | 0xb3,
129 | 0x68,
130 | 0x1c,
131 | 0xf6
132 | );
133 |
134 | const result = v3('hello.example.com', v3.DNS, buf);
135 |
136 | assert.deepEqual(buf, expectedUuid);
137 | assert.strictEqual(result, buf);
138 |
139 | // test offsets as well
140 | buf = new Uint8Array(19).fill(0xaa);
141 |
142 | const expectedBuf = new Uint8Array(19).fill(0xaa);
143 | expectedBuf.set(expectedUuid, 3);
144 |
145 | v3('hello.example.com', v3.DNS, buf, 3);
146 |
147 | assert.deepEqual(buf, expectedBuf);
148 | });
149 |
150 | test('v3 undefined/null', () => {
151 | // @ts-expect-error testing invalid input
152 | assert.throws(() => v3());
153 | // @ts-expect-error testing invalid input
154 | assert.throws(() => v3('hello'));
155 | // @ts-expect-error testing invalid input
156 | assert.throws(() => v3('hello.example.com', undefined));
157 | // @ts-expect-error testing invalid input
158 | assert.throws(() => v3('hello.example.com', null, new Uint8Array(16)));
159 | });
160 |
161 | test('v5', () => {
162 | // Expect to get the same results as http://tools.adjet.org/uuid-v5
163 | assert.strictEqual(v5('hello.example.com', v5.DNS), 'fdda765f-fc57-5604-a269-52a7df8164ec');
164 |
165 | assert.strictEqual(
166 | v5('http://example.com/hello', v5.URL),
167 | '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'
168 | );
169 |
170 | assert.strictEqual(
171 | v5('hello', '0f5abcd1-c194-47f3-905b-2df7263a084b'),
172 | '90123e1c-7512-523e-bb28-76fab9f2f73d'
173 | );
174 | });
175 |
176 | test('v5 namespace.toUpperCase', () => {
177 | // Expect to get the same results as http://tools.adjet.org/uuid-v5
178 | assert.strictEqual(
179 | v5('hello.example.com', v5.DNS.toUpperCase()),
180 | 'fdda765f-fc57-5604-a269-52a7df8164ec'
181 | );
182 |
183 | assert.strictEqual(
184 | v5('http://example.com/hello', v5.URL.toUpperCase()),
185 | '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'
186 | );
187 |
188 | assert.strictEqual(
189 | v5('hello', '0f5abcd1-c194-47f3-905b-2df7263a084b'.toUpperCase()),
190 | '90123e1c-7512-523e-bb28-76fab9f2f73d'
191 | );
192 | });
193 |
194 | test('v5 namespace string validation', () => {
195 | assert.throws(() => {
196 | v5('hello.example.com', 'zyxwvuts-rqpo-nmlk-jihg-fedcba000000');
197 | });
198 |
199 | assert.throws(() => {
200 | v5('hello.example.com', 'invalid uuid value');
201 | });
202 |
203 | assert.ok(v5('hello.example.com', '00000000-0000-0000-0000-000000000000'));
204 | });
205 |
206 | test('v5 namespace buffer validation', () => {
207 | assert.throws(() => {
208 | v5('hello.example.com', new Uint8Array(15));
209 | });
210 |
211 | assert.throws(() => {
212 | v5('hello.example.com', new Uint8Array(17));
213 | });
214 |
215 | assert.ok(v5('hello.example.com', new Uint8Array(16).fill(0)));
216 | });
217 |
218 | test('v5 fill buffer', () => {
219 | let buf = new Uint8Array(16);
220 |
221 | const expectedUuid = Uint8Array.of(
222 | 0xfd,
223 | 0xda,
224 | 0x76,
225 | 0x5f,
226 | 0xfc,
227 | 0x57,
228 | 0x56,
229 | 0x04,
230 | 0xa2,
231 | 0x69,
232 | 0x52,
233 | 0xa7,
234 | 0xdf,
235 | 0x81,
236 | 0x64,
237 | 0xec
238 | );
239 |
240 | const result = v5('hello.example.com', v5.DNS, buf);
241 | assert.deepEqual(buf, expectedUuid);
242 | assert.strictEqual(result, buf);
243 |
244 | // test offsets as well
245 | buf = new Uint8Array(19).fill(0xaa);
246 |
247 | const expectedBuf = new Uint8Array(19).fill(0xaa);
248 | expectedBuf.set(expectedUuid, 3);
249 |
250 | v5('hello.example.com', v5.DNS, buf, 3);
251 |
252 | assert.deepEqual(buf, expectedBuf);
253 | });
254 |
255 | test('v5 undefined/null', () => {
256 | // @ts-expect-error testing invalid input
257 | assert.throws(() => v5());
258 | // @ts-expect-error testing invalid input
259 | assert.throws(() => v5('hello'));
260 | // @ts-expect-error testing invalid input
261 | assert.throws(() => v5('hello.example.com', undefined));
262 | // @ts-expect-error testing invalid input
263 | assert.throws(() => v5('hello.example.com', null, new Uint8Array(16)));
264 | });
265 |
266 | test('v3/v5 constants', () => {
267 | assert.strictEqual(v3.DNS, '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
268 | assert.strictEqual(v3.URL, '6ba7b811-9dad-11d1-80b4-00c04fd430c8');
269 | assert.strictEqual(v5.DNS, '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
270 | assert.strictEqual(v5.URL, '6ba7b811-9dad-11d1-80b4-00c04fd430c8');
271 | });
272 | });
273 |
--------------------------------------------------------------------------------
/src/test/v4.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import native from '../native.js';
4 | import v4 from '../v4.js';
5 |
6 | const randomBytesFixture = Uint8Array.of(
7 | 0x10,
8 | 0x91,
9 | 0x56,
10 | 0xbe,
11 | 0xc4,
12 | 0xfb,
13 | 0xc1,
14 | 0xea,
15 | 0x71,
16 | 0xb4,
17 | 0xef,
18 | 0xe1,
19 | 0x67,
20 | 0x1c,
21 | 0x58,
22 | 0x36
23 | );
24 |
25 | const expectedBytes = Uint8Array.of(
26 | 16,
27 | 145,
28 | 86,
29 | 190,
30 | 196,
31 | 251,
32 | 65,
33 | 234,
34 | 177,
35 | 180,
36 | 239,
37 | 225,
38 | 103,
39 | 28,
40 | 88,
41 | 54
42 | );
43 |
44 | describe('v4', () => {
45 | test('subsequent UUIDs are different', () => {
46 | const id1 = v4();
47 | const id2 = v4();
48 |
49 | assert.ok(id1 !== id2);
50 | });
51 |
52 | test('should uses native randomUUID() if no option is passed', async () => {
53 | // TODO: `mock` is not supported until node@18, so we feature-detect it
54 | // here. Once node@16 drops off our support matrix, we can just
55 | // static-import it normally
56 | const mock = (await import('node:test')).default.mock;
57 | if (!mock) {
58 | return;
59 | }
60 |
61 | const mockRandomUUID = mock.method(native, 'randomUUID');
62 |
63 | assert.equal(mockRandomUUID.mock.callCount(), 0);
64 | v4();
65 | assert.equal(mockRandomUUID.mock.callCount(), 1);
66 |
67 | mock.restoreAll();
68 | });
69 |
70 | test('should not use native randomUUID() if an option is passed', async () => {
71 | // TODO: `mock` is not supported until node@18, so we feature-detect it
72 | // here. Once node@16 drops off our support matrix, we can just
73 | // static-import it normally
74 | const mock = (await import('node:test')).default.mock;
75 | if (!mock) {
76 | return;
77 | }
78 |
79 | const mockRandomUUID = mock.method(native, 'randomUUID');
80 |
81 | assert.equal(mockRandomUUID.mock.callCount(), 0);
82 | v4({});
83 | assert.equal(mockRandomUUID.mock.callCount(), 0);
84 |
85 | mock.restoreAll();
86 | });
87 |
88 | test('explicit options.random produces expected result', () => {
89 | const id = v4({ random: randomBytesFixture });
90 | assert.strictEqual(id, '109156be-c4fb-41ea-b1b4-efe1671c5836');
91 | });
92 |
93 | test('explicit options.rng produces expected result', () => {
94 | const id = v4({ rng: () => randomBytesFixture });
95 | assert.strictEqual(id, '109156be-c4fb-41ea-b1b4-efe1671c5836');
96 | });
97 |
98 | test('fills one UUID into a buffer as expected', () => {
99 | const buffer = new Uint8Array(16);
100 | const result = v4({ random: randomBytesFixture }, buffer);
101 |
102 | assert.deepEqual(buffer, expectedBytes);
103 | assert.strictEqual(buffer, result);
104 | });
105 |
106 | test('fills two UUIDs into a buffer as expected', () => {
107 | const buffer = new Uint8Array(32);
108 | v4({ random: randomBytesFixture }, buffer, 0);
109 | v4({ random: randomBytesFixture }, buffer, 16);
110 |
111 | const expectedBuf = new Uint8Array(32);
112 | expectedBuf.set(expectedBytes);
113 | expectedBuf.set(expectedBytes, 16);
114 |
115 | assert.deepEqual(buffer, expectedBuf);
116 | });
117 |
118 | test('throws when option.random is too short', () => {
119 | const random = Uint8Array.of(16);
120 | const buffer = new Uint8Array(16).fill(0);
121 | assert.throws(() => {
122 | v4({ random }, buffer);
123 | });
124 | });
125 |
126 | test('throws when options.rng() is too short', () => {
127 | const buffer = new Uint8Array(16);
128 | const rng = () => Uint8Array.of(0); // length = 1
129 | assert.throws(() => {
130 | v4({ rng }, buffer);
131 | });
132 | });
133 |
134 | test('throws RangeError for out-of-range indexes', () => {
135 | const buf15 = new Uint8Array(15);
136 | const buf30 = new Uint8Array(30);
137 | assert.throws(() => v4({}, buf15));
138 | assert.throws(() => v4({}, buf30, -1));
139 | assert.throws(() => v4({}, buf30, 15));
140 | });
141 | });
142 |
--------------------------------------------------------------------------------
/src/test/v6.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import v1ToV6 from '../v1ToV6.js';
4 | import v6 from '../v6.js';
5 | import v6ToV1 from '../v6ToV1.js';
6 |
7 | describe('v6', () => {
8 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
9 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
10 |
11 | const fullOptions = {
12 | msecs: 0x133b891f705,
13 | nsecs: 0x1538,
14 | clockseq: 0x385c,
15 | node: Uint8Array.of(0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10),
16 | };
17 |
18 | const EXPECTED_BYTES = Uint8Array.of(
19 | 0x1e,
20 | 0x11,
21 | 0x22,
22 | 0xbd,
23 | 0x94,
24 | 0x28,
25 | 0x68,
26 | 0x88,
27 | 0xb8,
28 | 0x5c,
29 | 0x61,
30 | 0xcd,
31 | 0x3c,
32 | 0xbb,
33 | 0x32,
34 | 0x10
35 | );
36 |
37 | test('default behavior', () => {
38 | // Verify explicit options produce expected id
39 | const id = v6();
40 | assert.ok(
41 | /[0-9a-f]{8}-[0-9a-f]{4}-6[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/.test(id),
42 |
43 | 'id is valid v6 UUID'
44 | );
45 | });
46 |
47 | test('default behavior (binary type)', () => {
48 | const buffer = new Uint8Array(16);
49 | const result = v6(fullOptions, buffer);
50 | assert.deepEqual(buffer, EXPECTED_BYTES);
51 | assert.strictEqual(buffer, result);
52 | });
53 |
54 | test('all options', () => {
55 | // Verify explicit options produce expected id
56 | const id = v6(fullOptions);
57 | assert.equal(id, '1e1122bd-9428-6888-b85c-61cd3cbb3210');
58 | });
59 |
60 | test('sort by creation time', () => {
61 | // Verify ids sort by creation time
62 | const ids = [];
63 | for (let i = 0; i < 5; i++) {
64 | ids.push(v6({ msecs: i * 1000 }));
65 | }
66 | assert.deepEqual(ids, ids.slice().sort());
67 | });
68 |
69 | test('creating at array offset', () => {
70 | const buffer = new Uint8Array(32);
71 | v6(fullOptions, buffer, 0);
72 | v6(fullOptions, buffer, 16);
73 |
74 | const expectedBuf = new Uint8Array(32);
75 | expectedBuf.set(EXPECTED_BYTES, 0);
76 | expectedBuf.set(EXPECTED_BYTES, 16);
77 |
78 | assert.deepEqual(buffer, expectedBuf);
79 | });
80 |
81 | test('v1 -> v6 conversion', () => {
82 | const id = v1ToV6(V1_ID);
83 | assert.equal(id, V6_ID);
84 | });
85 |
86 | test('v6 -> v1 conversion', () => {
87 | const id = v6ToV1(V6_ID);
88 | assert.equal(id, V1_ID);
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/src/test/v7.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import parse from '../parse.js';
4 | import stringify from '../stringify.js';
5 | import { Version7Options } from '../types.js';
6 | import v7, { updateV7State } from '../v7.js';
7 |
8 | // Fixture values for testing with the rfc v7 UUID example:
9 | // https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv7-value
10 | const RFC_V7 = '017f22e2-79b0-7cc3-98c4-dc0c0c07398f';
11 | const RFC_V7_BYTES = parse('017f22e2-79b0-7cc3-98c4-dc0c0c07398f');
12 | const RFC_MSECS = 0x17f22e279b0;
13 |
14 | // `option.seq` for the above RFC uuid
15 | const RFC_SEQ = (0x0cc3 << 20) | (0x98c4dc >> 2);
16 |
17 | // `option,random` for the above RFC uuid
18 | const RFC_RANDOM = Uint8Array.of(
19 | 0x10,
20 | 0x91,
21 | 0x56,
22 | 0xbe,
23 | 0xc4,
24 | 0xfb,
25 | 0x0c,
26 | 0xc3,
27 | 0x18,
28 | 0xc4,
29 | 0x6c,
30 | 0x0c,
31 | 0x0c,
32 | 0x07,
33 | 0x39,
34 | 0x8f
35 | );
36 |
37 | describe('v7', () => {
38 | test('subsequent UUIDs are different', () => {
39 | const id1 = v7();
40 | const id2 = v7();
41 | assert.ok(id1 !== id2);
42 | });
43 |
44 | test('explicit options.random and options.msecs produces expected result', () => {
45 | const id = v7({
46 | random: RFC_RANDOM,
47 | msecs: RFC_MSECS,
48 | seq: RFC_SEQ,
49 | });
50 | assert.strictEqual(id, RFC_V7);
51 | });
52 |
53 | test('explicit options.rng produces expected result', () => {
54 | const id = v7({
55 | rng: () => RFC_RANDOM,
56 | msecs: RFC_MSECS,
57 | seq: RFC_SEQ,
58 | });
59 | assert.strictEqual(id, RFC_V7);
60 | });
61 |
62 | test('explicit options.msecs produces expected result', () => {
63 | const id = v7({
64 | msecs: RFC_MSECS,
65 | });
66 | assert.strictEqual(id.indexOf('017f22e2'), 0);
67 | });
68 |
69 | test('fills one UUID into a buffer as expected', () => {
70 | const buffer = new Uint8Array(16);
71 | const result = v7(
72 | {
73 | random: RFC_RANDOM,
74 | msecs: RFC_MSECS,
75 | seq: RFC_SEQ,
76 | },
77 | buffer
78 | );
79 | stringify(buffer);
80 |
81 | assert.deepEqual(buffer, RFC_V7_BYTES);
82 | assert.strictEqual(buffer, result);
83 | });
84 |
85 | test('fills two UUIDs into a buffer as expected', () => {
86 | const buffer = new Uint8Array(32);
87 |
88 | v7(
89 | {
90 | random: RFC_RANDOM,
91 | msecs: RFC_MSECS,
92 | seq: RFC_SEQ,
93 | },
94 | buffer,
95 | 0
96 | );
97 | v7(
98 | {
99 | random: RFC_RANDOM,
100 | msecs: RFC_MSECS,
101 | seq: RFC_SEQ,
102 | },
103 | buffer,
104 | 16
105 | );
106 | const expected = new Uint8Array(32);
107 | expected.set(RFC_V7_BYTES);
108 | expected.set(RFC_V7_BYTES, 16);
109 | assert.deepEqual(buffer, expected);
110 | });
111 |
112 | //
113 | // monotonic and lexicographical sorting tests
114 | //
115 |
116 | test('lexicographical sorting is preserved', () => {
117 | let id;
118 | let prior;
119 | let msecs = RFC_MSECS;
120 | for (let i = 0; i < 20000; ++i) {
121 | if (i % 1500 === 0) {
122 | // every 1500 runs increment msecs so seq is
123 | // reinitialized, simulating passage of time
124 | msecs += 1;
125 | }
126 |
127 | id = v7({ msecs, seq: i });
128 |
129 | if (prior !== undefined) {
130 | assert.ok(prior < id, `${prior} < ${id}`);
131 | }
132 |
133 | prior = id;
134 | }
135 | });
136 |
137 | test('can supply seq', () => {
138 | let seq = 0x12345;
139 | let uuid = v7({
140 | msecs: RFC_MSECS,
141 | seq,
142 | });
143 |
144 | assert.strictEqual(uuid.substr(0, 25), '017f22e2-79b0-7000-848d-1');
145 |
146 | seq = 0x6fffffff;
147 | uuid = v7({
148 | msecs: RFC_MSECS,
149 | seq,
150 | });
151 |
152 | assert.strictEqual(uuid.substring(0, 25), '017f22e2-79b0-76ff-bfff-f');
153 | });
154 |
155 | test('internal seq is reset upon timestamp change', () => {
156 | v7({
157 | msecs: RFC_MSECS,
158 | seq: 0x6fffffff,
159 | });
160 |
161 | const uuid = v7({
162 | msecs: RFC_MSECS + 1,
163 | });
164 |
165 | assert.ok(uuid.indexOf('fff') !== 15);
166 | });
167 |
168 | test('v7() state transitions', () => {
169 | const tests = [
170 | {
171 | title: 'new time interval',
172 | state: { msecs: 1, seq: 123 },
173 | now: 2,
174 | expected: {
175 | msecs: 2, // time interval should update
176 | seq: 0x6c318c4, // sequence should be randomized
177 | },
178 | },
179 | {
180 | title: 'same time interval',
181 | state: { msecs: 1, seq: 123 },
182 | now: 1,
183 | expected: {
184 | msecs: 1, // timestamp unchanged
185 | seq: 124, // sequence increments
186 | },
187 | },
188 | {
189 | title: 'same time interval (sequence rollover)',
190 | state: { msecs: 1, seq: 0xffffffff },
191 | now: 1,
192 | expected: {
193 | msecs: 2, // timestamp increments
194 | seq: 0, // sequence rolls over
195 | },
196 | },
197 | {
198 | title: 'time regression',
199 | state: { msecs: 2, seq: 123 },
200 | now: 1,
201 | expected: {
202 | msecs: 2, // timestamp unchanged
203 | seq: 124, // sequence increments
204 | },
205 | },
206 | {
207 | title: 'time regression (sequence rollover)',
208 | state: { msecs: 2, seq: 0xffffffff },
209 | now: 1,
210 | expected: {
211 | // timestamp increments (crazy, right? The system clock goes backwards
212 | // but the UUID timestamp moves forward? Weird, but it's what's
213 | // required to maintain monotonicity... and this is why we have unit
214 | // tests!)
215 | msecs: 3,
216 | seq: 0, // sequence rolls over
217 | },
218 | },
219 | ];
220 | for (const { title, state, now, expected } of tests) {
221 | assert.deepStrictEqual(updateV7State(state, now, RFC_RANDOM), expected, `Failed: ${title}`);
222 | }
223 | });
224 |
225 | test('flipping bits changes the result', () => {
226 | // convert uint8array to BigInt (BE)
227 | const asBigInt = (buf: Uint8Array) => buf.reduce((acc, v) => (acc << 8n) | BigInt(v), 0n);
228 |
229 | // convert the given number of bits (LE) to number
230 | const asNumber = (bits: number, data: bigint) => Number(BigInt.asUintN(bits, data));
231 |
232 | // flip the nth bit (BE) in a BigInt
233 | const flip = (data: bigint, n: number) => data ^ (1n << BigInt(127 - n));
234 |
235 | // Extract v7 `options` from a (BigInt) UUID
236 | const optionsFrom = (data: bigint): Version7Options => {
237 | const ms = asNumber(48, data >> 80n);
238 | const hi = asNumber(12, data >> 64n);
239 | const lo = asNumber(20, data >> 42n);
240 | const r = BigInt.asUintN(42, data);
241 | return {
242 | msecs: ms,
243 | seq: (hi << 20) | lo,
244 | random: Uint8Array.from([
245 | ...Array(10).fill(0),
246 | ...Array(6)
247 | .fill(0)
248 | .map((_, i) => asNumber(8, r >> (BigInt(i) * 8n)))
249 | .reverse(),
250 | ]),
251 | };
252 | };
253 | const buf = new Uint8Array(16);
254 | const data = asBigInt(v7({}, buf));
255 | const id = stringify(buf);
256 | const reserved = [48, 49, 50, 51, 64, 65];
257 | for (let i = 0; i < 128; ++i) {
258 | if (reserved.includes(i)) {
259 | continue; // skip bits used for version and variant
260 | }
261 | const flipped = flip(data, i);
262 | assert.strictEqual(
263 | asBigInt(v7(optionsFrom(flipped), buf)).toString(16),
264 | flipped.toString(16),
265 | `Unequal uuids at bit ${i}`
266 | );
267 | assert.notStrictEqual(stringify(buf), id);
268 | }
269 | });
270 |
271 | test('throws when option.random is too short', () => {
272 | const random = Uint8Array.of(16);
273 | const buffer = new Uint8Array(16).fill(0);
274 | assert.throws(() => {
275 | v7({ random }, buffer);
276 | });
277 | });
278 |
279 | test('throws when options.rng() is too short', () => {
280 | const buffer = new Uint8Array(16);
281 | const rng = () => Uint8Array.of(0); // length = 1
282 | assert.throws(() => {
283 | v7({ rng }, buffer);
284 | });
285 | });
286 |
287 | test('throws RangeError for out-of-range indexes', () => {
288 | const buf15 = new Uint8Array(15);
289 | const buf30 = new Uint8Array(30);
290 | assert.throws(() => v7({}, buf15));
291 | assert.throws(() => v7({}, buf30, -1));
292 | assert.throws(() => v7({}, buf30, 15));
293 | });
294 | });
295 |
--------------------------------------------------------------------------------
/src/test/validate.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import validate from '../validate.js';
4 | import { TESTS } from './test_constants.js';
5 |
6 | describe('validate()', () => {
7 | test('TESTS cases', () => {
8 | for (const { value, expectedValidate } of TESTS) {
9 | assert.strictEqual(
10 | validate(value),
11 | expectedValidate,
12 | `validate(${value}) should be ${expectedValidate}`
13 | );
14 | }
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/test/version.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 | import { describe, test } from 'node:test';
3 | import version from '../version.js';
4 | import { TESTS } from './test_constants.js';
5 |
6 | describe('version()', () => {
7 | test('TESTS cases', () => {
8 | for (const { value, expectedValidate, expectedVersion } of TESTS) {
9 | try {
10 | // @ts-expect-error testing invalid input
11 | const actualVersion = version(value);
12 |
13 | assert.ok(expectedValidate, `version(${value}) should throw`);
14 | assert.strictEqual(actualVersion, expectedVersion);
15 | } catch {
16 | assert.ok(!expectedValidate, `version(${value}) threw unexpectedly`);
17 | }
18 | }
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export type UUIDTypes = string | TBuf;
2 |
3 | export type Version1Options = {
4 | node?: Uint8Array;
5 | clockseq?: number;
6 | random?: Uint8Array;
7 | rng?: () => Uint8Array;
8 | msecs?: number;
9 | nsecs?: number;
10 | _v6?: boolean; // Internal use only!
11 | };
12 |
13 | export type Version4Options = {
14 | random?: Uint8Array;
15 | rng?: () => Uint8Array;
16 | };
17 |
18 | export type Version6Options = Version1Options;
19 |
20 | export type Version7Options = {
21 | random?: Uint8Array;
22 | msecs?: number;
23 | seq?: number;
24 | rng?: () => Uint8Array;
25 | };
26 |
--------------------------------------------------------------------------------
/src/uuid-bin.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'node:assert/strict';
2 |
3 | import v1 from './v1.js';
4 | import v3 from './v3.js';
5 | import v4 from './v4.js';
6 | import v5 from './v5.js';
7 | import v6 from './v6.js';
8 | import v7 from './v7.js';
9 |
10 | function usage() {
11 | console.log('Usage:');
12 | console.log(' uuid');
13 | console.log(' uuid v1');
14 | console.log(' uuid v3 ');
15 | console.log(' uuid v4');
16 | console.log(' uuid v5 ');
17 | console.log(' uuid v6');
18 | console.log(' uuid v7');
19 | console.log(' uuid --help');
20 | console.log(
21 | '\nNote: may be "URL" or "DNS" to use the corresponding UUIDs defined by RFC9562'
22 | );
23 | }
24 |
25 | const args = process.argv.slice(2);
26 |
27 | if (args.indexOf('--help') >= 0) {
28 | usage();
29 | process.exit(0);
30 | }
31 |
32 | const version = args.shift() || 'v4';
33 |
34 | switch (version) {
35 | case 'v1':
36 | console.log(v1());
37 | break;
38 |
39 | case 'v3': {
40 | const name = args.shift();
41 | let namespace = args.shift();
42 |
43 | assert.ok(name != null, 'v3 name not specified');
44 | assert.ok(namespace != null, 'v3 namespace not specified');
45 |
46 | if (namespace === 'URL') {
47 | namespace = v3.URL;
48 | }
49 |
50 | if (namespace === 'DNS') {
51 | namespace = v3.DNS;
52 | }
53 |
54 | console.log(v3(name, namespace));
55 | break;
56 | }
57 |
58 | case 'v4':
59 | console.log(v4());
60 | break;
61 |
62 | case 'v5': {
63 | const name = args.shift();
64 | let namespace = args.shift();
65 |
66 | assert.ok(name != null, 'v5 name not specified');
67 | assert.ok(namespace != null, 'v5 namespace not specified');
68 |
69 | if (namespace === 'URL') {
70 | namespace = v5.URL;
71 | }
72 |
73 | if (namespace === 'DNS') {
74 | namespace = v5.DNS;
75 | }
76 |
77 | console.log(v5(name, namespace));
78 | break;
79 | }
80 |
81 | case 'v6':
82 | console.log(v6());
83 | break;
84 |
85 | case 'v7':
86 | console.log(v7());
87 | break;
88 |
89 | default:
90 | usage();
91 | process.exit(1);
92 | }
93 |
--------------------------------------------------------------------------------
/src/v1.ts:
--------------------------------------------------------------------------------
1 | import rng from './rng.js';
2 | import { unsafeStringify } from './stringify.js';
3 | import { UUIDTypes, Version1Options } from './types.js';
4 |
5 | // **`v1()` - Generate time-based UUID**
6 | //
7 | // Inspired by https://github.com/LiosK/UUID.js
8 | // and http://docs.python.org/library/uuid.html
9 |
10 | type V1State = {
11 | node?: Uint8Array; // node id (47-bit random)
12 | clockseq?: number; // sequence number (14-bit)
13 |
14 | // v1 & v6 timestamps are a pain to deal with. They specify time from the
15 | // Gregorian epoch in 100ns intervals, which requires values with 57+ bits of
16 | // precision. But that's outside the precision of IEEE754 floats (i.e. JS
17 | // numbers). To work around this, we represent them internally using 'msecs'
18 | // (milliseconds since unix epoch) and 'nsecs' (100-nanoseconds offset from
19 | // `msecs`).
20 |
21 | msecs?: number; // timestamp (milliseconds, unix epoch)
22 | nsecs?: number; // timestamp (100-nanoseconds offset from 'msecs')
23 | };
24 |
25 | const _state: V1State = {};
26 |
27 | function v1(options?: Version1Options, buf?: undefined, offset?: number): string;
28 | function v1(
29 | options: Version1Options | undefined,
30 | buf: Buf,
31 | offset?: number
32 | ): Buf;
33 | function v1(
34 | options?: Version1Options,
35 | buf?: TBuf,
36 | offset?: number
37 | ): UUIDTypes {
38 | let bytes: Uint8Array;
39 |
40 | // Extract _v6 flag from options, clearing options if appropriate
41 | const isV6 = options?._v6 ?? false;
42 | if (options) {
43 | const optionsKeys = Object.keys(options);
44 | if (optionsKeys.length === 1 && optionsKeys[0] === '_v6') {
45 | options = undefined;
46 | }
47 | }
48 |
49 | if (options) {
50 | // With options: Make UUID independent of internal state
51 | bytes = v1Bytes(
52 | options.random ?? options.rng?.() ?? rng(),
53 | options.msecs,
54 | options.nsecs,
55 | options.clockseq,
56 | options.node,
57 | buf,
58 | offset
59 | );
60 | } else {
61 | // Without options: Make UUID from internal state
62 | const now = Date.now();
63 | const rnds = rng();
64 |
65 | updateV1State(_state, now, rnds);
66 |
67 | // Geenerate UUID. Note that v6 uses random values for `clockseq` and
68 | // `node`.
69 | //
70 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-5.6-4
71 | bytes = v1Bytes(
72 | rnds,
73 | _state.msecs,
74 | _state.nsecs,
75 | // v6 UUIDs get random `clockseq` and `node` for every UUID
76 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-5.6-4
77 | isV6 ? undefined : _state.clockseq,
78 | isV6 ? undefined : _state.node,
79 | buf,
80 | offset
81 | );
82 | }
83 |
84 | return buf ?? unsafeStringify(bytes);
85 | }
86 |
87 | // (Private!) Do not use. This method is only exported for testing purposes
88 | // and may change without notice.
89 | export function updateV1State(state: V1State, now: number, rnds: Uint8Array) {
90 | state.msecs ??= -Infinity;
91 | state.nsecs ??= 0;
92 |
93 | // Update timestamp
94 | if (now === state.msecs) {
95 | // Same msec-interval = simulate higher clock resolution by bumping `nsecs`
96 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-6.1-2.6
97 | state.nsecs++;
98 |
99 | // Check for `nsecs` overflow (nsecs is capped at 10K intervals / msec)
100 | if (state.nsecs >= 10000) {
101 | // Prior to uuid@11 this would throw an error, however the RFCs allow for
102 | // changing the node in this case. This slightly breaks monotonicity at
103 | // msec granularity, but that's not a significant concern.
104 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-6.1-2.16
105 | state.node = undefined;
106 | state.nsecs = 0;
107 | }
108 | } else if (now > state.msecs) {
109 | // Reset nsec counter when clock advances to a new msec interval
110 | state.nsecs = 0;
111 | } else if (now < state.msecs) {
112 | // Handle clock regression
113 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-6.1-2.7
114 | //
115 | // Note: Unsetting node here causes both it and clockseq to be randomized,
116 | // below.
117 | state.node = undefined;
118 | }
119 |
120 | // Init node and clock sequence (do this after timestamp update which may
121 | // reset the node) https://www.rfc-editor.org/rfc/rfc9562.html#section-5.1-7
122 | //
123 | // Note:
124 | if (!state.node) {
125 | state.node = rnds.slice(10, 16);
126 |
127 | // Set multicast bit
128 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-6.10-3
129 | state.node[0] |= 0x01; // Set multicast bit
130 |
131 | // Clock sequence must be randomized
132 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-5.1-8
133 | state.clockseq = ((rnds[8] << 8) | rnds[9]) & 0x3fff;
134 | }
135 |
136 | state.msecs = now;
137 |
138 | return state;
139 | }
140 |
141 | function v1Bytes(
142 | rnds: Uint8Array,
143 | msecs?: number,
144 | nsecs?: number,
145 | clockseq?: number,
146 | node?: Uint8Array,
147 | buf?: Uint8Array,
148 | offset = 0
149 | ) {
150 | if (rnds.length < 16) {
151 | throw new Error('Random bytes length must be >= 16');
152 | }
153 |
154 | // Defaults
155 | if (!buf) {
156 | buf = new Uint8Array(16);
157 | offset = 0;
158 | } else {
159 | if (offset < 0 || offset + 16 > buf.length) {
160 | throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
161 | }
162 | }
163 |
164 | msecs ??= Date.now();
165 | nsecs ??= 0;
166 | clockseq ??= ((rnds[8] << 8) | rnds[9]) & 0x3fff;
167 | node ??= rnds.slice(10, 16);
168 |
169 | // Offset to Gregorian epoch
170 | // https://www.rfc-editor.org/rfc/rfc9562.html#section-5.1-1
171 | msecs += 12219292800000;
172 |
173 | // `time_low`
174 | const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
175 | buf[offset++] = (tl >>> 24) & 0xff;
176 | buf[offset++] = (tl >>> 16) & 0xff;
177 | buf[offset++] = (tl >>> 8) & 0xff;
178 | buf[offset++] = tl & 0xff;
179 |
180 | // `time_mid`
181 | const tmh = ((msecs / 0x100000000) * 10000) & 0xfffffff;
182 | buf[offset++] = (tmh >>> 8) & 0xff;
183 | buf[offset++] = tmh & 0xff;
184 |
185 | // `time_high_and_version`
186 | buf[offset++] = ((tmh >>> 24) & 0xf) | 0x10; // include version
187 | buf[offset++] = (tmh >>> 16) & 0xff;
188 |
189 | // `clock_seq_hi_and_reserved` | variant
190 | buf[offset++] = (clockseq >>> 8) | 0x80;
191 |
192 | // `clock_seq_low`
193 | buf[offset++] = clockseq & 0xff;
194 |
195 | // `node`
196 | for (let n = 0; n < 6; ++n) {
197 | buf[offset++] = node[n];
198 | }
199 |
200 | return buf;
201 | }
202 |
203 | export default v1;
204 |
--------------------------------------------------------------------------------
/src/v1ToV6.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes } from './types.js';
2 | import parse from './parse.js';
3 | import { unsafeStringify } from './stringify.js';
4 |
5 | /**
6 | * Convert a v1 UUID to a v6 UUID
7 | *
8 | * @param {string|Uint8Array} uuid - The v1 UUID to convert to v6
9 | * @returns {string|Uint8Array} The v6 UUID as the same type as the `uuid` arg
10 | * (string or Uint8Array)
11 | */
12 | export default function v1ToV6(uuid: string): string;
13 | export default function v1ToV6(uuid: Uint8Array): Uint8Array;
14 | export default function v1ToV6(uuid: string | Uint8Array): UUIDTypes {
15 | const v1Bytes = typeof uuid === 'string' ? parse(uuid) : uuid;
16 |
17 | const v6Bytes = _v1ToV6(v1Bytes);
18 |
19 | return typeof uuid === 'string' ? unsafeStringify(v6Bytes) : v6Bytes;
20 | }
21 |
22 | // Do the field transformation needed for v1 -> v6
23 | function _v1ToV6(v1Bytes: Uint8Array) {
24 | return Uint8Array.of(
25 | ((v1Bytes[6] & 0x0f) << 4) | ((v1Bytes[7] >> 4) & 0x0f),
26 | ((v1Bytes[7] & 0x0f) << 4) | ((v1Bytes[4] & 0xf0) >> 4),
27 | ((v1Bytes[4] & 0x0f) << 4) | ((v1Bytes[5] & 0xf0) >> 4),
28 | ((v1Bytes[5] & 0x0f) << 4) | ((v1Bytes[0] & 0xf0) >> 4),
29 |
30 | ((v1Bytes[0] & 0x0f) << 4) | ((v1Bytes[1] & 0xf0) >> 4),
31 | ((v1Bytes[1] & 0x0f) << 4) | ((v1Bytes[2] & 0xf0) >> 4),
32 |
33 | 0x60 | (v1Bytes[2] & 0x0f),
34 | v1Bytes[3],
35 |
36 | v1Bytes[8],
37 | v1Bytes[9],
38 | v1Bytes[10],
39 | v1Bytes[11],
40 | v1Bytes[12],
41 | v1Bytes[13],
42 | v1Bytes[14],
43 | v1Bytes[15]
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/src/v3.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes } from './types.js';
2 | import md5 from './md5.js';
3 | import v35, { DNS, URL } from './v35.js';
4 |
5 | export { DNS, URL } from './v35.js';
6 |
7 | function v3(
8 | value: string | Uint8Array,
9 | namespace: UUIDTypes,
10 | buf?: undefined,
11 | offset?: number
12 | ): string;
13 | function v3(
14 | value: string | Uint8Array,
15 | namespace: UUIDTypes,
16 | buf: TBuf,
17 | offset?: number
18 | ): TBuf;
19 | function v3(
20 | value: string | Uint8Array,
21 | namespace: UUIDTypes,
22 | buf?: TBuf,
23 | offset?: number
24 | ): UUIDTypes {
25 | return v35(0x30, md5, value, namespace, buf, offset);
26 | }
27 |
28 | v3.DNS = DNS;
29 | v3.URL = URL;
30 |
31 | export default v3;
32 |
--------------------------------------------------------------------------------
/src/v35.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes } from './types.js';
2 | import parse from './parse.js';
3 | import { unsafeStringify } from './stringify.js';
4 |
5 | export function stringToBytes(str: string) {
6 | // TODO: Use TextEncoder (see https://stackoverflow.com/a/48762658/109538)
7 | str = unescape(encodeURIComponent(str));
8 |
9 | const bytes = new Uint8Array(str.length);
10 |
11 | for (let i = 0; i < str.length; ++i) {
12 | bytes[i] = str.charCodeAt(i);
13 | }
14 |
15 | return bytes;
16 | }
17 |
18 | export const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
19 | export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
20 |
21 | type HashFunction = (bytes: Uint8Array) => Uint8Array;
22 |
23 | export default function v35(
24 | version: 0x30 | 0x50,
25 | hash: HashFunction,
26 | value: string | Uint8Array,
27 | namespace: UUIDTypes,
28 | buf?: TBuf,
29 | offset?: number
30 | ): UUIDTypes {
31 | const valueBytes: Uint8Array = typeof value === 'string' ? stringToBytes(value) : value;
32 | const namespaceBytes: Uint8Array = typeof namespace === 'string' ? parse(namespace) : namespace;
33 |
34 | if (typeof namespace === 'string') {
35 | namespace = parse(namespace);
36 | }
37 |
38 | if (namespace?.length !== 16) {
39 | throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)');
40 | }
41 |
42 | // Compute hash of namespace and value, Per 4.3
43 | // Future: Use spread syntax when supported on all platforms, e.g. `bytes =
44 | // hashfunc([...namespace, ... value])`
45 | let bytes = new Uint8Array(16 + valueBytes.length);
46 | bytes.set(namespaceBytes);
47 | bytes.set(valueBytes, namespaceBytes.length);
48 | bytes = hash(bytes);
49 |
50 | bytes[6] = (bytes[6] & 0x0f) | version;
51 | bytes[8] = (bytes[8] & 0x3f) | 0x80;
52 |
53 | if (buf) {
54 | offset = offset || 0;
55 |
56 | for (let i = 0; i < 16; ++i) {
57 | buf[offset + i] = bytes[i];
58 | }
59 |
60 | return buf;
61 | }
62 |
63 | return unsafeStringify(bytes);
64 | }
65 |
--------------------------------------------------------------------------------
/src/v4.ts:
--------------------------------------------------------------------------------
1 | import native from './native.js';
2 | import rng from './rng.js';
3 | import { unsafeStringify } from './stringify.js';
4 | import { UUIDTypes, Version4Options } from './types.js';
5 |
6 | function v4(options?: Version4Options, buf?: undefined, offset?: number): string;
7 | function v4(
8 | options: Version4Options | undefined,
9 | buf: TBuf,
10 | offset?: number
11 | ): TBuf;
12 | function v4(
13 | options?: Version4Options,
14 | buf?: TBuf,
15 | offset?: number
16 | ): UUIDTypes {
17 | if (native.randomUUID && !buf && !options) {
18 | return native.randomUUID();
19 | }
20 |
21 | options = options || {};
22 |
23 | const rnds = options.random ?? options.rng?.() ?? rng();
24 | if (rnds.length < 16) {
25 | throw new Error('Random bytes length must be >= 16');
26 | }
27 |
28 | // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
29 | rnds[6] = (rnds[6] & 0x0f) | 0x40;
30 | rnds[8] = (rnds[8] & 0x3f) | 0x80;
31 |
32 | // Copy bytes to buffer, if provided
33 | if (buf) {
34 | offset = offset || 0;
35 | if (offset < 0 || offset + 16 > buf.length) {
36 | throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
37 | }
38 |
39 | for (let i = 0; i < 16; ++i) {
40 | buf[offset + i] = rnds[i];
41 | }
42 |
43 | return buf;
44 | }
45 |
46 | return unsafeStringify(rnds);
47 | }
48 |
49 | export default v4;
50 |
--------------------------------------------------------------------------------
/src/v5.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes } from './types.js';
2 | import sha1 from './sha1.js';
3 | import v35, { DNS, URL } from './v35.js';
4 |
5 | export { DNS, URL } from './v35.js';
6 |
7 | function v5(
8 | value: string | Uint8Array,
9 | namespace: UUIDTypes,
10 | buf?: undefined,
11 | offset?: number
12 | ): string;
13 | function v5(
14 | value: string | Uint8Array,
15 | namespace: UUIDTypes,
16 | buf: TBuf,
17 | offset?: number
18 | ): TBuf;
19 | function v5(
20 | value: string | Uint8Array,
21 | namespace: UUIDTypes,
22 | buf?: TBuf,
23 | offset?: number
24 | ): UUIDTypes {
25 | return v35(0x50, sha1, value, namespace, buf, offset);
26 | }
27 |
28 | v5.DNS = DNS;
29 | v5.URL = URL;
30 |
31 | export default v5;
32 |
--------------------------------------------------------------------------------
/src/v6.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes, Version6Options } from './types.js';
2 | import { unsafeStringify } from './stringify.js';
3 | import v1 from './v1.js';
4 | import v1ToV6 from './v1ToV6.js';
5 |
6 | function v6(options?: Version6Options, buf?: undefined, offset?: number): string;
7 | function v6(
8 | options: Version6Options | undefined,
9 | buf: TBuf,
10 | offset?: number
11 | ): TBuf;
12 | function v6(
13 | options?: Version6Options,
14 | buf?: TBuf,
15 | offset?: number
16 | ): UUIDTypes {
17 | options ??= {};
18 | offset ??= 0;
19 |
20 | // v6 is v1 with different field layout, so we start with a v1 UUID, albeit
21 | // with slightly different behavior around how the clock_seq and node fields
22 | // are randomized, which is why we call v1 with _v6: true.
23 | let bytes = v1({ ...options, _v6: true }, new Uint8Array(16));
24 |
25 | // Reorder the fields to v6 layout.
26 | bytes = v1ToV6(bytes);
27 |
28 | // Return as a byte array if requested
29 | if (buf) {
30 | for (let i = 0; i < 16; i++) {
31 | buf[offset + i] = bytes[i];
32 | }
33 | return buf;
34 | }
35 |
36 | return unsafeStringify(bytes);
37 | }
38 |
39 | export default v6;
40 |
--------------------------------------------------------------------------------
/src/v6ToV1.ts:
--------------------------------------------------------------------------------
1 | import { UUIDTypes } from './types.js';
2 | import parse from './parse.js';
3 | import { unsafeStringify } from './stringify.js';
4 |
5 | /**
6 | * Convert a v6 UUID to a v1 UUID
7 | *
8 | * @param {string|Uint8Array} uuid - The v6 UUID to convert to v6
9 | * @returns {string|Uint8Array} The v1 UUID as the same type as the `uuid` arg
10 | * (string or Uint8Array)
11 | */
12 | export default function v6ToV1(uuid: string): string;
13 | export default function v6ToV1(uuid: Uint8Array): Uint8Array;
14 | export default function v6ToV1(uuid: UUIDTypes): UUIDTypes {
15 | const v6Bytes = typeof uuid === 'string' ? parse(uuid) : uuid;
16 |
17 | const v1Bytes = _v6ToV1(v6Bytes);
18 |
19 | return typeof uuid === 'string' ? unsafeStringify(v1Bytes) : v1Bytes;
20 | }
21 |
22 | // Do the field transformation needed for v6 -> v1
23 | function _v6ToV1(v6Bytes: Uint8Array) {
24 | return Uint8Array.of(
25 | ((v6Bytes[3] & 0x0f) << 4) | ((v6Bytes[4] >> 4) & 0x0f),
26 | ((v6Bytes[4] & 0x0f) << 4) | ((v6Bytes[5] & 0xf0) >> 4),
27 | ((v6Bytes[5] & 0x0f) << 4) | (v6Bytes[6] & 0x0f),
28 | v6Bytes[7],
29 |
30 | ((v6Bytes[1] & 0x0f) << 4) | ((v6Bytes[2] & 0xf0) >> 4),
31 | ((v6Bytes[2] & 0x0f) << 4) | ((v6Bytes[3] & 0xf0) >> 4),
32 |
33 | 0x10 | ((v6Bytes[0] & 0xf0) >> 4),
34 | ((v6Bytes[0] & 0x0f) << 4) | ((v6Bytes[1] & 0xf0) >> 4),
35 |
36 | v6Bytes[8],
37 | v6Bytes[9],
38 | v6Bytes[10],
39 | v6Bytes[11],
40 | v6Bytes[12],
41 | v6Bytes[13],
42 | v6Bytes[14],
43 | v6Bytes[15]
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/src/v7.ts:
--------------------------------------------------------------------------------
1 | import rng from './rng.js';
2 | import { unsafeStringify } from './stringify.js';
3 | import { UUIDTypes, Version7Options } from './types.js';
4 |
5 | type V7State = {
6 | msecs?: number; // time, milliseconds
7 | seq?: number; // sequence number (32-bits)
8 | };
9 |
10 | const _state: V7State = {};
11 |
12 | function v7(options?: Version7Options, buf?: undefined, offset?: number): string;
13 | function v7(
14 | options: Version7Options | undefined,
15 | buf: TBuf,
16 | offset?: number
17 | ): TBuf;
18 | function v7(
19 | options?: Version7Options,
20 | buf?: TBuf,
21 | offset?: number
22 | ): UUIDTypes {
23 | let bytes: Uint8Array;
24 |
25 | if (options) {
26 | // With options: Make UUID independent of internal state
27 | bytes = v7Bytes(
28 | options.random ?? options.rng?.() ?? rng(),
29 | options.msecs,
30 | options.seq,
31 | buf,
32 | offset
33 | );
34 | } else {
35 | // No options: Use internal state
36 | const now = Date.now();
37 | const rnds = rng();
38 |
39 | updateV7State(_state, now, rnds);
40 |
41 | bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
42 | }
43 |
44 | return buf ?? unsafeStringify(bytes);
45 | }
46 |
47 | // (Private!) Do not use. This method is only exported for testing purposes
48 | // and may change without notice.
49 | export function updateV7State(state: V7State, now: number, rnds: Uint8Array) {
50 | state.msecs ??= -Infinity;
51 | state.seq ??= 0;
52 |
53 | if (now > state.msecs) {
54 | // Time has moved on! Pick a new random sequence number
55 | state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];
56 | state.msecs = now;
57 | } else {
58 | // Bump sequence counter w/ 32-bit rollover
59 | state.seq = (state.seq + 1) | 0;
60 |
61 | // In case of rollover, bump timestamp to preserve monotonicity. This is
62 | // allowed by the RFC and should self-correct as the system clock catches
63 | // up. See https://www.rfc-editor.org/rfc/rfc9562.html#section-6.2-9.4
64 | if (state.seq === 0) {
65 | state.msecs++;
66 | }
67 | }
68 |
69 | return state;
70 | }
71 |
72 | function v7Bytes(rnds: Uint8Array, msecs?: number, seq?: number, buf?: Uint8Array, offset = 0) {
73 | if (rnds.length < 16) {
74 | throw new Error('Random bytes length must be >= 16');
75 | }
76 |
77 | if (!buf) {
78 | buf = new Uint8Array(16);
79 | offset = 0;
80 | } else {
81 | if (offset < 0 || offset + 16 > buf.length) {
82 | throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
83 | }
84 | }
85 |
86 | // Defaults
87 | msecs ??= Date.now();
88 | seq ??= ((rnds[6] * 0x7f) << 24) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9];
89 |
90 | // byte 0-5: timestamp (48 bits)
91 | buf[offset++] = (msecs / 0x10000000000) & 0xff;
92 | buf[offset++] = (msecs / 0x100000000) & 0xff;
93 | buf[offset++] = (msecs / 0x1000000) & 0xff;
94 | buf[offset++] = (msecs / 0x10000) & 0xff;
95 | buf[offset++] = (msecs / 0x100) & 0xff;
96 | buf[offset++] = msecs & 0xff;
97 |
98 | // byte 6: `version` (4 bits) | sequence bits 28-31 (4 bits)
99 | buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f);
100 |
101 | // byte 7: sequence bits 20-27 (8 bits)
102 | buf[offset++] = (seq >>> 20) & 0xff;
103 |
104 | // byte 8: `variant` (2 bits) | sequence bits 14-19 (6 bits)
105 | buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f);
106 |
107 | // byte 9: sequence bits 6-13 (8 bits)
108 | buf[offset++] = (seq >>> 6) & 0xff;
109 |
110 | // byte 10: sequence bits 0-5 (6 bits) | random (2 bits)
111 | buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03);
112 |
113 | // bytes 11-15: random (40 bits)
114 | buf[offset++] = rnds[11];
115 | buf[offset++] = rnds[12];
116 | buf[offset++] = rnds[13];
117 | buf[offset++] = rnds[14];
118 | buf[offset++] = rnds[15];
119 |
120 | return buf;
121 | }
122 |
123 | export default v7;
124 |
--------------------------------------------------------------------------------
/src/validate.ts:
--------------------------------------------------------------------------------
1 | import REGEX from './regex.js';
2 |
3 | function validate(uuid: unknown) {
4 | return typeof uuid === 'string' && REGEX.test(uuid);
5 | }
6 |
7 | export default validate;
8 |
--------------------------------------------------------------------------------
/src/version.ts:
--------------------------------------------------------------------------------
1 | import validate from './validate.js';
2 |
3 | function version(uuid: string) {
4 | if (!validate(uuid)) {
5 | throw TypeError('Invalid UUID');
6 | }
7 |
8 | return parseInt(uuid.slice(14, 15), 16);
9 | }
10 |
11 | export default version;
12 |
--------------------------------------------------------------------------------
/test/browser/browser.spec.js:
--------------------------------------------------------------------------------
1 | /* global browser:false, $:false, $$:false */
2 |
3 | const v1Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
4 | const v4Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
5 | const v6Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-6[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
6 | const v7Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-7[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
7 |
8 | const V1_ID = 'f1207660-21d2-11ef-8c4f-419efbd44d48';
9 | const V6_ID = '1ef21d2f-1207-6660-8c4f-419efbd44d48';
10 |
11 | const v1 = (result) => expect(result).toMatch(v1Regex);
12 | const v4 = (result) => expect(result).toMatch(v4Regex);
13 | const v6 = (result) => expect(result).toMatch(v6Regex);
14 | const v7 = (result) => expect(result).toMatch(v7Regex);
15 | const v3dns = (result) => expect(result).toBe('9125a8dc-52ee-365b-a5aa-81b0b3681cf6');
16 | const v3url = (result) => expect(result).toBe('c6235813-3ba4-3801-ae84-e0a6ebb7d138');
17 | const v3custom = (result) => expect(result).toBe('f5a52d34-dcd7-30f7-b581-0112fab43d0c');
18 | const v5dns = (result) => expect(result).toBe('fdda765f-fc57-5604-a269-52a7df8164ec');
19 | const v5url = (result) => expect(result).toBe('3bbcee75-cecc-5b56-8031-b6641c1ed1f1');
20 | const v5custom = (result) => expect(result).toBe('c49c5142-4d9a-5940-a926-612ede0ec632');
21 |
22 | const v1ToV6 = (result) => expect(result).toBe(V6_ID);
23 | const v6ToV1 = (result) => expect(result).toBe(V1_ID);
24 |
25 | const nil = (result) => expect(result).toBe('00000000-0000-0000-0000-000000000000');
26 | const max = (result) => expect(result).toBe('ffffffff-ffff-ffff-ffff-ffffffffffff');
27 | const parse = (result) =>
28 | expect(result).toEqual('85,35,141,21,201,38,69,152,180,157,207,78,145,59,161,60');
29 | const stringify = (result) => expect(result).toBe('55238d15-c926-4598-b49d-cf4e913ba13c');
30 | const validate = (result) => expect(result).toBe('true');
31 | const version = (result) => expect(result).toBe('4');
32 |
33 | const expectations = {
34 | 'uuidv1()': v1,
35 | 'uuidv4()': v4,
36 | 'uuidv7()': v7,
37 | 'uuidv3() DNS': v3dns,
38 | 'uuidv3() URL': v3url,
39 | 'uuidv3() MY_NAMESPACE': v3custom,
40 | 'uuidv5() DNS': v5dns,
41 | 'uuidv5() URL': v5url,
42 | 'uuidv5() MY_NAMESPACE': v5custom,
43 | 'uuidv6()': v6,
44 |
45 | 'uuidv1ToV6()': v1ToV6,
46 | 'uuidv6ToV1()': v6ToV1,
47 |
48 | NIL_UUID: nil,
49 | MAX_UUID: max,
50 | 'uuidParse()': parse,
51 | 'uuidStringify()': stringify,
52 | 'uuidValidate()': validate,
53 | 'uuidVersion()': version,
54 |
55 | 'uuid.v1()': v1,
56 | 'uuid.v4()': v4,
57 | 'uuid.v7()': v7,
58 | 'uuid.v3() DNS': v3dns,
59 | 'uuid.v3() URL': v3url,
60 | 'uuid.v3() MY_NAMESPACE': v3custom,
61 | 'uuid.v5() DNS': v5dns,
62 | 'uuid.v5() URL': v5url,
63 | 'uuid.v5() MY_NAMESPACE': v5custom,
64 | 'uuid.v6()': v6,
65 |
66 | 'uuid.v1ToV6()': v1ToV6,
67 | 'uuid.v6ToV1()': v6ToV1,
68 |
69 | 'uuid.NIL': nil,
70 | 'uuid.MAX': max,
71 | 'uuid.parse()': parse,
72 | 'uuid.stringify()': stringify,
73 | 'uuid.validate()': validate,
74 | 'uuid.version()': version,
75 | };
76 | const expectationTitles = Object.keys(expectations);
77 |
78 | const PORT = 9000;
79 |
80 | describe('BrowserStack Local Testing', () => {
81 | async function testExpectations(path, titleFilter) {
82 | const url = `http://127.0.0.1:${PORT}/${path}`;
83 | await browser.url(url);
84 |
85 | await browser.waitUntil(async () => $('#done').isExisting(), 30000);
86 |
87 | const elements = await $$('.test_result');
88 |
89 | // Unfortunately the WebDriver API is not thread safe and we cannot use Promise.all() to
90 | // query it in parallel:
91 | // https://github.com/SeleniumHQ/selenium/issues/422#issuecomment-90629726
92 | const titles = [];
93 |
94 | for (let i = 0; i < elements.length; ++i) {
95 | const element = elements[i];
96 | const titleEl = await element.$('dt');
97 | const title = await titleEl.getText();
98 | const resultEl = await element.$('dd');
99 | const result = await resultEl.getText();
100 |
101 | if (!expectations[title]) {
102 | throw new Error(`Unexpected title: ${title}`);
103 | }
104 |
105 | expectations[title](result);
106 | titles.push(title);
107 | }
108 |
109 | // Confirm the expected titles are all present
110 | const expectedTitles = expectationTitles.filter(titleFilter);
111 | expect(titles.length).toEqual(expectedTitles.length);
112 | expect(titles.sort()).toEqual(expectedTitles.sort());
113 | }
114 |
115 | describe('webpack', () => {
116 | it('renders all', async () => testExpectations('browser-webpack/example-all.html', () => true));
117 |
118 | it('renders v1 only', async () =>
119 | testExpectations('browser-webpack/example-v1.html', (title) => title.includes('uuidv1()')));
120 |
121 | it('renders v4 only', async () =>
122 | testExpectations('browser-webpack/example-v4.html', (title) => title.includes('uuidv4()')));
123 | });
124 |
125 | describe('rollup', () => {
126 | it('renders all', async () => testExpectations('browser-rollup/example-all.html', () => true));
127 |
128 | it('renders v1 only', async () =>
129 | testExpectations('browser-rollup/example-v1.html', (title) => title.includes('uuidv1()')));
130 |
131 | it('renders v4 only', async () =>
132 | testExpectations('browser-rollup/example-v4.html', (title) => title.includes('uuidv4(')));
133 | });
134 | });
135 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "removeComments": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "target": "ES2022"
8 | },
9 | "exclude": ["dist", "examples"]
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.cjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "CommonJS",
5 | "moduleResolution": "Node",
6 | "outDir": "./dist/cjs"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.esm.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "NodeNext",
5 | "moduleResolution": "NodeNext",
6 | "outDir": "./dist/esm"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | // NOTE: Do not extend or alter this file. This file is only here to point
2 | // VSCode to the correct config file. (There's no way of configuring the path
3 | // VSCode uses for the tsconfig.json file)
4 | { "extends": "./tsconfig.esm.json" }
5 |
--------------------------------------------------------------------------------
/wdio.conf.js:
--------------------------------------------------------------------------------
1 | const PORT = 9000;
2 | const PROJECT = process.env.GITHUB_REPOSITORY || 'node-uuid';
3 | const GITHUB_SHA = process.env.GITHUB_SHA || '';
4 | const GITHUB_REF = process.env.GITHUB_REF || '';
5 | const BUILD = GITHUB_SHA || GITHUB_REF ? `${GITHUB_REF} ${GITHUB_SHA}` : 'manual build';
6 |
7 | const commonCapabilities = {
8 | projectName: PROJECT,
9 | buildName: BUILD,
10 | sessionName: 'browser test',
11 | resolution: '1024x768',
12 | };
13 |
14 | const capabilities = [
15 | // Chrome Latest
16 | {
17 | browserName: 'Chrome',
18 | browserVersion: 'latest',
19 |
20 | 'bstack:options': {
21 | ...commonCapabilities,
22 | os: 'Windows',
23 | osVersion: '11',
24 | },
25 | },
26 |
27 | // Firefox Latest
28 | {
29 | browserName: 'Firefox',
30 | browserVersion: 'latest',
31 |
32 | 'bstack:options': {
33 | ...commonCapabilities,
34 | os: 'Windows',
35 | osVersion: '11',
36 | },
37 | },
38 |
39 | // Edge Latest
40 | {
41 | browserName: 'Edge',
42 | browserVersion: 'latest',
43 |
44 | 'bstack:options': {
45 | ...commonCapabilities,
46 | os: 'Windows',
47 | osVersion: '11',
48 | },
49 | },
50 |
51 | // Safari Latest
52 | {
53 | browserName: 'Safari',
54 | browserVersion: 'latest',
55 |
56 | 'bstack:options': {
57 | ...commonCapabilities,
58 | os: 'OS X',
59 | osVersion: 'Monterey',
60 | },
61 | },
62 | ];
63 |
64 | export const config = {
65 | specs: ['./test/browser/browser.spec.js'],
66 |
67 | user: process.env.BROWSERSTACK_USER,
68 | key: process.env.BROWSERSTACK_ACCESS_KEY,
69 |
70 | services: [
71 | [
72 | 'static-server',
73 | {
74 | folders: [{ mount: '/', path: './examples' }],
75 | port: PORT,
76 | },
77 | ],
78 | [
79 | 'browserstack',
80 | {
81 | browserstackLocal: true,
82 | },
83 | ],
84 | ],
85 |
86 | runner: 'local',
87 | maxInstances: 5,
88 |
89 | capabilities,
90 |
91 | logLevel: 'warn',
92 | bail: 1,
93 | waitforTimeout: 10000,
94 | connectionRetryTimeout: 90000,
95 | connectionRetryCount: 3,
96 | framework: 'jasmine',
97 | jasmineOpts: {
98 | defaultTimeoutInterval: 120000,
99 | },
100 | reporters: ['spec'],
101 | };
102 |
--------------------------------------------------------------------------------