npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@majikah/majik-bytes

v1.0.0

Published

MajikBytes is a TypeScript utility for lossless byte conversion and portable data encoding. It preserves source types and encodes strings, JSON, binary data, Files, numbers, BigInts, and booleans as PNG, TXT, or JSON.

Readme

MajikBytes

Developed by Zelijah GitHub Sponsors

MajikBytes is a TypeScript utility for lossless conversion between JavaScript values, raw bytes, and portable media representations.

It can wrap strings, JSON, binary data, files, numbers, BigInts, and booleans into a versioned byte representation that preserves the original source type. The payload can then be serialised as:

  • PNG
  • TXT
  • JSON

MajikBytes is designed around deterministic binary processing, explicit metadata, and integrity verification.

npm npm downloads License TypeScript



Overview

What is MajikBytes?

A MajikBytes instance is a structured representation of a value backed by a prefixed Uint8Array.

The prefix stores:

  • the original source type;
  • the payload format version;
  • filename and MIME type metadata for File values.

The raw payload follows the prefix.

This allows MajikBytes to restore a value without requiring the caller to remember which type was originally supplied.

const value = await MajikBytes.create({
  message: "Hello, Majikah!",
  count: 42,
});

const restored = await value.restore();

The restored value retains its original logical type.


Supported Source Types

MajikBytes currently supports:

| Source type | Restoration | | ------------- | ------------------ | | string | toString() | | json | toJSONValue<T>() | | uint8array | toUint8Array() | | arraybuffer | toArrayBuffer() | | blob | toBlob() | | file | toFile() | | number | toNumber() | | bigint | toBigInt() | | boolean | toBoolean() |

The original type can also be inspected with the corresponding is*() type guards.


Architecture

1. Versioned Type Prefix

Every MajikBytes payload begins with a compact prefix:

| Field | Byte/Description | | ------- | --------------------- | | Byte 0 | Source type tag | | Byte 1 | Prefix format version | | Payload | Raw data |

For File values, the prefix additionally contains the UTF-8 encoded filename and MIME type.

The current source-type tags are stable serialized values:

  • 0x00 → string
  • 0x01 → json
  • 0x02 → uint8array
  • 0x03 → arraybuffer
  • 0x04 → blob
  • 0x05 → file
  • 0x06 → number
  • 0x07 → bigint
  • 0x08 → boolean

The prefix format is versioned so future structural changes can be introduced without silently changing the meaning of existing payloads.


2. Lossless PNG Encoding

MajikBytes stores its prefixed payload in standard RGBA PNG pixel data.

Three payload bytes are stored per pixel:

  • R = byte 0
  • G = byte 1
  • B = byte 2
  • A = 255

The alpha channel is always opaque.

This keeps the encoded pixel representation deterministic and prevents alpha premultiplication from becoming part of the payload representation.

PNG structure

The generated PNG contains:

┌──────────────────────────┐
│ PNG signature            │
├──────────────────────────┤
│ IHDR                     │
├──────────────────────────┤
│ IDAT                     │
│                          │
│   data rows              │
│   ───────────────        │
│   packed payload bytes   │
│                          │
│   sentinel row           │
│                          │
│   hash row               │
├──────────────────────────┤
│ IEND                     │
└──────────────────────────┘

PNG scanlines are stored without a PNG filter (filter type 0) and compressed using raw DEFLATE before being wrapped in a zlib stream for the IDAT chunk.


3. Sentinel Row

PNG images are rectangular, so the payload may not completely fill the final data row.

MajikBytes appends a dedicated sentinel row after the payload rows.

The first pixel of the sentinel row stores the exact prefixed payload length as a 24-bit big-endian value:

R = length >> 16

G = length >> 8

B = length

A = 255

All remaining pixels in the sentinel row are zero-valued in RGB.

This allows the decoder to recover the exact payload length without relying on trailing zero padding.


4. SHA-3-512 Integrity Hash

MajikBytes computes a complete prefixed payload SHA-3-512 digest.

The resulting 64-byte digest is stored in the final PNG row.

During decoding:

  1. the payload length is recovered from the sentinel row;
  2. the payload is extracted;
  3. SHA-3-512 is recomputed;
  4. the computed digest is compared with the stored digest using a constant-time comparison.

A mismatch causes decoding to fail.

The digest provides integrity verification and corruption detection. It does not provide authentication or prove who created the payload.


PNG Decoding

Direct Binary Decoding

MajikBytes previously relied on browser image APIs such as:

createImageBitmap()

OffscreenCanvas

CanvasRenderingContext2D

for PNG decoding.

The PNG decoder now uses fast-png directly.

PNG Blob

   │

   ▼

ArrayBuffer

   │

   ▼

fast-png

   │

   ▼

RGBA Uint8Array

This avoids the browser graphics pipeline entirely during MajikBytes PNG decoding.

Why this changed

Browser privacy and anti-fingerprinting protections can alter or restrict behavior around graphics APIs. In particular, Canvas/ImageBitmap-based decoding caused compatibility problems in privacy-focused environments such as Brave.

