Search by

manacost-labs / hearthstone-deckstrings

Zulut30

Dependency-free Hearthstone deckstring codec, validation, and clipboard export library

Package info

github.com/Manacost-Labs/deckstrings

Language:C#

pkg:composer/manacost-labs/hearthstone-deckstrings

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 6

v1.0.0 2026-08-12 23:30 UTC

This package is not auto-updated.

Last update: 2026-09-24 23:27:10 UTC


README

CI CodeQL npm PyPI NuGet Packagist License: ISC

A dependency-free Hearthstone deckstring backend library for JavaScript, TypeScript, PHP, Python, and .NET. All four implementations share one public contract and the same golden fixtures, including sideboards and full clipboard exports.

Release status: 1.0.0 is the first stable cross-language release and is publicly available on npm, Packagist, PyPI, and NuGet. The install commands below are the supported production path.

Install

Ecosystem Package Supported runtime
npm npm install @manacost-labs/deckstrings Node.js 22 or 24+, modern browsers
Composer composer require manacost-labs/hearthstone-deckstrings PHP 8.2–8.5
PyPI python -m pip install manacost-deckstrings Python 3.10–3.14
NuGet dotnet add package ManacostLabs.Deckstrings netstandard2.0, .NET 8, .NET 10

Package versions advance together. Version 1.0.0 defines the first stable cross-language API.

What the library owns

  • version 1 deckstring encoding and decoding;
  • Wild, Standard, Classic, and Twist formats;
  • heroes, cards, and sideboards;
  • deterministic canonical ordering;
  • structured validation and stable error codes;
  • parsing and formatting complete Hearthstone clipboard exports;
  • defensive limits for untrusted input.

The core does not download card data, make network requests, or decide whether a deck is legal for a patch. Card names and costs can be added at the edge with an optional resolver callback.

Shared model

{
  "format": 1,
  "heroes": [7],
  "cards": [[1, 2], [2, 2], [3, 2], [4, 1]],
  "sideboardCards": [[5, 1, 90749]]
}
  • cards entries are [dbfId, count];
  • sideboardCards entries are [dbfId, count, ownerDbfId];
  • heroes and cards are sorted by DBF ID;
  • sideboard cards are sorted by owner and then DBF ID;
  • duplicate heroes, cards, and sideboard (ownerDbfId, dbfId) pairs are invalid.

The normative model is spec/deck.schema.json, and the wire/error/export contract is documented in spec/README.md.

JavaScript / TypeScript

import {
  FormatType,
  canonicalize,
  decode,
  encode,
  formatExport,
  parseExport,
  validate,
} from "@manacost-labs/deckstrings";

const deck = decode("AAEBAQcBBAMBAgMAAA==");
const result = validate(deck); // { valid, errors }
const canonical = canonicalize(deck);
const deckstring = encode(canonical);
const parsed = parseExport(`### Example\n${deckstring}`);
const text = formatExport(parsed.deck, parsed.metadata);

The npm package includes ESM, CommonJS, browser ESM, UMD, and bundled TypeScript declarations.

PHP

use ManacostLabs\Deckstrings\Deckstrings;

$deck = Deckstrings::decode('AAEBAQcBBAMBAgMAAA==');
$result = Deckstrings::validate($deck);
$deckstring = Deckstrings::encode(Deckstrings::canonicalize($deck));
$parsed = Deckstrings::parseExport("### Example\n{$deckstring}");
$text = Deckstrings::formatExport($parsed['deck'], $parsed['metadata']);

Python

from manacost_deckstrings import (
    canonicalize,
    decode,
    encode,
    format_export,
    parse_export,
    validate,
)

deck = decode("AAEBAQcBBAMBAgMAAA==")
result = validate(deck)
deckstring = encode(canonicalize(deck))
parsed = parse_export(f"### Example\n{deckstring}")
text = format_export(parsed["deck"], parsed["metadata"])

The Python distribution is typed and ships a py.typed marker.

C# / .NET

using ManacostLabs.Deckstrings;

var deck = Deckstrings.Decode("AAEBAQcBBAMBAgMAAA==");
var result = Deckstrings.Validate(deck);
var deckstring = Deckstrings.Encode(Deckstrings.Canonicalize(deck));
var parsed = Deckstrings.ParseExport($"### Example\n{deckstring}");
var text = Deckstrings.FormatExport(parsed.Deck, parsed.Metadata);

NuGet releases include XML documentation, portable PDBs, Source Link metadata, and a separate .snupkg symbol package.

Validation and errors

validate/Validate returns ordinary user-input failures and does not throw:

{
  "valid": false,
  "errors": [
    {
      "code": "invalid_count",
      "path": "cards[0][1]",
      "message": "card count must be a positive integer"
    }
  ]
}

Encoding, decoding, canonicalization, and export parsing raise an idiomatic language exception. Match its stable machine-readable code, not the human-readable message. See docs/API.md for language-specific names and the complete code list.

Card display resolver

formatExport/format_export accepts an optional callback from DBF ID to { name, cost? } (or the native equivalent). The callback may return null for an unknown card. Names must be non-blank single-line strings, and costs must be non-negative integers no larger than 2,147,483,647. The resolver is presentation-only and never changes the encoded deckstring.

Compatibility promise

Every implementation reads fixtures/deckstrings.json, fixtures/api.json, and fixtures/exports.json directly. A behavior change is not accepted until the shared contract and all language jobs agree. Legacy deckstrings without a sideboard marker remain supported; encoders always produce canonical output.

Development

# JavaScript / TypeScript
yarn install --frozen-lockfile --ignore-scripts
npx playwright install chromium
npm run verify

# Shared schemas
uv sync --project packages/python --locked --all-extras
uv run --project packages/python --locked python scripts/validate_fixtures.py
uv run --project packages/python --locked python scripts/check_versions.py

# PHP
composer install --no-scripts --no-plugins
composer check

# Python
uv run --project packages/python --locked pytest packages/python/tests
uv run --project packages/python --locked ruff check packages/python
uv run --project packages/python --locked mypy packages/python/src

# .NET
dotnet test packages/dotnet/tests/ManacostLabs.Deckstrings.Tests/ManacostLabs.Deckstrings.Tests.csproj -c Release

See CONTRIBUTING.md, the release process, the migration guide, and the roadmap.

Credits and license

This is an independent Manacost Labs repository whose complete Git history is derived from and preserves attribution to HearthSim/hearthstone-deckstrings. Manacost Labs maintains the multi-language contract, native backend implementations, packaging, and release automation. Repository migration details are recorded in docs/REPOSITORY_MIGRATION.md.

Licensed under the ISC License.