Skip to content
/ atob Public

Performant platform-agnostic ponyfills for `atob` and `btoa`.

License

Notifications You must be signed in to change notification settings

nberlette/atob

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@nick/atob

Lightweight, dependency-free, portable ponyfills for atob and btoa.


Install

deno add jsr:@nick/atob
pnpm add jsr:@nick/atob
yarn add jsr:@nick/atob
bunx jsr add @nick/atob
npx -y jsr add @nick/atob

Usage

This package provides ponyfill exports for atob and btoa, as well as a ./shim entrypoint that will automatically polyfill the global scope with atob and/or btoa if they are not already supported.

import { atob, btoa } from "@nick/atob";
import assert from "node:assert";

const datauri = `data:image/svg+xml;base64,${btoa("<svg>...</svg>")}`;
const base64 = datauri.split(",")[1]!;

const decoded = atob(base64); // "<svg>...</svg>"
assert.strictEqual(decoded, "<svg>...</svg>"); // OK

While the primary focus of this package is providing a ponyfill for atob and btoa, some users might need a polyfill instead.

Therefore, I've also provided an automatic shim module that gracefully installs these functions on an as-needed basis, as well as a manual install module that allows you to choose when and if you want it to mutate the global scope.

Shim (automatic)

import "@nick/atob/shim"; // side-effect import

const bytes = "data:application/wasm;base64,AGFzbQEAAAABOwpgAn9/AX...";

const buf = Uint8Array.from(atob(bytes.split(",")[1]!), (b) => b.charCodeAt(0));

const module = new WebAssembly.Module(buf);
const instance = new WebAssembly.Instance(module);

Install (manual)

If you need explicit control over the polyfilling, install() can be used to gracefully install the functions on-demand.

import { install } from "@nick/atob/install";
import assert from "node:assert";

if (typeof atob !== "function" || typeof btoa !== "function") {
  install(); // ta da!
}

assert.strictEqual(btoa("hello world"), "aGVsbG8gd29ybGQ="); // OK
assert.strictEqual(atob("aGVsbG8gd29ybGQ="), "hello world"); // OK

Note

This is used internally by the ./shim entrypoint.


API

atob

Decodes a Base64-encoded string into a decoded string.

Signature

function atob(data: string): string;
Params

data The Base64-encoded string to decode.

Return

A decoded string.

Example

import { atob } from "@nick/atob";
import assert from "node:assert";

const encoded = "aGVsbG8gd29ybGQ=";
const decoded = atob(encoded);

assert.strictEqual(decoded, "hello world"); // OK

References


btoa

Encodes a string into Base64.

Signature

function btoa(data: string): string;
Params

data The string to encode.

Return

A Base64-encoded string.

Example

import { btoa } from "@nick/atob";
import assert from "node:assert";

const data = "hello world";
const encoded = btoa(data);

assert.strictEqual(encoded, "aGVsbG8gd29ybGQ=");

References


install

Gracefully polyfills the global atob and btoa functions if they are not already present in the environment.

Signature

function install(): Result;
Return
  • On success, returns a Success object containing the installed functions.
  • If the functions are already defined, returns a Skipped result.
  • If the installation fails, returns a Failure result with the error.

Associated Types

Success<T>

Represents a successful polyfill installation

interface Success<T> {
  readonly type: "success";
  readonly data: T;
}
Skipped

Indicates that the installation was skipped because atob and btoa are already present. If available, the info property will contain extra context about which functions were already defined and thus skipped.

interface Skipped {
  readonly type: "skipped";
  readonly info?: string;
}
Failure

Represents a failed installation with an error.

interface Failure {
  readonly type: "failure";
  readonly error: unknown;
}
Data

Contains references to the installed polyfill functions. This is the type of the data property within a Success result returned by calling install(). If only one function was installed, it will be the only one present in the data payload. Otherwise, both of the polyfilled functions will be referenced.

type Data =
  | { readonly atob: typeof atob }
  | { readonly btoa: typeof btoa }
  | { readonly atob: typeof atob; readonly btoa: typeof btoa };
Result

Represents the union of all possible results of the installation process, which are each documented in the sections above. This is a discriminated union type; check against the type property to determine which variant you have and allow TypeScript to narrow the type accordingly.

type Result = Success<Data> | Skipped | Failure;

Example

import { install } from "@nick/atob/install";
import assert from "node:assert";

if (typeof atob !== "function" || typeof btoa !== "function") {
  const result = install();
  if (result.type === "success") {
    console.log("atob and btoa installed successfully.");
  } else if (result.type === "skipped") {
    console.log("atob and btoa already installed.");
  } else {
    console.error("Failed to install atob and btoa:", result.error);
  }
}

assert.ok(typeof btoa === "function"); // OK
assert.strictEqual(btoa("hello world"), "aGVsbG8gd29ybGQ=");

assert.ok(typeof atob === "function"); // OK
assert.strictEqual(atob("aGVsbG8gd29ybGQ="), "hello world");

Contributions are always welcome! Before submitting a pull request, I kindly ask that you first open an issue and start a discussion regarding the feature or bug you would like to address. This helps contributions align with the goals and scope of the project, ensuring a smoother integration process.

For additional details, please refer to the contributing guidelines. Thanks!


MIT © Nicholas Berlette. All rights reserved.

github · issues · docs · contributing

About

Performant platform-agnostic ponyfills for `atob` and `btoa`.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published