Direct binary PNG decoding avoids that dependency and gives MajikBytes a deterministic byte-oriented decoding path.

The decoder therefore no longer needs Canvas or ImageBitmap just to recover the embedded bytes.


Overview of the Data Flow

flowchart TD
    A["JavaScript value"] --> B["MajikBytes.create()"]
    B --> C["Type normalization"]
    C --> D["Versioned prefix"]
    D --> E["Raw prefixed bytes"]

    E --> F["PNG"]
    E --> G["TXT"]
    E --> H["JSON"]

    F --> I["PNG binary"]
    G --> J["Base64 + hash"]
    H --> K["Base64 + length"]

    I --> L["fast-png"]
    L --> M["RGBA bytes"]
    M --> N["Sentinel + hash verification"]

    N --> O["Prefix decoding"]
    O --> P["Original value"]

Features

  • Lossless byte preservation — raw payload bytes are preserved without lossy image processing.
  • Multiple source types — supports strings, JSON, binary data, files, numbers, BigInts, and booleans.
  • Automatic type restoration — recover the original logical value without manually tracking its type.
  • PNG serialisation — embeds payload bytes inside a standard RGBA PNG.
  • Direct PNG decoding — uses fast-png rather than Canvas/ImageBitmap-based decoding.
  • Browser privacy friendly — avoids Canvas decoding paths that can trigger anti-fingerprinting behavior.
  • SHA-3-512 integrity verification — detects corruption or modifications to the encoded payload.
  • Versioned payload format — prefix format changes can be versioned explicitly.
  • File metadata preservation — original filename and MIME type are retained for File values.
  • Portable TXT representation — Base64 payload with an integrity digest.
  • JSON representation — Base64 payload with an explicit byte-length check.
  • TypeScript-first API — strongly typed source identifiers, restoration methods, and validation results.
  • Apache-2.0 licensed — suitable for personal and commercial use.

Installation

npm install @majikah/majik-bytes

Quick Start

Create and encode a value

import { MajikBytes } from "@majikah/majik-bytes";

const originalData = {
  text: "Hi there!",
  id: 42,
};

const majikBytes = await MajikBytes.create(originalData);
const pngBlob = await majikBytes.toPNG();

pngBlob is a standard image/png Blob and can be uploaded, stored, or downloaded normally.


Decode and restore

const decoded = await MajikBytes.fromPNG(pngBlob);

if (decoded.isJSON()) {
  const data = decoded.toJSONValue<{
    text: string;
    id: number;
  }>();

  console.log(data.text);
  // Hi there!
}

Or restore without explicitly knowing the original type:

const value = await decoded.restore();

console.log(value);

API Reference

Factory Methods

MajikBytes.create(input: unknown)

Creates a MajikBytes instance from a supported JavaScript value.

const bytes = await MajikBytes.create("Hello");

Returns

Promise<MajikBytes>

MajikBytes.fromJSON(json: unknown)

Restores a MajikBytes instance from its JSON representation.

const restored = MajikBytes.fromJSON({
  data: "...",
  length: 42,
});

Returns

MajikBytes

Throws MajikBytesError when the structure or declared payload length is invalid.


PNG

MajikBytes.toPNG()

Encodes the prefixed payload into a lossless PNG.

const png = await majikBytes.toPNG();

Returns

Promise<Blob>

The resulting Blob uses:

image/png

MajikBytes.fromPNG(blob: Blob)

Decodes a MajikBytes PNG directly from its binary representation.

const bytes = await MajikBytes.fromPNG(blob);

The decoder:

  1. decodes the PNG using fast-png;
  2. locates the sentinel row;
  3. recovers the exact payload length;
  4. extracts the prefixed payload;
  5. verifies the SHA-3-512 digest;
  6. decodes the source-type prefix.

Returns

Promise<MajikBytes>

Throws MajikBytesError when the PNG is malformed, the sentinel cannot be located, or the integrity digest does not match.


TXT

majikBytes.toTXT()

Serialises the prefixed payload as a plain-text representation containing:

Line 1 → MAJIKBYTES:v{version}

Line 2 → Base64 encoded prefixed payload

Line 3 → SHA-3-512 digest as hexadecimal
const txt = await majikBytes.toTXT();

Returns

Promise<Blob>

with:

text/plain

MajikBytes.fromTXT(blob: Blob)

Restores a MajikBytes instance from a TXT representation created by toTXT().

const bytes = await MajikBytes.fromTXT(blob);

The payload digest is verified before the instance is constructed.


Type Restoration

MajikBytes provides explicit restoration methods for each supported source type.

| Method | Return type | Source type | | ------------------ | ------------------ | ---------------------- | | toString() | string | string | | toJSONValue<T>() | T | json | | toUint8Array() | Uint8Array | uint8array | | toArrayBuffer() | ArrayBuffer | arraybuffer | | toBlob() | Blob | blob | | toFile() | File | file | | toNumber() | number | number | | toBigInt() | bigint | bigint | | toBoolean() | boolean | boolean | | restore() | Promise<unknown> | Automatically selected |

Type-specific restoration methods verify the stored source type before returning a value.

For example:

