@bigdreamsweb3/wordbin 1.0.7 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/constants.ts","../src/dict/dictionary-loader.ts","../src/core.ts"],"sourcesContent":["// wordbin\\src\\constants.ts\r\nexport const MAGIC = new Uint8Array([87, 66]) // 'W''B'\r\nexport const LITERAL = 0xff\r\n","import fs from \"fs/promises\";\r\nimport path from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\nimport type { WordBinDictionary } from \"../types.js\";\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\n\r\n// 1️⃣ Bundled dictionaries inside the package (dist/data)\r\nconst PACKAGE_DATA_DIR = path.join(__dirname, \"data\");\r\n\r\n// 2️⃣ User project dictionaries (built via CLI)\r\nconst LOCAL_DATA_DIR = path.join(process.cwd(), \"data\");\r\n\r\n/**\r\n * Get all dictionary directories that exist\r\n * Priority: LOCAL first, then PACKAGE fallback\r\n */\r\nasync function getExistingDataDirs(): Promise<string[]> {\r\n const dirs: string[] = [];\r\n\r\n try {\r\n await fs.access(LOCAL_DATA_DIR);\r\n dirs.push(LOCAL_DATA_DIR);\r\n } catch {}\r\n\r\n try {\r\n await fs.access(PACKAGE_DATA_DIR);\r\n dirs.push(PACKAGE_DATA_DIR);\r\n } catch {}\r\n\r\n return dirs;\r\n}\r\n\r\n/**\r\n * Scan all available dictionary versions from all data dirs\r\n */\r\nexport async function getAllAvailableDictionaryVersions(): Promise<number[]> {\r\n const dirs = await getExistingDataDirs();\r\n const versions = new Set<number>();\r\n\r\n for (const dir of dirs) {\r\n try {\r\n const files = await fs.readdir(dir);\r\n\r\n for (const file of files) {\r\n const match = file.match(/wordbin-v(\\d+)/i);\r\n if (match) {\r\n versions.add(parseInt(match[1], 10));\r\n }\r\n }\r\n } catch {\r\n // Ignore invalid dirs silently\r\n }\r\n }\r\n\r\n return Array.from(versions).sort((a, b) => a - b);\r\n}\r\n\r\n/**\r\n * Load a specific dictionary version\r\n * LOCAL dictionaries override PACKAGE ones\r\n */\r\nexport async function loadDictionaryByVersion(\r\n version: number,\r\n): Promise<WordBinDictionary> {\r\n const dirs = await getExistingDataDirs();\r\n\r\n if (dirs.length === 0) {\r\n throw new Error(\r\n `No dictionary directories found. Expected ./data or bundled package data.`,\r\n );\r\n }\r\n\r\n for (const dir of dirs) {\r\n const files = await fs.readdir(dir);\r\n\r\n const versionFile = files.find((f) =>\r\n f.match(new RegExp(`wordbin-v${version}(?:\\\\.|-)`, \"i\")),\r\n );\r\n\r\n if (versionFile) {\r\n const filePath = path.join(dir, versionFile);\r\n const data = await fs.readFile(filePath, \"utf-8\");\r\n const dict = JSON.parse(data) as WordBinDictionary;\r\n\r\n if (dict.version !== version) {\r\n throw new Error(\r\n `Version mismatch: file ${versionFile} claims v${dict.version} but expected v${version}`,\r\n );\r\n }\r\n\r\n return dict;\r\n }\r\n }\r\n\r\n const available = await getAllAvailableDictionaryVersions();\r\n\r\n throw new Error(\r\n `Dictionary version ${version} not found. Available versions: ${available.join(\", \")}`,\r\n );\r\n}\r\n\r\n/**\r\n * Load the latest available dictionary version\r\n */\r\nexport async function loadLatestDictionary(): Promise<WordBinDictionary> {\r\n const versions = await getAllAvailableDictionaryVersions();\r\n\r\n if (versions.length === 0) {\r\n throw new Error(\r\n `No dictionary files found. Run \"npx wordbin build\" or use bundled v1.`,\r\n );\r\n }\r\n\r\n const latestVersion = Math.max(...versions);\r\n\r\n console.log(\r\n `Loading latest dictionary: v${latestVersion} (available: ${versions.join(\", \")})`,\r\n );\r\n\r\n return loadDictionaryByVersion(latestVersion);\r\n}\r\n\r\n/**\r\n * Check if a specific version exists\r\n */\r\nexport async function hasDictionaryVersion(version: number): Promise<boolean> {\r\n const versions = await getAllAvailableDictionaryVersions();\r\n return versions.includes(version);\r\n}\r\n","import { LITERAL } from \"./constants.js\";\r\nimport {\r\n toHex,\r\n toBase64,\r\n fromBase64,\r\n encodeVarint,\r\n decodeVarint,\r\n utf8Encode,\r\n utf8Decode,\r\n} from \"./utils/buffer.js\";\r\nimport type { EncodeResult, WordBinDictionary } from \"./types\";\r\nimport { buildDictionary } from \"./dict/builder\";\r\nimport {\r\n loadDictionaryByVersion,\r\n loadLatestDictionary,\r\n} from \"./dict/dictionary-loader.js\";\r\n\r\nexport class WordBin {\r\n private primaryDictVersion: number;\r\n private log: (...args: any[]) => void;\r\n\r\n constructor(initialDict?: WordBinDictionary, options?: { debug?: boolean }) {\r\n this.primaryDictVersion = initialDict?.version ?? 2;\r\n this.log = options?.debug\r\n ? (...args) => console.log(\"[WordBin]\", ...args)\r\n : () => {};\r\n }\r\n\r\n static async createFromWords(words: string[]): Promise<WordBin> {\r\n console.warn(\r\n \"Building dictionary from scratch – consider using pre-built files\",\r\n );\r\n const dict = await buildDictionary(words);\r\n return new WordBin(dict);\r\n }\r\n\r\n static async createFromJson(dictJson: WordBinDictionary): Promise<WordBin> {\r\n return new WordBin(dictJson);\r\n }\r\n\r\n static async create(options?: { debug?: boolean }): Promise<WordBin> {\r\n const latestDict = await loadLatestDictionary();\r\n return new WordBin(latestDict, options);\r\n }\r\n\r\n private async getMapsForVersion(version: number): Promise<{\r\n reverseMap: Map<string, string>;\r\n forwardMap: Map<string, Uint8Array>;\r\n sortedIdLengths: number[];\r\n }> {\r\n const dict = await loadDictionaryByVersion(version);\r\n\r\n const reverseMap = new Map<string, string>();\r\n const forwardMap = new Map<string, Uint8Array>();\r\n const idLengths = new Set<number>();\r\n\r\n for (const [hex, words] of Object.entries(dict.words)) {\r\n if (!words.length) continue;\r\n if (words.length > 1) {\r\n throw new Error(\r\n `Dictionary corruption: ID ${hex} maps to multiple words`,\r\n );\r\n }\r\n\r\n const word = words[0];\r\n const bytes = Buffer.from(hex, \"hex\"); // Buffer is a Uint8Array\r\n idLengths.add(bytes.length);\r\n\r\n reverseMap.set(hex, word);\r\n forwardMap.set(word, bytes);\r\n }\r\n\r\n const sortedIdLengths = Array.from(idLengths).sort((a, b) => b - a); // longest first\r\n\r\n return { reverseMap, forwardMap, sortedIdLengths };\r\n }\r\n\r\n async encode(\r\n text: string | EncodeResult | Uint8Array,\r\n options?: { dictVersion?: number },\r\n ): Promise<EncodeResult> {\r\n let textStr: string;\r\n if (typeof text === \"string\") {\r\n textStr = text;\r\n } else if (text instanceof Uint8Array) {\r\n textStr = toBase64(text);\r\n } else {\r\n textStr = text.encodedBase64;\r\n }\r\n\r\n const trimmed = textStr.trim();\r\n if (!trimmed) {\r\n return {\r\n originalText: \"\",\r\n dictVersion: this.primaryDictVersion,\r\n encoded: new Uint8Array(0),\r\n payload: \"\",\r\n encodedBase64: \"\",\r\n originalBytes: 0,\r\n encodedBytes: 0,\r\n bytesSaved: 0,\r\n ratioPercent: 100,\r\n };\r\n }\r\n\r\n const words = trimmed.split(/\\s+/).filter(Boolean);\r\n const useVersion = options?.dictVersion ?? this.primaryDictVersion;\r\n\r\n const header = new Uint8Array([useVersion]);\r\n const chunks: Uint8Array[] = [header];\r\n\r\n const { forwardMap } = await this.getMapsForVersion(useVersion);\r\n\r\n for (const w of words) {\r\n const id = forwardMap.get(w);\r\n if (id) {\r\n chunks.push(id);\r\n } else {\r\n const utf8 = utf8Encode(w);\r\n const lenVarint = encodeVarint(utf8.length);\r\n const out = new Uint8Array(1 + lenVarint.length + utf8.length);\r\n out[0] = LITERAL;\r\n out.set(lenVarint, 1);\r\n out.set(utf8, 1 + lenVarint.length);\r\n chunks.push(out);\r\n }\r\n }\r\n\r\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n const originalBytes = new TextEncoder().encode(textStr).length;\r\n const base64Result = toBase64(result);\r\n\r\n return {\r\n originalText: textStr,\r\n dictVersion: useVersion,\r\n encoded: result,\r\n payload: base64Result,\r\n encodedBase64: base64Result,\r\n originalBytes,\r\n encodedBytes: totalLength,\r\n bytesSaved: originalBytes - totalLength,\r\n ratioPercent:\r\n totalLength === 0\r\n ? 100\r\n : Math.round((totalLength / originalBytes) * 100 * 100) / 100,\r\n };\r\n }\r\n\r\n async decode(data: Uint8Array | string): Promise<string> {\r\n let buffer: Uint8Array;\r\n if (typeof data === \"string\") {\r\n buffer = fromBase64(data);\r\n } else {\r\n buffer = data;\r\n }\r\n\r\n if (buffer.length < 1) {\r\n throw new Error(\"Data too short to contain version byte\");\r\n }\r\n\r\n const version = buffer[0];\r\n let pos = 1;\r\n\r\n const { reverseMap, sortedIdLengths } =\r\n await this.getMapsForVersion(version);\r\n\r\n const result: string[] = [];\r\n const decoded = this.tryDecode(\r\n pos,\r\n buffer,\r\n reverseMap,\r\n result,\r\n 0,\r\n sortedIdLengths,\r\n );\r\n\r\n if (decoded === null) {\r\n throw new Error(\r\n \"Decode failed — possible data corruption, wrong dictionary version, or unsupported format\",\r\n );\r\n }\r\n\r\n return decoded;\r\n }\r\n\r\n private tryDecode(\r\n pos: number,\r\n buffer: Uint8Array,\r\n reverseMap: Map<string, string>,\r\n result: string[],\r\n depth: number,\r\n sortedIdLengths: number[],\r\n ): string | null {\r\n if (pos === buffer.length) {\r\n return result.join(\" \");\r\n }\r\n\r\n // 1. Try literal block\r\n if (buffer[pos] === LITERAL) {\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n\r\n // Basic sanity check — very large literals are suspicious\r\n if (byteLen > 1_000_000 || byteLen < 0) {\r\n return null;\r\n }\r\n\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n\r\n if (end > buffer.length) {\r\n return null;\r\n }\r\n\r\n const literalBytes = buffer.subarray(start, end);\r\n const word = utf8Decode(literalBytes);\r\n\r\n result.push(word);\r\n const res = this.tryDecode(\r\n end,\r\n buffer,\r\n reverseMap,\r\n result,\r\n depth + 1,\r\n sortedIdLengths,\r\n );\r\n if (res !== null) return res;\r\n result.pop();\r\n }\r\n\r\n // 2. Try dictionary IDs — longest first\r\n for (const len of sortedIdLengths) {\r\n if (pos + len > buffer.length) continue;\r\n\r\n const slice = buffer.subarray(pos, pos + len);\r\n const key = toHex(slice);\r\n\r\n if (reverseMap.has(key)) {\r\n const word = reverseMap.get(key)!;\r\n result.push(word);\r\n\r\n const res = this.tryDecode(\r\n pos + len,\r\n buffer,\r\n reverseMap,\r\n result,\r\n depth + 1,\r\n sortedIdLengths,\r\n );\r\n if (res !== null) return res;\r\n\r\n result.pop();\r\n }\r\n }\r\n\r\n // No valid continuation found on this path\r\n return null;\r\n }\r\n}\r\n"],"names":["__filename","__dirname"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/constants.ts","../src/dict/dictionary-loader.ts","../node_modules/base-x/src/esm/index.js","../node_modules/bs58/src/esm/index.js","../src/core/index.ts"],"sourcesContent":["// wordbin\\src\\constants.ts\r\nexport const MAGIC = new Uint8Array([87, 66]) // 'W''B'\r\nexport const LITERAL = 0xff\r\n","import fs from \"fs/promises\";\r\nimport path from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\nimport type { WordBinDictionary } from \"../types.js\";\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\n\r\n// 1️⃣ Bundled dictionaries inside the package (dist/data)\r\nconst PACKAGE_DATA_DIR = path.join(__dirname, \"data\");\r\n\r\n// 2️⃣ User project dictionaries (built via CLI)\r\nconst LOCAL_DATA_DIR = path.join(process.cwd(), \"data\");\r\n\r\n/**\r\n * Get all dictionary directories that exist\r\n * Priority: LOCAL first, then PACKAGE fallback\r\n */\r\nasync function getExistingDataDirs(): Promise<string[]> {\r\n const dirs: string[] = [];\r\n\r\n try {\r\n await fs.access(LOCAL_DATA_DIR);\r\n dirs.push(LOCAL_DATA_DIR);\r\n } catch {}\r\n\r\n try {\r\n await fs.access(PACKAGE_DATA_DIR);\r\n dirs.push(PACKAGE_DATA_DIR);\r\n } catch {}\r\n\r\n return dirs;\r\n}\r\n\r\n/**\r\n * Scan all available dictionary versions from all data dirs\r\n */\r\nexport async function getAllAvailableDictionaryVersions(): Promise<number[]> {\r\n const dirs = await getExistingDataDirs();\r\n const versions = new Set<number>();\r\n\r\n for (const dir of dirs) {\r\n try {\r\n const files = await fs.readdir(dir);\r\n\r\n for (const file of files) {\r\n const match = file.match(/wordbin-v(\\d+)/i);\r\n if (match) {\r\n versions.add(parseInt(match[1], 10));\r\n }\r\n }\r\n } catch {\r\n // Ignore invalid dirs silently\r\n }\r\n }\r\n\r\n return Array.from(versions).sort((a, b) => a - b);\r\n}\r\n\r\n/**\r\n * Load a specific dictionary version\r\n * LOCAL dictionaries override PACKAGE ones\r\n */\r\nexport async function loadDictionaryByVersion(\r\n version: number,\r\n): Promise<WordBinDictionary> {\r\n const dirs = await getExistingDataDirs();\r\n\r\n if (dirs.length === 0) {\r\n throw new Error(\r\n `No dictionary directories found. Expected ./data or bundled package data.`,\r\n );\r\n }\r\n\r\n for (const dir of dirs) {\r\n const files = await fs.readdir(dir);\r\n\r\n const versionFile = files.find((f) =>\r\n f.match(new RegExp(`wordbin-v${version}(?:\\\\.|-)`, \"i\")),\r\n );\r\n\r\n if (versionFile) {\r\n const filePath = path.join(dir, versionFile);\r\n const data = await fs.readFile(filePath, \"utf-8\");\r\n const dict = JSON.parse(data) as WordBinDictionary;\r\n\r\n if (dict.version !== version) {\r\n throw new Error(\r\n `Version mismatch: file ${versionFile} claims v${dict.version} but expected v${version}`,\r\n );\r\n }\r\n\r\n return dict;\r\n }\r\n }\r\n\r\n const available = await getAllAvailableDictionaryVersions();\r\n\r\n throw new Error(\r\n `Dictionary version ${version} not found. Available versions: ${available.join(\", \")}`,\r\n );\r\n}\r\n\r\n/**\r\n * Load the latest available dictionary version\r\n */\r\nexport async function loadLatestDictionary(): Promise<WordBinDictionary> {\r\n const versions = await getAllAvailableDictionaryVersions();\r\n\r\n if (versions.length === 0) {\r\n throw new Error(\r\n `No dictionary files found. Run \"npx wordbin build\" or use bundled v1.`,\r\n );\r\n }\r\n\r\n const latestVersion = Math.max(...versions);\r\n\r\n console.log(\r\n `Loading latest dictionary: v${latestVersion} (available: ${versions.join(\", \")})`,\r\n );\r\n\r\n return loadDictionaryByVersion(latestVersion);\r\n}\r\n\r\n/**\r\n * Check if a specific version exists\r\n */\r\nexport async function hasDictionaryVersion(version: number): Promise<boolean> {\r\n const versions = await getAllAvailableDictionaryVersions();\r\n return versions.includes(version);\r\n}\r\n","// base-x encoding / decoding\n// Copyright (c) 2018 base-x contributors\n// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)\n// Distributed under the MIT software license, see the accompanying\n// file LICENSE or http://www.opensource.org/licenses/mit-license.php.\nfunction base (ALPHABET) {\n if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }\n const BASE_MAP = new Uint8Array(256)\n for (let j = 0; j < BASE_MAP.length; j++) {\n BASE_MAP[j] = 255\n }\n for (let i = 0; i < ALPHABET.length; i++) {\n const x = ALPHABET.charAt(i)\n const xc = x.charCodeAt(0)\n if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }\n BASE_MAP[xc] = i\n }\n const BASE = ALPHABET.length\n const LEADER = ALPHABET.charAt(0)\n const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up\n const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up\n function encode (source) {\n // eslint-disable-next-line no-empty\n if (source instanceof Uint8Array) { } else if (ArrayBuffer.isView(source)) {\n source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength)\n } else if (Array.isArray(source)) {\n source = Uint8Array.from(source)\n }\n if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') }\n if (source.length === 0) { return '' }\n // Skip & count leading zeroes.\n let zeroes = 0\n let length = 0\n let pbegin = 0\n const pend = source.length\n while (pbegin !== pend && source[pbegin] === 0) {\n pbegin++\n zeroes++\n }\n // Allocate enough space in big-endian base58 representation.\n const size = ((pend - pbegin) * iFACTOR + 1) >>> 0\n const b58 = new Uint8Array(size)\n // Process the bytes.\n while (pbegin !== pend) {\n let carry = source[pbegin]\n // Apply \"b58 = b58 * 256 + ch\".\n let i = 0\n for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {\n carry += (256 * b58[it1]) >>> 0\n b58[it1] = (carry % BASE) >>> 0\n carry = (carry / BASE) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n pbegin++\n }\n // Skip leading zeroes in base58 result.\n let it2 = size - length\n while (it2 !== size && b58[it2] === 0) {\n it2++\n }\n // Translate the result into a string.\n let str = LEADER.repeat(zeroes)\n for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }\n return str\n }\n function decodeUnsafe (source) {\n if (typeof source !== 'string') { throw new TypeError('Expected String') }\n if (source.length === 0) { return new Uint8Array() }\n let psz = 0\n // Skip and count leading '1's.\n let zeroes = 0\n let length = 0\n while (source[psz] === LEADER) {\n zeroes++\n psz++\n }\n // Allocate enough space in big-endian base256 representation.\n const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.\n const b256 = new Uint8Array(size)\n // Process the characters.\n while (psz < source.length) {\n // Find code of next character\n const charCode = source.charCodeAt(psz)\n // Base map can not be indexed using char code\n if (charCode > 255) { return }\n // Decode character\n let carry = BASE_MAP[charCode]\n // Invalid character\n if (carry === 255) { return }\n let i = 0\n for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {\n carry += (BASE * b256[it3]) >>> 0\n b256[it3] = (carry % 256) >>> 0\n carry = (carry / 256) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n psz++\n }\n // Skip leading zeroes in b256.\n let it4 = size - length\n while (it4 !== size && b256[it4] === 0) {\n it4++\n }\n const vch = new Uint8Array(zeroes + (size - it4))\n let j = zeroes\n while (it4 !== size) {\n vch[j++] = b256[it4++]\n }\n return vch\n }\n function decode (string) {\n const buffer = decodeUnsafe(string)\n if (buffer) { return buffer }\n throw new Error('Non-base' + BASE + ' character')\n }\n return {\n encode,\n decodeUnsafe,\n decode\n }\n}\nexport default base\n","import basex from 'base-x';\nvar ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\nexport default basex(ALPHABET);\n","import { LITERAL } from \"../constants.js\";\r\nimport {\r\n toHex,\r\n toBase64,\r\n encodeVarint,\r\n decodeVarint,\r\n utf8Encode,\r\n utf8Decode,\r\n} from \"../utils/buffer.js\";\r\nimport type { EncodeResult, WordBinDictionary } from \"../types.js\";\r\nimport { buildDictionary } from \"../dict/builder.js\";\r\nimport {\r\n loadDictionaryByVersion,\r\n loadLatestDictionary,\r\n getAllAvailableDictionaryVersions,\r\n} from \"../dict/dictionary-loader.js\";\r\nimport bs58 from \"bs58\";\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ntype PayloadFormat = \"bytes\" | \"base58\" | \"base64\" | \"hex\" | \"bin21\";\r\n\r\nexport interface DecodeResult {\r\n /** The decoded text — words for WordBin payloads, best-effort for others. */\r\n text: string;\r\n /** True only when the payload was a valid, fully-parsed WordBin stream. */\r\n isWordBin: boolean;\r\n /** Auto-detected wire format of the input. */\r\n detectedFormat: PayloadFormat;\r\n /**\r\n * Human-readable notice when the payload is not a valid WordBin stream.\r\n * Includes information about what the decoder did as a fallback.\r\n */\r\n notice?: string;\r\n /**\r\n * Present when partial scanning was used (non-WordBin payloads).\r\n * Lists raw byte sequences that had no dictionary match, in order.\r\n */\r\n rawSegments?: string[];\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/** Standard hex encoding — every byte zero-padded to exactly 2 chars. */\r\nfunction bytesToHex(bytes: Uint8Array): string {\r\n return Array.from(bytes)\r\n .map((b) => b.toString(16).padStart(2, \"0\"))\r\n .join(\"\");\r\n}\r\n\r\n// ─── Payload format detection ─────────────────────────────────────────────────\r\n\r\n/**\r\n * Detects the wire format of a string payload and converts it to raw bytes.\r\n *\r\n * Priority:\r\n * 1. Pure hex string (only 0-9 a-f, even length)\r\n * 2. Base58 (only Base58 alphabet chars)\r\n * 3. Base64 / Base64url\r\n * 4. Binary / Latin-1 (bin21Payload / payload field from encode())\r\n */\r\nfunction detectAndConvert(payload: string): {\r\n buffer: Uint8Array;\r\n detectedFormat: PayloadFormat;\r\n} {\r\n // 1. Hex\r\n if (/^[0-9a-fA-F]+$/.test(payload) && payload.length % 2 === 0) {\r\n const bytes = Uint8Array.from(\r\n payload.match(/.{1,2}/g)!.map((h) => parseInt(h, 16)),\r\n );\r\n return { buffer: bytes, detectedFormat: \"hex\" };\r\n }\r\n\r\n // 2. Base58\r\n const base58Re =\r\n /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/;\r\n if (base58Re.test(payload)) {\r\n try {\r\n return { buffer: bs58.decode(payload), detectedFormat: \"base58\" };\r\n } catch {\r\n /* fall through */\r\n }\r\n }\r\n\r\n // 3. Base64 / Base64url\r\n const b64Re =\r\n /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;\r\n const b64urlRe =\r\n /^(?:[A-Za-z0-9\\-_]{4})*(?:[A-Za-z0-9\\-_]{2}(?:==)?|[A-Za-z0-9\\-_]{3}=?|[A-Za-z0-9\\-_]{4})$/;\r\n const norm = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\r\n const padded =\r\n norm + (norm.length % 4 ? \"=\".repeat(4 - (norm.length % 4)) : \"\");\r\n if (b64Re.test(payload) || b64urlRe.test(payload)) {\r\n try {\r\n const bin = atob(padded);\r\n return {\r\n buffer: Uint8Array.from(bin, (c) => c.charCodeAt(0)),\r\n detectedFormat: \"base64\",\r\n };\r\n } catch {\r\n /* fall through */\r\n }\r\n }\r\n\r\n // 4. Binary / Latin-1\r\n const bytes = new Uint8Array(payload.length);\r\n for (let i = 0; i < payload.length; i++) bytes[i] = payload.charCodeAt(i);\r\n return { buffer: bytes, detectedFormat: \"bin21\" };\r\n}\r\n\r\n// ─── WordBin ──────────────────────────────────────────────────────────────────\r\n\r\nexport class WordBin {\r\n private primaryDictVersion: number;\r\n private log: (...args: any[]) => void;\r\n\r\n constructor(initialDict?: WordBinDictionary, options?: { debug?: boolean }) {\r\n this.primaryDictVersion = initialDict?.version ?? 1;\r\n this.log = options?.debug\r\n ? (...args: any[]) => console.log(\"[WordBin]\", ...args)\r\n : () => {};\r\n }\r\n\r\n static async createFromWords(words: string[]): Promise<WordBin> {\r\n console.warn(\r\n \"Building dictionary from scratch – consider using pre-built files\",\r\n );\r\n return new WordBin(await buildDictionary(words));\r\n }\r\n\r\n static async createFromJson(dictJson: WordBinDictionary): Promise<WordBin> {\r\n return new WordBin(dictJson);\r\n }\r\n\r\n static async create(options?: { debug?: boolean }): Promise<WordBin> {\r\n return new WordBin(await loadLatestDictionary(), options);\r\n }\r\n\r\n private async getMapsForVersion(version: number): Promise<{\r\n reverseMap: Map<string, string>;\r\n forwardMap: Map<string, Uint8Array>;\r\n sortedIdLengths: number[];\r\n }> {\r\n const dict = await loadDictionaryByVersion(version);\r\n const reverseMap = new Map<string, string>();\r\n const forwardMap = new Map<string, Uint8Array>();\r\n const idLengths = new Set<number>();\r\n\r\n for (const [hex, words] of Object.entries(dict.words)) {\r\n if (!words.length) continue;\r\n if (words.length > 1) {\r\n throw new Error(\r\n `Dictionary corruption: ID ${hex} maps to multiple words`,\r\n );\r\n }\r\n const word = words[0];\r\n const bytes = Buffer.from(hex, \"hex\");\r\n idLengths.add(bytes.length);\r\n reverseMap.set(hex, word);\r\n forwardMap.set(word, bytes);\r\n }\r\n\r\n return {\r\n reverseMap,\r\n forwardMap,\r\n sortedIdLengths: Array.from(idLengths).sort((a, b) => b - a),\r\n };\r\n }\r\n\r\n // ── encode ──────────────────────────────────────────────────────────────────\r\n\r\n async encode(\r\n text: string | EncodeResult | Uint8Array,\r\n options?: { dictVersion?: number },\r\n ): Promise<EncodeResult> {\r\n let textStr: string;\r\n if (typeof text === \"string\") {\r\n textStr = text;\r\n } else if (text instanceof Uint8Array) {\r\n textStr = toBase64(text);\r\n } else {\r\n textStr = text.base64Payload;\r\n }\r\n\r\n const trimmed = textStr.trim();\r\n if (!trimmed) {\r\n return {\r\n originalText: \"\",\r\n dictVersion: this.primaryDictVersion,\r\n encoded: new Uint8Array(0),\r\n payload: \"\",\r\n bin21: \"\",\r\n bin21Payload: \"\",\r\n base64Payload: \"\",\r\n hexPayload: \"\",\r\n base58Payload: \"\",\r\n originalBytes: 0,\r\n encodedBytes: 0,\r\n bytesSaved: 0,\r\n ratioPercent: 100,\r\n };\r\n }\r\n\r\n const useVersion = options?.dictVersion ?? this.primaryDictVersion;\r\n const { forwardMap } = await this.getMapsForVersion(useVersion);\r\n const chunks: Uint8Array[] = [new Uint8Array([useVersion])];\r\n\r\n for (const w of trimmed.split(/\\s+/).filter(Boolean)) {\r\n const id = forwardMap.get(w);\r\n if (id) {\r\n chunks.push(id);\r\n } else {\r\n const utf8 = utf8Encode(w);\r\n const lenVarint = encodeVarint(utf8.length);\r\n const out = new Uint8Array(1 + lenVarint.length + utf8.length);\r\n out[0] = LITERAL;\r\n out.set(lenVarint, 1);\r\n out.set(utf8, 1 + lenVarint.length);\r\n chunks.push(out);\r\n }\r\n }\r\n\r\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n const originalBytes = new TextEncoder().encode(textStr).length;\r\n\r\n // ── All payload representations derived directly from `result` ────────────\r\n // hexPayload: standard lowercase hex, 2 chars per byte, zero-padded.\r\n const hexPayload = bytesToHex(result);\r\n\r\n // bin21Payload / payload: Latin-1 string, 1 char per byte.\r\n const bin21Payload = Array.from(result)\r\n .map((b) => String.fromCharCode(b))\r\n .join(\"\");\r\n\r\n // base64: via existing toBase64 util.\r\n const base64Payload = toBase64(result);\r\n\r\n // base58: directly from the raw result bytes.\r\n const base58Payload = bs58.encode(result);\r\n\r\n return {\r\n originalText: textStr,\r\n dictVersion: useVersion,\r\n encoded: result,\r\n bin21: bin21Payload,\r\n payload: bin21Payload,\r\n bin21Payload,\r\n hexPayload,\r\n base64Payload,\r\n base58Payload,\r\n originalBytes,\r\n encodedBytes: bin21Payload.length,\r\n bytesSaved: originalBytes - bin21Payload.length,\r\n ratioPercent:\r\n Math.round((bin21Payload.length / originalBytes) * 10000) / 100,\r\n };\r\n }\r\n\r\n // ── decode ───────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Decodes any supported payload format back to human-readable text.\r\n *\r\n * For valid WordBin payloads: returns the exact original words.\r\n * For non-WordBin payloads: scans byte-by-byte, extracts dictionary words\r\n * wherever possible, and preserves unrecognised\r\n * bytes as \"[0xXX]\" markers.\r\n */\r\n async decode(payload: Uint8Array | string): Promise<DecodeResult> {\r\n // ── Step 1: wire-format → raw bytes ───────────────────────────────────────\r\n let buffer: Uint8Array;\r\n let detectedFormat: PayloadFormat;\r\n\r\n if (payload instanceof Uint8Array) {\r\n buffer = payload;\r\n detectedFormat = \"bytes\";\r\n } else {\r\n ({ buffer, detectedFormat } = detectAndConvert(payload));\r\n }\r\n\r\n this.log(\r\n `[decode] format=${detectedFormat} bufLen=${buffer.length} ` +\r\n `firstBytes=[${Array.from(buffer.slice(0, 8)).join(\",\")}]`,\r\n );\r\n\r\n if (buffer.length < 1) {\r\n return {\r\n text: \"\",\r\n isWordBin: false,\r\n detectedFormat,\r\n notice: \"Payload is empty — nothing to decode.\",\r\n };\r\n }\r\n\r\n // ── Step 2: try every installed dictionary (strict WordBin parse) ──────────\r\n //\r\n // For each version we try two start positions:\r\n // pos=1 treat byte[0] as the version header and skip it\r\n // pos=0 treat the entire buffer as payload (no header present)\r\n const availableVersions = await getAllAvailableDictionaryVersions();\r\n const versionByte = buffer[0];\r\n const versionIsHeader = availableVersions.includes(versionByte);\r\n\r\n this.log(\r\n `[decode] availableVersions=[${availableVersions.join(\",\")}] ` +\r\n `versionByte=${versionByte} isKnownHeader=${versionIsHeader}`,\r\n );\r\n\r\n // Put the version that matches byte[0] first so the fast path is tried first.\r\n const tryOrder = versionIsHeader\r\n ? [versionByte, ...availableVersions.filter((v) => v !== versionByte)]\r\n : [...availableVersions];\r\n\r\n for (const ver of tryOrder) {\r\n let maps: { reverseMap: Map<string, string>; sortedIdLengths: number[] };\r\n try {\r\n maps = await this.getMapsForVersion(ver);\r\n } catch (err) {\r\n this.log(`[decode] v${ver}: getMapsForVersion threw — ${err}`);\r\n continue;\r\n }\r\n const { reverseMap, sortedIdLengths } = maps;\r\n\r\n // pos=1: standard WordBin stream with header byte\r\n const r1 =\r\n this.greedyDecode(buffer, 1, reverseMap, sortedIdLengths) ??\r\n this.tryDecode(1, buffer, reverseMap, [], 0, sortedIdLengths);\r\n this.log(\r\n `[decode] v${ver} strict(pos=1): ${r1 !== null ? `\"${r1}\"` : \"null\"}`,\r\n );\r\n if (r1 !== null) {\r\n const notice =\r\n versionByte === ver\r\n ? undefined\r\n : `Byte[0]=${versionByte} is not a recognised version header but ` +\r\n `decoded successfully with dictionary v${ver}.`;\r\n return { text: r1, isWordBin: true, detectedFormat, notice };\r\n }\r\n\r\n // pos=0: payload with no header byte\r\n const r0 =\r\n this.greedyDecode(buffer, 0, reverseMap, sortedIdLengths) ??\r\n this.tryDecode(0, buffer, reverseMap, [], 0, sortedIdLengths);\r\n this.log(\r\n `[decode] v${ver} strict(pos=0): ${r0 !== null ? `\"${r0}\"` : \"null\"}`,\r\n );\r\n if (r0 !== null) {\r\n return {\r\n text: r0,\r\n isWordBin: true,\r\n detectedFormat,\r\n notice: `Payload had no version header. Decoded using dictionary v${ver}.`,\r\n };\r\n }\r\n }\r\n\r\n // ── Step 3: partial / best-effort scan ────────────────────────────────────\r\n //\r\n // No strict parse succeeded. Scan byte-by-byte across every available\r\n // dictionary and extract words wherever the bytes match a dictionary ID.\r\n // Bytes that match nothing are preserved as \"[0xXX]\" markers.\r\n // This ensures the decoder never silently discards data.\r\n this.log(`[decode] strict parse failed — falling back to partial scan`);\r\n\r\n if (availableVersions.length > 0) {\r\n // Use the latest available dictionary for the scan.\r\n const scanVersion = availableVersions[availableVersions.length - 1];\r\n try {\r\n const { reverseMap, sortedIdLengths } =\r\n await this.getMapsForVersion(scanVersion);\r\n\r\n // Try scanning from pos=1 (skip possible header) and pos=0, pick the\r\n // one that recognises more words.\r\n const scan1 = this.partialScan(buffer, 1, reverseMap, sortedIdLengths);\r\n const scan0 = this.partialScan(buffer, 0, reverseMap, sortedIdLengths);\r\n const best = scan1.wordCount >= scan0.wordCount ? scan1 : scan0;\r\n\r\n this.log(\r\n `[decode] partial scan(pos=1) words=${scan1.wordCount} raw=${scan1.rawSegments.length}` +\r\n ` | scan(pos=0) words=${scan0.wordCount} raw=${scan0.rawSegments.length}`,\r\n );\r\n\r\n const notice =\r\n `This does not appear to be a valid WordBin payload. ` +\r\n `Partial scan using dictionary v${scanVersion} extracted ` +\r\n `${best.wordCount} word(s); ${best.rawSegments.length} byte ` +\r\n `sequence(s) had no dictionary match and are shown as [0xXX] markers.`;\r\n\r\n return {\r\n text: best.text,\r\n isWordBin: false,\r\n detectedFormat,\r\n rawSegments: best.rawSegments,\r\n notice,\r\n };\r\n } catch {\r\n /* fall through to plain UTF-8 */\r\n }\r\n }\r\n\r\n // ── Step 4: plain UTF-8 last resort ───────────────────────────────────────\r\n const notice =\r\n `Could not decode with any available dictionary ` +\r\n `(tried: ${availableVersions.join(\", \") || \"none\"}). ` +\r\n `Falling back to UTF-8 text decoding.`;\r\n this.log(`[decode] ${notice}`);\r\n return {\r\n text: new TextDecoder(\"utf-8\", { fatal: false }).decode(buffer),\r\n isWordBin: false,\r\n detectedFormat,\r\n notice,\r\n };\r\n }\r\n\r\n // ── Private: greedy linear decode ────────────────────────────────────────────\r\n\r\n /**\r\n * O(n) longest-match-first decode. Returns null if any byte has no match.\r\n * This is the fast path; tryDecode is used as a backtracking fallback.\r\n */\r\n private greedyDecode(\r\n buffer: Uint8Array,\r\n startPos: number,\r\n reverseMap: Map<string, string>,\r\n sortedIdLengths: number[],\r\n ): string | null {\r\n const words: string[] = [];\r\n let pos = startPos;\r\n\r\n while (pos < buffer.length) {\r\n if (buffer[pos] === LITERAL) {\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n if (byteLen > 1_000_000 || byteLen < 0) return null;\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n if (end > buffer.length) return null;\r\n words.push(utf8Decode(buffer.subarray(start, end)));\r\n pos = end;\r\n continue;\r\n }\r\n\r\n let matched = false;\r\n for (const len of sortedIdLengths) {\r\n if (pos + len > buffer.length) continue;\r\n const key = toHex(buffer.subarray(pos, pos + len));\r\n if (reverseMap.has(key)) {\r\n words.push(reverseMap.get(key)!);\r\n pos += len;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n if (!matched) return null;\r\n }\r\n\r\n return words.join(\" \");\r\n }\r\n\r\n // ── Private: partial / best-effort scan ──────────────────────────────────────\r\n\r\n /**\r\n * Scans through the buffer extracting any recognised dictionary words.\r\n * Unrecognised bytes are collected as raw segments and rendered as [0xXX].\r\n * Always consumes the entire buffer — never returns null.\r\n */\r\n private partialScan(\r\n buffer: Uint8Array,\r\n startPos: number,\r\n reverseMap: Map<string, string>,\r\n sortedIdLengths: number[],\r\n ): { text: string; wordCount: number; rawSegments: string[] } {\r\n const parts: string[] = [];\r\n const rawSegments: string[] = [];\r\n let wordCount = 0;\r\n let pos = startPos;\r\n\r\n while (pos < buffer.length) {\r\n // Try LITERAL token\r\n if (buffer[pos] === LITERAL && pos + 1 < buffer.length) {\r\n try {\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n if (byteLen > 0 && byteLen <= 1_000_000) {\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n if (end <= buffer.length) {\r\n const word = utf8Decode(buffer.subarray(start, end));\r\n parts.push(word);\r\n wordCount++;\r\n pos = end;\r\n continue;\r\n }\r\n }\r\n } catch {\r\n /* malformed varint — treat as raw byte */\r\n }\r\n }\r\n\r\n // Try dictionary IDs (longest first)\r\n let matched = false;\r\n for (const len of sortedIdLengths) {\r\n if (pos + len > buffer.length) continue;\r\n const key = toHex(buffer.subarray(pos, pos + len));\r\n if (reverseMap.has(key)) {\r\n parts.push(reverseMap.get(key)!);\r\n wordCount++;\r\n pos += len;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!matched) {\r\n // No match — emit this byte as a hex marker and advance by 1\r\n const marker = `[0x${buffer[pos].toString(16).padStart(2, \"0\")}]`;\r\n parts.push(marker);\r\n rawSegments.push(marker);\r\n this.log(\r\n `[decode] partial scan: no match at pos=${pos} byte=${buffer[pos]}`,\r\n );\r\n pos++;\r\n }\r\n }\r\n\r\n return { text: parts.join(\" \"), wordCount, rawSegments };\r\n }\r\n\r\n // ── Private: backtracking decode ─────────────────────────────────────────────\r\n\r\n private tryDecode(\r\n pos: number,\r\n buffer: Uint8Array,\r\n reverseMap: Map<string, string>,\r\n result: string[],\r\n depth: number,\r\n sortedIdLengths: number[],\r\n ): string | null {\r\n if (pos === buffer.length) return result.join(\" \");\r\n\r\n if (buffer[pos] === LITERAL) {\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n if (byteLen > 1_000_000 || byteLen < 0) return null;\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n if (end > buffer.length) return null;\r\n result.push(utf8Decode(buffer.subarray(start, end)));\r\n const res = this.tryDecode(\r\n end,\r\n buffer,\r\n reverseMap,\r\n result,\r\n depth + 1,\r\n sortedIdLengths,\r\n );\r\n if (res !== null) return res;\r\n result.pop();\r\n }\r\n\r\n for (const len of sortedIdLengths) {\r\n if (pos + len > buffer.length) continue;\r\n const key = toHex(buffer.subarray(pos, pos + len));\r\n if (reverseMap.has(key)) {\r\n result.push(reverseMap.get(key)!);\r\n const res = this.tryDecode(\r\n pos + len,\r\n buffer,\r\n reverseMap,\r\n result,\r\n depth + 1,\r\n sortedIdLengths,\r\n );\r\n if (res !== null) return res;\r\n result.pop();\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n"],"names":["__filename","__dirname","ALPHABET","basex","bytes","notice"],"mappings":"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","x_google_ignoreList":[2,3]}
package/dist/types.d.ts CHANGED
@@ -5,16 +5,20 @@ export interface WordBinDictionary {
5
5
  }
