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

@aokiapp/tlv

v0.4.1

Published

Tag-Length-Value (TLV) parser and builder library with schema support. Provides both parsing and building APIs as submodules.

Readme

@aokiapp/tlv

Tag-Length-Value (TLV) parser and builder library with schema support. Provides both parsing and building APIs as submodules.

Features

  • Schema-based TLV parsing and building: Define structured schemas for complex TLV data
  • DER encoding support: Full compliance with Distinguished Encoding Rules
  • Modular API: Separate parser and builder modules for focused usage
  • TypeScript-first: Complete type safety with inferred types from schemas
  • ASN.1 compatible: Support for various ASN.1 constructs (SEQUENCE, SET, primitives, etc.)
  • Real-world examples: Includes CMS (RFC 5652) and CRCL implementations

Installation

From npm

npm install @aokiapp/tlv

From GitHub Packages

Note: GitHub Packages requires authentication even for public packages.

First, authenticate with GitHub:

npm login --registry=https://npm.pkg.github.com

Then install:

npm install @aokiapp/tlv --registry=https://npm.pkg.github.com

Or configure your .npmrc:

@aokiapp:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN

Quick Start

Basic TLV Parsing

import { BasicTLVParser } from "@aokiapp/tlv/parser";

// Parse raw TLV data
const buffer = new Uint8Array([0x04, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f])
  .buffer;
const tlv = BasicTLVParser.parse(buffer);

console.log(tlv);
// {
//   tag: { tagClass: 0, constructed: false, tagNumber: 4 },
//   length: 5,
//   value: ArrayBuffer(...),
//   endOffset: 7
// }

Schema-based Parsing

import { SchemaParser, Schema, TagClass } from "@aokiapp/tlv/parser";
import { decodeUtf8, decodeInteger } from "@aokiapp/tlv/common";

// Define a schema for a person record
const PersonSchema = Schema.constructed("person", { tagNumber: 16 }, [
  Schema.primitive("id", { tagNumber: 2 }, decodeInteger),
  Schema.primitive("name", { tagNumber: 12 }, decodeUtf8),
  Schema.primitive("email", { tagNumber: 12, optional: true }, decodeUtf8),
]);

// Parse TLV data according to schema
const parser = new SchemaParser(PersonSchema);
const result = parser.parse(tlvBuffer);

// Result is fully typed:
// { id: number, name: string, email?: string }

Schema-based Building

import { SchemaBuilder, Schema } from "@aokiapp/tlv/builder";
import { encodeUtf8, encodeInteger } from "@aokiapp/tlv/common";

// Define builder schema
const PersonSchema = Schema.constructed("person", { tagNumber: 16 }, [
  Schema.primitive("id", { tagNumber: 2 }, encodeInteger),
  Schema.primitive("name", { tagNumber: 12 }, encodeUtf8),
]);

// Build TLV data from structured input
const builder = new SchemaBuilder(PersonSchema);
const tlvBuffer = builder.build({
  id: 123,
  name: "John Doe",
});

API Reference

Parser Module (@aokiapp/tlv/parser)

BasicTLVParser

Low-level TLV parsing for raw DER/BER data.

class BasicTLVParser {
  static parse(buffer: ArrayBuffer): TLVResult;
}

Parameters:

  • buffer: ArrayBuffer - Raw TLV data to parse

Returns:

  • TLVResult - Parsed structure with tag, length, value, and endOffset

Throws:

  • Error if indefinite length (0x80) is encountered (DER compliance)
  • Error if declared length exceeds available bytes

Example:

const buffer = new Uint8Array([0x04, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f])
  .buffer;
const result = BasicTLVParser.parse(buffer);
// Returns: {
//   tag: { tagClass: 0, constructed: false, tagNumber: 4 },
//   length: 5,
//   value: ArrayBuffer(5), // "Hello"
//   endOffset: 7
// }

SchemaParser