const value = await MajikBytes.create("hello");

value.toString(); // ✅

value.toJSONValue(); // ❌ TYPE_MISMATCH

Type Guards

Each supported source type has a corresponding type guard:

isString()

isJSON()

isUint8Array()

isArrayBuffer()

isBlob()

isFile()

isNumber()

isBigInt()

isBoolean()

Example:

const value = await MajikBytes.fromPNG(blob);

if (value.isFile()) {
  const file = value.toFile();

  console.log(file.name);
}

These guards also provide TypeScript narrowing for sourceType.


Validation

MajikBytes provides validation helpers for the serialised PNG and TXT formats.

MajikBytes.isValidPNG(blob: Blob | File)

Validates a PNG as a MajikBytes payload.

const result = await MajikBytes.isValidPNG(file);

console.log(result.isValid);

console.log(result.message);

Returns

Promise<MajikBytesValidationResult>

The validator checks the MIME type, PNG structure, sentinel row, payload extraction, and SHA-3-512 integrity.


MajikBytes.isValidTXT(blob: Blob | File)

Validates a TXT representation by attempting to decode and verify it.

const result = await MajikBytes.isValidTXT(file);

Returns

Promise<MajikBytesValidationResult>

Getters

| Getter | Type | Description | | -------------------- | ----------------------- | ------------------------------------------- | | sourceType | MajikBytesSourceType | Original source type | | version | number | Prefix format version | | fileMeta | FileMeta \| undefined | Filename and MIME type for File sources | | bytes | Uint8Array | Defensive copy of raw payload bytes | | prefixedBytes | Uint8Array | Defensive copy of complete prefixed payload | | byteLength | number | Raw payload byte length | | prefixedByteLength | number | Complete prefixed payload byte length |


JSON Representation

MajikBytes can also be represented as a normal JSON object:

const json = majikBytes.toJSON();

The structure is:

interface MajikBytesJSON {
  data: string;
  length: number;
}

Where:

  • data is the Base64-encoded complete prefixed payload;
  • length is the decoded byte length of that payload.

This allows MajikBytes values to travel through JSON-compatible systems without losing their binary representation.


Error Handling

MajikBytes uses a dedicated MajikBytesError class.

try {
  const bytes = await MajikBytes.fromPNG(blob);
} catch (error) {
  if (error instanceof MajikBytesError) {
    console.error(error.code);
    console.error(error.message);
  }
}

Available error codes:

| Code | Meaning | | ------------------ | ---------------------------------------------------------------- | | INVALID_INPUT | Input is missing, invalid, or unsupported | | CORRUPT_DATA | Encoded data is malformed or fails integrity checks | | TYPE_MISMATCH | Requested restoration type does not match the stored source type | | NOT_IMPLEMENTED | Requested operation is intentionally unsupported | | ASSERTION_FAILED | Internal validation assertion failed |

The error code is intended for programmatic handling and is more stable than parsing message.


Design Notes

No Canvas Dependency for PNG Decoding

PNG decoding is intentionally performed from raw PNG binary data.

MajikBytes does not require:

createImageBitmap()

OffscreenCanvas

CanvasRenderingContext2D

to decode its embedded payload.

This makes the decoding path independent of browser graphics rendering behavior and avoids compatibility problems caused by anti-fingerprinting mechanisms in privacy-focused browsers.

The PNG is treated as a binary container rather than as a rendered image.


Lossless Does Not Mean Authenticated

MajikBytes uses SHA-3-512 to detect unexpected changes to the payload.

This provides:

  • corruption detection;
  • accidental modification detection;
  • integrity verification.

It does not provide:

  • digital signatures;
  • author authentication;
  • proof of origin;
  • non-repudiation.

Applications requiring authenticity should use a dedicated signature mechanism in addition to MajikBytes integrity verification.


File Metadata

For File inputs, MajikBytes preserves:

interface FileMeta {
  filename: string;
  mimetype: string;
}

Example:

const bytes = await MajikBytes.create(file);

const restored = await bytes.toFile();

console.log(restored.name);

console.log(restored.type);

Use Cases

MajikBytes can be useful anywhere binary data benefits from a portable, self-describing representation.

Binary data in image-compatible workflows

Embed arbitrary bytes inside a standard PNG container while retaining a structured payload format.

Portable data exchange

Move data through systems that naturally support images, text files, or JSON.

Tamper-evident payloads

Detect unexpected payload modification using SHA-3-512 integrity verification.

File preservation

Store binary files while retaining their original filename and MIME type.

Structured application state

Encode JSON or primitive values while retaining their original source type.


Contributing

If you want to contribute or help extend support to more platforms or file formats, reach out via email. All contributions are welcome!


License

Apache-2.0 — free for personal and commercial use.


Author

Developed by Josef Elijah Fabian (Zelijah) | Majikah Solutions OPC

Developer: Josef Elijah Fabian

GitHub: https://github.com/Majikah

Project Repository: https://github.com/Majikah/majik-signature


Contact

  • Business Email: [email protected]
  • Official Website: https://www.thezelijah.world
  • Majikah Ecosystem: https://majikah.solutions