
# Installation

> Install unsecure with any package manager, or import a single module straight from a CDN.

`unsecure` is published to npm as [`unsecure`](https://npmx.dev/package/unsecure).

## Install

<!-- automd:pm-i -->
<!-- /automd -->

Or let [`nypm`](https://github.com/unjs/nypm) detect the package manager for you:

```sh
npx nypm install unsecure
```

## Requirements

- **Node.js 22.13 or later on the 22 line, or 24 and later.** Any other runtime works as long as the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is available as a global: Bun, Deno, Cloudflare Workers, browsers.
- **ESM only.** The package ships pure ECMAScript modules.
- **Zero runtime dependencies.**

The only global the library touches is `crypto`: `crypto.subtle` and `crypto.getRandomValues`.

## Subpaths and the barrel

Every module is published twice: once inside the barrel at `unsecure`, and once as its own entry point at `unsecure/<name>`. Both hold the same code.

```ts
// Barrel — one import site, everything available
import { hash, uuidv7, totp } from "unsecure";

// Subpath — one module per import
import { hash } from "unsecure/hash";
import { uuidv7 } from "unsecure/uuid";
import { totp } from "unsecure/otp";
```

Which one to use:

| Situation                                               | Import from                                                                                  |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| A bundler (Vite, webpack, Rollup, esbuild, Bun)         | Either. The package is `sideEffects: false`, so the barrel tree-shakes down to what you use. |
| A CDN, an import map, or a browser without a build step | The subpath. A network import of the barrel downloads every module.                          |
| You want the import to say which module it came from    | The subpath.                                                                                 |

The full list of entry points:

`unsecure`, `unsecure/argon2`, `unsecure/compare`, `unsecure/entropy`, `unsecure/errors`, `unsecure/generate`, `unsecure/hash`, `unsecure/hkdf`, `unsecure/hmac`, `unsecure/otp`, `unsecure/random`, `unsecure/sanitize`, `unsecure/utils`, `unsecure/uuid`.

## From a CDN

Each subpath is its own bundle, so the browser downloads only the module named in the URL.

```ts
import { uuidv7, createUUIDv7Generator } from "https://esm.sh/unsecure/uuid";
import { hkdf } from "https://esm.sh/unsecure/hkdf";
import { argon2Hash, argon2Verify } from "https://esm.sh/unsecure/argon2";
import { totp, generateOTPSecret } from "https://esm.sh/unsecure/otp";
import { Base64, Base32 } from "https://esm.sh/unsecure/utils";
```

::warning
Importing `https://esm.sh/unsecure` — the barrel — over a CDN pulls in every module, Argon2 included. On a page that only needs UUIDs, that is the whole library for one function. Name the subpath.
::

Pin a version in production, the same as any other CDN import:

```ts
import { uuidv7 } from "https://esm.sh/unsecure@0.3.0/uuid";
```

## Types

Types ship with the package; there is no `@types/unsecure`. Two type names show up across the API:

- `BytesSource` — anything the library will read as bytes: a `Uint8Array`, any other typed array, a `DataView`, an `ArrayBuffer`, or a view backed by a `SharedArrayBuffer`. Anything else is [`INVALID_TYPE`](/safety/errors).
- `DigestReturnAs` — how `hash`, `hmac`, `hkdf` and `argon2` hand their bytes back: `"hex"`, `"base64"` (alias `"b64"`), `"base64url"` (alias `"b64url"`), or `"uint8array"` (alias `"bytes"`).
- `DecodeReturnAs` — the narrower set the codecs use when decoding: `"string"`, `"uint8array"` (alias `"bytes"`).