Schema-driven TLV parsing with full type inference.

class SchemaParser {
  constructor(schema: TLVSchema, options?: { strict?: boolean });
  parse(buffer: ArrayBuffer): any; // Fully typed based on schema
}

Constructor Parameters:

  • schema: TLVSchema - TLV schema definition
  • options.strict?: boolean - Enable strict validation (default: true)

Methods:

parse(buffer: ArrayBuffer): any

Parse TLV data according to schema with full type inference.

Parameters:

  • buffer: ArrayBuffer - DER-encoded TLV data

Returns:

  • Fully typed result based on schema definition (TypeScript infers the exact type)

Behavior:

  • Strict mode (default): Enforces exact schema compliance, canonical SET ordering
  • Non-strict mode: More permissive parsing, preserves original SET order
  • SEQUENCE: Children must appear in exact schema order
  • SET: Children can appear in any order, validated for canonical ordering in strict mode
  • Repeated fields: Automatically collect multiple consecutive matching children

Throws:

  • Error on tag class/number mismatches
  • Error on missing required fields
  • Error on unknown children (immediate failure regardless of strict mode)
  • Error on DER canonical order violations in SET (strict mode only)

Schema (Parser)

Factory class for creating parser schemas.

class Schema {
  static primitive(
    name: string,
    options: SchemaOptions,
    decode?: (buffer: ArrayBuffer) => any,
  ): TLVSchema;

  static constructed(
    name: string,
    options: SchemaOptions,
    fields: TLVSchema[],
  ): TLVSchema;

  static repeated(
    name: string,
    options: SchemaOptions,
    item: TLVSchema,
  ): TLVSchema;
}

Builder Module (@aokiapp/tlv/builder)

BasicTLVBuilder

Low-level TLV building for constructing DER-encoded data.

class BasicTLVBuilder {
  static build(tlv: TLVResult): ArrayBuffer;
}

Parameters:

  • tlv: TLVResult - TLV structure to encode

Returns:

  • ArrayBuffer - DER-encoded TLV data

Behavior:

  • Supports high tag numbers (>= 31) with multi-byte encoding
  • Supports long-form length encoding (>= 128 bytes)
  • Enforces DER canonical encoding rules
  • Maximum length field: 126 bytes (BER/DER limit)

Throws:

  • Error for invalid tag numbers (negative, non-finite)
  • Error for invalid tag classes (outside 0-3 range)
  • Error for values too large to encode (> 126-byte length field)

Example:

const tlv: TLVResult = {
  tag: { tagClass: TagClass.Universal, constructed: false, tagNumber: 4 },
  length: 5,
  value: new TextEncoder().encode("Hello").buffer,
  endOffset: 0,
};
const encoded = BasicTLVBuilder.build(tlv);

SchemaBuilder

Schema-driven TLV building with type validation.

class SchemaBuilder {
  constructor(schema: TLVSchema, options?: { strict?: boolean });
  build(data: any): ArrayBuffer; // Input type inferred from schema
}

Constructor Parameters:

  • schema: TLVSchema - TLV schema definition
  • options.strict?: boolean - Enable strict validation (default: true)

Methods:

build(data: any): ArrayBuffer

Build DER-encoded TLV data from structured input.

Parameters:

  • data: any - Input data matching schema structure (TypeScript infers exact type)

Returns:

  • ArrayBuffer - DER-encoded TLV data

Behavior:

  • Strict mode (default): Validates all required fields, sorts SET children canonically
  • Non-strict mode: Permits missing fields, preserves SET child order
  • Type safety: Input data type is inferred from schema definition
  • SET ordering: Applies DER canonical lexicographic sorting in strict mode

Throws:

  • Error on missing required properties (strict mode)
  • Error on type validation failures
  • Error on top-level repeated schemas (must be wrapped in constructed container)

Schema (Builder)

Factory class for creating builder schemas.