6
6
  export interface EncodeResult {
7
7
  originalText: string;
8
- payload: string;
9
8
  encoded: Uint8Array;
10
9
  dictVersion: number;
11
- encodedBase64: string;
10
+ payload: string | Uint8Array;
11
+ bin21: string | Uint8Array;
12
+ bin21Payload: string | Uint8Array;
13
+ hexPayload: string;
14
+ base58Payload: string;
15
+ base64Payload: string;
12
16
  originalBytes: number;
13
17
  encodedBytes: number;
14
18
  bytesSaved: number;
15
19
  ratioPercent: number;
16
20
  wrapped?: {
17
- encodedBase64: string;
21
+ base64Payload: string;
18
22
  encodedBytes: number;
19
23
  bytesSaved: number;
20
24
  ratioPercent: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigdreamsweb3/wordbin",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "WordBin – Encode words & short text into tiny, reversible binary for storage, URLs, IoT, QR codes, metadata, blockchain, or Web3 apps.",
5
5
  "author": "Agbaka Daniel Ugonna <99cratson@gmail.com>",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "scripts": {
41
41
  "build": "vite build",
42
- "build:dict:v1": "npx tsx scripts/dictionaries/build-v1-bip39.mts",
42
+ "build:dict:v1": "npx tsx scripts/dictionaries/build-v1-bip39.ts",
43
43
  "build:dict:v2": "npx tsx scripts/dictionaries/build-v2-dwyl.ts",
44
44
  "build:dict:all": "npm run build:dict:v1 && npm run build:dict:v2",
45
45
  "clean": "rimraf dist",
@@ -56,7 +56,8 @@
56
56
  "git-pull-origin-main": "git pull origin main --force"
57
57
  },
58
58
  "dependencies": {
59
- "bip39": "^3.1.0"
59
+ "bip39": "^3.1.0",
60
+ "bs58": "^6.0.0"
60
61
  },
61
62
  "devDependencies": {
62
63
  "@types/node": "^20.11.30",
package/dist/core.d.ts DELETED
@@ -1,19 +0,0 @@
1
- import { EncodeResult, WordBinDictionary } from './types';
2
- export declare class WordBin {
3
- private primaryDictVersion;
4
- private log;
5
- constructor(initialDict?: WordBinDictionary, options?: {
6
- debug?: boolean;
7
- });
8
- static createFromWords(words: string[]): Promise<WordBin>;
9
- static createFromJson(dictJson: WordBinDictionary): Promise<WordBin>;
10
- static create(options?: {
11
- debug?: boolean;
12
- }): Promise<WordBin>;
13
- private getMapsForVersion;
14
- encode(text: string | EncodeResult | Uint8Array, options?: {
15
- dictVersion?: number;
16
- }): Promise<EncodeResult>;
17
- decode(data: Uint8Array | string): Promise<string>;
18
- private tryDecode;
19
- }