class Schema {
  static primitive(
    name: string,
    options: SchemaOptions,
    encode?: (data: any) => ArrayBuffer,
  ): TLVSchema;

  static constructed(
    name: string,
    options: SchemaOptions,
    fields: TLVSchema[],
  ): TLVSchema;

  static repeated(
    name: string,
    options: SchemaOptions,
    item: TLVSchema,
  ): TLVSchema;
}

Schema Options

All schema factory methods accept common options:

interface SchemaOptions {
  readonly tagClass?: TagClass; // Default: TagClass.Universal
  readonly tagNumber?: number; // Required for primitives
  readonly optional?: boolean; // Default: false
  readonly isSet?: boolean; // Auto-inferred for UNIVERSAL 16/17
}

Tag Class Values:

  • TagClass.Universal (0) - Standard ASN.1 types
  • TagClass.Application (1) - Application-specific types
  • TagClass.ContextSpecific (2) - Context-specific types
  • TagClass.Private (3) - Private types

Tag Number Inference:

  • SEQUENCE: tagNumber: 16 (UNIVERSAL, constructed)
  • SET: tagNumber: 17 (UNIVERSAL, constructed)
  • Custom tags: Explicit tagNumber required

Utility Functions

Encoding Functions

// Text encoding
function encodeUtf8(str: string): ArrayBuffer;
function encodeAscii(str: string): ArrayBuffer;

// Number encoding
function encodeInteger(n: number): ArrayBuffer; // DER INTEGER encoding
function encodeOID(oid: string): ArrayBuffer; // OBJECT IDENTIFIER encoding

// Binary encoding
function encodeBitString(bits: {
  unusedBits: number;
  data: Uint8Array;
}): ArrayBuffer;

// Buffer utilities
function toArrayBuffer(u8: Uint8Array): ArrayBuffer;

Decoding Functions

// Text decoding
function decodeUtf8(buffer: ArrayBuffer): string;
function decodeAscii(buffer: ArrayBuffer): string;
function decodeShiftJis(buffer: ArrayBuffer): string;

// Number decoding
function decodeInteger(buffer: ArrayBuffer): number;
function decodeOID(buffer: ArrayBuffer): string;

// Binary decoding
function decodeBitStringHex(buffer: ArrayBuffer): {
  unusedBits: number;
  hex: string;
};

// Buffer utilities
function toHex(input: ArrayBuffer | Uint8Array): string;
function bufferToArrayBuffer(buf: Buffer): ArrayBuffer;

Schema Pattern Examples

Basic Schema Types

// Primitive field
Schema.primitive("fieldName", { tagNumber: 4 }, decodeUtf8);

// Optional field
Schema.primitive("optional", { tagNumber: 5, optional: true }, decodeUtf8);

// Context-specific tag [0], [1], etc.
Schema.primitive(
  "contextTag",
  {
    tagClass: TagClass.ContextSpecific,
    tagNumber: 0,
  },
  decodeInteger,
);

// SEQUENCE (ordered container)
Schema.constructed("sequence", { tagNumber: 16 }, [
  Schema.primitive("field1", { tagNumber: 2 }, decodeInteger),
  Schema.primitive("field2", { tagNumber: 12 }, decodeUtf8),
]);

// SET (unordered container)
Schema.constructed("set", { tagNumber: 17, isSet: true }, [
  Schema.primitive("a", { tagNumber: 2 }, decodeInteger),
  Schema.primitive("b", { tagNumber: 12 }, decodeUtf8),
]);

// SEQUENCE OF (repeated items)
Schema.constructed("container", { tagNumber: 16 }, [
  Schema.repeated(
    "items",
    {},
    Schema.primitive("item", { tagNumber: 4 }, decodeUtf8),
  ),
]);

Nested Structures

const DocumentSchema = Schema.constructed("document", { tagNumber: 16 }, [
  Schema.constructed("header", { tagNumber: 16 }, [
    Schema.primitive("version", { tagNumber: 2 }, decodeInteger),
    Schema.primitive("timestamp", { tagNumber: 24 }, decodeUtf8),
  ]),
  Schema.constructed("content", { tagNumber: 16 }, [
    Schema.primitive("title", { tagNumber: 12 }, decodeUtf8),
    Schema.primitive(
      "description",
      { tagNumber: 12, optional: true },
      decodeUtf8,
    ),
    Schema.repeated(
      "tags",
      {},
      Schema.primitive("tag", { tagNumber: 12 }, decodeUtf8),
    ),
  ]),
]);

// TypeScript infers:
// {
//   header: { version: number; timestamp: string };
//   content: { title: string; description?: string; tags: string[] }
// }

Operating Modes

Strict Mode (Default)

new SchemaParser(schema, { strict: true }); // Default
new SchemaBuilder(schema, { strict: true });
  • Validation: Enforces exact schema compliance
  • SET ordering: Validates/applies DER canonical ordering
  • Error handling: Fails fast on any schema violations

Non-Strict Mode

new SchemaParser(schema, { strict: false });
new SchemaBuilder(schema, { strict: false });
  • Flexibility: More permissive parsing/building
  • SET ordering: Preserves original order
  • Performance: Faster with less validation overhead

Error Handling

try {
  const result = new SchemaParser(schema).parse(buffer);
} catch (error) {
  // Detailed error messages for debugging:
  // - "TLV tag mismatch for primitive 'fieldName'"
  // - "Missing required property 'fieldName'"
  // - "DER canonical order violation in SET 'setName'"
  console.error("Parse failed:", error.message);
}

Advanced Usage

Custom Codecs

// Custom timestamp codec
function decodeTimestamp(buffer: ArrayBuffer): Date {
  const iso = new TextDecoder().decode(buffer);
  return new Date(iso);
}

const schema = Schema.primitive("created", { tagNumber: 24 }, decodeTimestamp);
// Result type automatically inferred as Date

Development

Build

npm run build          # Compile TypeScript
npm run typecheck      # Type checking only

Testing

npm test              # Run tests

Code Quality

npm run lint          # ESLint
npm run format        # Prettier

Release

This library is automatically published to both npm and GitHub Packages via GitHub Actions.

npm run changelog     # Create changeset
npm run version       # Update version
npm run publish       # Publish manually (for testing, otherwise use GitHub Actions)

When changes are pushed to the main branch with a changeset, the GitHub Actions workflow will:

  1. Create a release PR or publish to npm
  2. Automatically publish to GitHub Packages if npm publish succeeds

Project Structure

├── src/
│   ├── parser/          # TLV parsing functionality
│   ├── builder/         # TLV building functionality
│   ├── common/          # Shared types and utilities
│   └── utils/           # Encoding/decoding utilities
├── examples/
│   ├── cms/             # CMS (RFC 5652) examples
│   └── crcl/            # CRCL certificate request examples
├── tests/               # Test suite
└── dist/                # Compiled output

Supported Encoders/Decoders

The library includes various built-in codecs:

  • Text: UTF-8, ASCII, Shift-JIS
  • Numbers: INTEGER (DER encoding)
  • Identifiers: OBJECT IDENTIFIER
  • Binary: BIT STRING, OCTET STRING
  • Utility: Hex conversion, buffer operations

TypeScript Support

Full TypeScript support with:

  • Schema type inference for parsing results
  • Compile-time validation of builder input data
  • Optional/required field type safety
  • Generic schema composition

License

This project is licensed under the AokiApp Normative Application License - Tight. See LICENSE.md for details.

Note: This is NOT an open source license. The source code is made publicly visible for transparency only. Commercial use requires explicit written permission from AokiApp Inc.

Contributing

This project is currently under restrictive licensing. For contribution guidelines or commercial licensing inquiries, please contact AokiApp Inc. at [email protected].

Changelog

See CHANGELOG.md for version history and changes.