@bigdreamsweb3/wordbin 1.0.6 → 1.0.8
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.
- package/CONTRIBUTING.md +156 -67
- package/README.md +364 -149
- package/dist/{dictionary-D3gr2Ala.js → builder-vFphFQMU.js} +16 -19
- package/dist/builder-vFphFQMU.js.map +1 -0
- package/dist/cli.mjs +1 -1
- package/dist/core/binary-payload.d.ts +6 -0
- package/dist/core/comp/latin1-compressor.d.ts +9 -0
- package/dist/core/comp/onebyte-encoder.d.ts +2 -0
- package/dist/core/index.d.ts +58 -0
- package/dist/data/wordbin-v1-bip39.json +13 -11
- package/dist/{dictionary.d.ts → dict/builder.d.ts} +1 -1
- package/dist/{dictionary-loader.d.ts → dict/dictionary-loader.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +425 -142
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +7 -3
- package/package.json +6 -2
- package/dist/core.d.ts +0 -19
- package/dist/dictionary-D3gr2Ala.js.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/constants.ts","../src/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 { generateWordId } from \"./core/id.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 \"./dictionary.js\";\r\nimport {\r\n loadDictionaryByVersion,\r\n loadLatestDictionary,\r\n} from \"./dictionary-loader.js\";\r\n\r\nexport class WordBin {\r\n private primaryDictVersion: number;\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 private log: (...args: any[]) => void;\r\n\r\n static async createFromWords(words: string[]): Promise<WordBin> {\r\n console.warn(\"Building dictionary from scratch – consider pre-built files\");\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 getReverseMapForVersion(\r\n version: number,\r\n ): Promise<Map<string, string>> {\r\n const dict = await loadDictionaryByVersion(version);\r\n const reverseMap = new Map<string, string>();\r\n for (const [hex, words] of Object.entries(dict.words)) {\r\n if (words.length > 0) reverseMap.set(hex, words[0]);\r\n }\r\n return reverseMap;\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\") textStr = text;\r\n else if (text instanceof Uint8Array) textStr = toBase64(text);\r\n else textStr = text.encodedBase64;\r\n\r\n if (!textStr.trim()) {\r\n return {\r\n originalText: \"\",\r\n dictVersion: 0,\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 = textStr.split(/\\s+/).filter(Boolean);\r\n this.log(`[encode] Input words (${words.length}):`, words);\r\n\r\n const useVersion = options.dictVersion ?? this.primaryDictVersion;\r\n this.log(`[encode] Using dictionary version: ${useVersion}`);\r\n\r\n // ──────────────────────────────────────────────\r\n // Header: just the version byte (no magic bytes)\r\n // ──────────────────────────────────────────────\r\n const header = new Uint8Array([useVersion]);\r\n\r\n this.log(`[encode] Header bytes: [${[...header].join(\", \")}]`);\r\n this.log(`[encode] Header hex: ${toHex(header)}`);\r\n\r\n const chunks: Uint8Array[] = [header];\r\n\r\n const reverseMap = await this.getReverseMapForVersion(useVersion);\r\n this.log(`[encode] Reverse map loaded — size: ${reverseMap.size} entries`);\r\n\r\n // ──────────────────────────────────────────────\r\n // Process each word\r\n // ──────────────────────────────────────────────\r\n this.log(\"[encode] Word → ID mapping:\");\r\n\r\n for (const w of words) {\r\n const id = await generateWordId(w);\r\n const key = toHex(id);\r\n\r\n this.log(` \"${w}\" → ID bytes: [${[...id].join(\", \")}] | hex: ${key}`);\r\n\r\n if (reverseMap.has(key)) {\r\n const mappedWord = reverseMap.get(key);\r\n this.log(` → Found in dictionary → using ${id.length}-byte ID`);\r\n chunks.push(id);\r\n } else {\r\n const utf8 = utf8Encode(w);\r\n const lenVarint = encodeVarint(utf8.length);\r\n this.log(` → NOT in dictionary → literal mode`);\r\n this.log(\r\n ` Literal length varint bytes: [${[...lenVarint].join(\", \")}] (value = ${utf8.length})`,\r\n );\r\n this.log(` Word UTF-8 bytes length: ${utf8.length}`);\r\n\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\r\n this.log(` Literal chunk bytes: [${[...out].join(\", \")}]`);\r\n chunks.push(out);\r\n }\r\n }\r\n\r\n // ──────────────────────────────────────────────\r\n // Final assembly\r\n // ──────────────────────────────────────────────\r\n const totalLength = chunks.reduce((n, c) => n + c.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n\r\n this.log(`[encode] Total encoded length: ${totalLength} bytes`);\r\n\r\n let off = 0;\r\n chunks.forEach((chunk, i) => {\r\n result.set(chunk, off);\r\n off += chunk.length;\r\n this.log(\r\n ` Chunk ${i}: ${chunk.length} bytes → offset ${off - chunk.length}`,\r\n );\r\n });\r\n\r\n this.log(\r\n `[encode] Final encoded bytes (first 32): [${[...result.subarray(0, Math.min(32, result.length))].join(\", \")}]`,\r\n );\r\n\r\n const originalBytes = new TextEncoder().encode(textStr).length;\r\n\r\n const base64Result = toBase64(result);\r\n this.log(`[encode] Base64 starts with: ${base64Result.slice(0, 12)}...`);\r\n\r\n return {\r\n originalText: textStr,\r\n dictVersion: result[0],\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),\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 this.log(\r\n `[decode] Input is base64 string: \"${data.substring(0, 20)}...\"`,\r\n );\r\n buffer = fromBase64(data);\r\n this.log(`[decode] Decoded to ${buffer.length} bytes`);\r\n } else {\r\n buffer = data;\r\n this.log(`[decode] Input is Uint8Array with ${buffer.length} bytes`);\r\n }\r\n\r\n this.log(`[decode] Full buffer hex: ${toHex(buffer)}`);\r\n this.log(\r\n `[decode] First 16 bytes: [${[...buffer.subarray(0, Math.min(16, buffer.length))].join(\", \")}]`,\r\n );\r\n\r\n if (buffer.length < 1) {\r\n throw new Error(\"Data too short\");\r\n }\r\n\r\n const version = buffer[0];\r\n this.log(`[decode] Dictionary version from header: ${version}`);\r\n\r\n // Optional: basic sanity check (you can adjust or remove)\r\n if (version < 1 || version > 100) {\r\n this.log(`[decode] Warning: unusual dictionary version ${version}`);\r\n // You can throw here if you want strict validation:\r\n // throw new Error(`Unreasonable dictionary version: ${version}`);\r\n }\r\n\r\n let pos = 1; // payload starts right after the version byte\r\n this.log(`[decode] Starting decode at position ${pos}`);\r\n\r\n const reverseMap = await this.getReverseMapForVersion(version);\r\n this.log(\r\n `[decode] Reverse map loaded for v${version} — size: ${reverseMap.size} entries`,\r\n );\r\n\r\n this.log(`[decode] ===== STARTING DECODE LOOP =====`);\r\n\r\n const result: string[] = [];\r\n const decoded = this.tryDecode(pos, buffer, reverseMap, result, 0);\r\n\r\n if (decoded === null) {\r\n throw new Error(\r\n \"No valid decode path found — possible corruption or dictionary mismatch\",\r\n );\r\n }\r\n\r\n this.log(`\\n[decode] ===== DECODE COMPLETE =====`);\r\n this.log(`[decode] Total words decoded: ${result.length}`);\r\n this.log(`[decode] Final result: \"${decoded}\"`);\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 ): string | null {\r\n const indent = \" \".repeat(depth);\r\n this.log(`${indent}[tryDecode] At position ${pos} (depth ${depth})`);\r\n\r\n if (pos === buffer.length) {\r\n this.log(`${indent}[tryDecode] Reached end successfully`);\r\n return result.join(\" \");\r\n }\r\n\r\n const previewLen = Math.min(8, buffer.length - pos);\r\n const preview = [...buffer.subarray(pos, pos + previewLen)]\r\n .map((b) => `0x${b.toString(16).padStart(2, \"0\")}`)\r\n .join(\" \");\r\n this.log(`${indent}[tryDecode] Next ${previewLen} bytes: ${preview}`);\r\n\r\n // Try literal first\r\n if (buffer[pos] === LITERAL) {\r\n this.log(\r\n `${indent}[tryDecode] Found LITERAL marker (0x${LITERAL.toString(16)})`,\r\n );\r\n\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n this.log(\r\n `${indent}[tryDecode] Varint: value=${byteLen}, bytesRead=${bytesRead}`,\r\n );\r\n\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n this.log(\r\n `${indent}[tryDecode] Literal range: [${start}..${end}) (${byteLen} bytes)`,\r\n );\r\n\r\n if (end > buffer.length) {\r\n this.log(`${indent}[tryDecode] Truncated literal — failing path`);\r\n return null;\r\n }\r\n\r\n const literalBytes = buffer.subarray(start, end);\r\n const word = utf8Decode(literalBytes);\r\n this.log(`${indent}[tryDecode] Decoded literal: \"${word}\"`);\r\n\r\n result.push(word);\r\n const res = this.tryDecode(end, buffer, reverseMap, result, depth + 1);\r\n if (res !== null) return res;\r\n result.pop();\r\n this.log(`${indent}[tryDecode] Backtracking from literal`);\r\n return null;\r\n }\r\n\r\n // Try dictionary matches (longest first)\r\n for (const len of [4, 3, 2]) {\r\n if (pos + len > buffer.length) {\r\n this.log(`${indent}[tryDecode] Skipping ${len}-byte (would exceed)`);\r\n continue;\r\n }\r\n\r\n const slice = buffer.subarray(pos, pos + len);\r\n const key = toHex(slice);\r\n const keyBytes = [...slice]\r\n .map((b) => `0x${b.toString(16).padStart(2, \"0\")}`)\r\n .join(\" \");\r\n\r\n this.log(\r\n `${indent}[tryDecode] Trying ${len}-byte: [${keyBytes}] hex=${key}`,\r\n );\r\n\r\n if (reverseMap.has(key)) {\r\n const word = reverseMap.get(key)!;\r\n this.log(`${indent}[tryDecode] Match: \"${word}\" (ID: ${key})`);\r\n\r\n result.push(word);\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 );\r\n if (res !== null) return res;\r\n result.pop();\r\n this.log(`${indent}[tryDecode] Backtracking from \"${word}\"`);\r\n } else {\r\n this.log(`${indent}[tryDecode] No match for ${key}`);\r\n }\r\n }\r\n\r\n this.log(`${indent}[tryDecode] No valid branches — failing path`);\r\n return null;\r\n }\r\n}\r\n"],"names":["__filename","__dirname"],"mappings":";;;;AACO,MAAM,QAAQ,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;AACrC,MAAM,UAAU;ACGvB,MAAMA,eAAa,cAAc,YAAY,GAAG;AAChD,MAAMC,cAAY,KAAK,QAAQD,YAAU;AAGzC,MAAM,mBAAmB,KAAK,KAAKC,aAAW,MAAM;AAGpD,MAAM,iBAAiB,KAAK,KAAK,QAAQ,IAAA,GAAO,MAAM;AAMtD,eAAe,sBAAyC;AACtD,QAAM,OAAiB,CAAA;AAEvB,MAAI;AACF,UAAM,GAAG,OAAO,cAAc;AAC9B,SAAK,KAAK,cAAc;AAAA,EAC1B,QAAQ;AAAA,EAAC;AAET,MAAI;AACF,UAAM,GAAG,OAAO,gBAAgB;AAChC,SAAK,KAAK,gBAAgB;AAAA,EAC5B,QAAQ;AAAA,EAAC;AAET,SAAO;AACT;AAKA,eAAsB,oCAAuD;AAC3E,QAAM,OAAO,MAAM,oBAAA;AACnB,QAAM,+BAAe,IAAA;AAErB,aAAW,OAAO,MAAM;AACtB,QAAI;AACF,YAAM,QAAQ,MAAM,GAAG,QAAQ,GAAG;AAElC,iBAAW,QAAQ,OAAO;AACxB,cAAM,QAAQ,KAAK,MAAM,iBAAiB;AAC1C,YAAI,OAAO;AACT,mBAAS,IAAI,SAAS,MAAM,CAAC,GAAG,EAAE,CAAC;AAAA,QACrC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAClD;AAMA,eAAsB,wBACpB,SAC4B;AAC5B,QAAM,OAAO,MAAM,oBAAA;AAEnB,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,MAAM,GAAG,QAAQ,GAAG;AAElC,UAAM,cAAc,MAAM;AAAA,MAAK,CAAC,MAC9B,EAAE,MAAM,IAAI,OAAO,YAAY,OAAO,aAAa,GAAG,CAAC;AAAA,IAAA;AAGzD,QAAI,aAAa;AACf,YAAM,WAAW,KAAK,KAAK,KAAK,WAAW;AAC3C,YAAM,OAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAChD,YAAM,OAAO,KAAK,MAAM,IAAI;AAE5B,UAAI,KAAK,YAAY,SAAS;AAC5B,cAAM,IAAI;AAAA,UACR,0BAA0B,WAAW,YAAY,KAAK,OAAO,kBAAkB,OAAO;AAAA,QAAA;AAAA,MAE1F;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,kCAAA;AAExB,QAAM,IAAI;AAAA,IACR,sBAAsB,OAAO,mCAAmC,UAAU,KAAK,IAAI,CAAC;AAAA,EAAA;AAExF;AAKA,eAAsB,uBAAmD;AACvE,QAAM,WAAW,MAAM,kCAAA;AAEvB,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,QAAM,gBAAgB,KAAK,IAAI,GAAG,QAAQ;AAE1C,UAAQ;AAAA,IACN,+BAA+B,aAAa,gBAAgB,SAAS,KAAK,IAAI,CAAC;AAAA,EAAA;AAGjF,SAAO,wBAAwB,aAAa;AAC9C;ACxGO,MAAM,QAAQ;AAAA,EAGnB,YAAY,aAAiC,SAA+B;AAC1E,SAAK,qBAAqB,aAAa,WAAW;AAClD,SAAK,MAAM,SAAS,QAChB,IAAI,SAAS,QAAQ,IAAI,aAAa,GAAG,IAAI,IAC7C,MAAM;AAAA,IAAC;AAAA,EACb;AAAA,EAIA,aAAa,gBAAgB,OAAmC;AAC9D,YAAQ,KAAK,6DAA6D;AAC1E,UAAM,OAAO,MAAM,gBAAgB,KAAK;AACxC,WAAO,IAAI,QAAQ,IAAI;AAAA,EACzB;AAAA,EAEA,aAAa,eAAe,UAA+C;AACzE,WAAO,IAAI,QAAQ,QAAQ;AAAA,EAC7B;AAAA,EAEA,aAAa,OAAO,SAAiD;AACnE,UAAM,aAAa,MAAM,qBAAA;AACzB,WAAO,IAAI,QAAQ,YAAY,OAAO;AAAA,EACxC;AAAA,EAEA,MAAc,wBACZ,SAC8B;AAC9B,UAAM,OAAO,MAAM,wBAAwB,OAAO;AAClD,UAAM,iCAAiB,IAAA;AACvB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACrD,UAAI,MAAM,SAAS,EAAG,YAAW,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OACJ,MACA,UAAoC,IACb;AACvB,QAAI;AACJ,QAAI,OAAO,SAAS,SAAU,WAAU;AAAA,aAC/B,gBAAgB,WAAY,WAAU,SAAS,IAAI;AAAA,mBAC7C,KAAK;AAEpB,QAAI,CAAC,QAAQ,QAAQ;AACnB,aAAO;AAAA,QACL,cAAc;AAAA,QACd,aAAa;AAAA,QACb,SAAS,IAAI,WAAW,CAAC;AAAA,QACzB,SAAS;AAAA,QACT,eAAe;AAAA,QACf,eAAe;AAAA,QACf,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,cAAc;AAAA,MAAA;AAAA,IAElB;AAEA,UAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE,OAAO,OAAO;AACjD,SAAK,IAAI,yBAAyB,MAAM,MAAM,MAAM,KAAK;AAEzD,UAAM,aAAa,QAAQ,eAAe,KAAK;AAC/C,SAAK,IAAI,sCAAsC,UAAU,EAAE;AAK3D,UAAM,SAAS,IAAI,WAAW,CAAC,UAAU,CAAC;AAE1C,SAAK,IAAI,2BAA2B,CAAC,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG;AAC7D,SAAK,IAAI,wBAAwB,MAAM,MAAM,CAAC,EAAE;AAEhD,UAAM,SAAuB,CAAC,MAAM;AAEpC,UAAM,aAAa,MAAM,KAAK,wBAAwB,UAAU;AAChE,SAAK,IAAI,uCAAuC,WAAW,IAAI,UAAU;AAKzE,SAAK,IAAI,6BAA6B;AAEtC,eAAW,KAAK,OAAO;AACrB,YAAM,KAAK,MAAM,eAAe,CAAC;AACjC,YAAM,MAAM,MAAM,EAAE;AAEpB,WAAK,IAAI,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,YAAY,GAAG,EAAE;AAErE,UAAI,WAAW,IAAI,GAAG,GAAG;AACJ,mBAAW,IAAI,GAAG;AACrC,aAAK,IAAI,qCAAqC,GAAG,MAAM,UAAU;AACjE,eAAO,KAAK,EAAE;AAAA,MAChB,OAAO;AACL,cAAM,OAAO,WAAW,CAAC;AACzB,cAAM,YAAY,aAAa,KAAK,MAAM;AAC1C,aAAK,IAAI,wCAAwC;AACjD,aAAK;AAAA,UACH,uCAAuC,CAAC,GAAG,SAAS,EAAE,KAAK,IAAI,CAAC,cAAc,KAAK,MAAM;AAAA,QAAA;AAE3F,aAAK,IAAI,kCAAkC,KAAK,MAAM,EAAE;AAExD,cAAM,MAAM,IAAI,WAAW,IAAI,UAAU,SAAS,KAAK,MAAM;AAC7D,YAAI,CAAC,IAAI;AACT,YAAI,IAAI,WAAW,CAAC;AACpB,YAAI,IAAI,MAAM,IAAI,UAAU,MAAM;AAElC,aAAK,IAAI,+BAA+B,CAAC,GAAG,GAAG,EAAE,KAAK,IAAI,CAAC,GAAG;AAC9D,eAAO,KAAK,GAAG;AAAA,MACjB;AAAA,IACF;AAKA,UAAM,cAAc,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAC3D,UAAM,SAAS,IAAI,WAAW,WAAW;AAEzC,SAAK,IAAI,kCAAkC,WAAW,QAAQ;AAE9D,QAAI,MAAM;AACV,WAAO,QAAQ,CAAC,OAAO,MAAM;AAC3B,aAAO,IAAI,OAAO,GAAG;AACrB,aAAO,MAAM;AACb,WAAK;AAAA,QACH,WAAW,CAAC,KAAK,MAAM,MAAM,mBAAmB,MAAM,MAAM,MAAM;AAAA,MAAA;AAAA,IAEtE,CAAC;AAED,SAAK;AAAA,MACH,6CAA6C,CAAC,GAAG,OAAO,SAAS,GAAG,KAAK,IAAI,IAAI,OAAO,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAAA;AAG9G,UAAM,gBAAgB,IAAI,YAAA,EAAc,OAAO,OAAO,EAAE;AAExD,UAAM,eAAe,SAAS,MAAM;AACpC,SAAK,IAAI,gCAAgC,aAAa,MAAM,GAAG,EAAE,CAAC,KAAK;AAEvE,WAAO;AAAA,MACL,cAAc;AAAA,MACd,aAAa,OAAO,CAAC;AAAA,MACrB,SAAS;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA,MACf;AAAA,MACA,cAAc;AAAA,MACd,YAAY,gBAAgB;AAAA,MAC5B,cACE,gBAAgB,IACZ,MACA,KAAK,MAAO,cAAc,gBAAiB,GAAG;AAAA,IAAA;AAAA,EAExD;AAAA,EAEA,MAAM,OAAO,MAA4C;AACvD,QAAI;AACJ,QAAI,OAAO,SAAS,UAAU;AAC5B,WAAK;AAAA,QACH,qCAAqC,KAAK,UAAU,GAAG,EAAE,CAAC;AAAA,MAAA;AAE5D,eAAS,WAAW,IAAI;AACxB,WAAK,IAAI,uBAAuB,OAAO,MAAM,QAAQ;AAAA,IACvD,OAAO;AACL,eAAS;AACT,WAAK,IAAI,qCAAqC,OAAO,MAAM,QAAQ;AAAA,IACrE;AAEA,SAAK,IAAI,6BAA6B,MAAM,MAAM,CAAC,EAAE;AACrD,SAAK;AAAA,MACH,6BAA6B,CAAC,GAAG,OAAO,SAAS,GAAG,KAAK,IAAI,IAAI,OAAO,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAAA;AAG9F,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AAEA,UAAM,UAAU,OAAO,CAAC;AACxB,SAAK,IAAI,4CAA4C,OAAO,EAAE;AAG9D,QAAI,UAAU,KAAK,UAAU,KAAK;AAChC,WAAK,IAAI,gDAAgD,OAAO,EAAE;AAAA,IAGpE;AAEA,QAAI,MAAM;AACV,SAAK,IAAI,wCAAwC,GAAG,EAAE;AAEtD,UAAM,aAAa,MAAM,KAAK,wBAAwB,OAAO;AAC7D,SAAK;AAAA,MACH,oCAAoC,OAAO,YAAY,WAAW,IAAI;AAAA,IAAA;AAGxE,SAAK,IAAI,2CAA2C;AAEpD,UAAM,SAAmB,CAAA;AACzB,UAAM,UAAU,KAAK,UAAU,KAAK,QAAQ,YAAY,QAAQ,CAAC;AAEjE,QAAI,YAAY,MAAM;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,SAAK,IAAI;AAAA,qCAAwC;AACjD,SAAK,IAAI,iCAAiC,OAAO,MAAM,EAAE;AACzD,SAAK,IAAI,2BAA2B,OAAO,GAAG;AAE9C,WAAO;AAAA,EACT;AAAA,EAEQ,UACN,KACA,QACA,YACA,QACA,OACe;AACf,UAAM,SAAS,KAAK,OAAO,KAAK;AAChC,SAAK,IAAI,GAAG,MAAM,2BAA2B,GAAG,WAAW,KAAK,GAAG;AAEnE,QAAI,QAAQ,OAAO,QAAQ;AACzB,WAAK,IAAI,GAAG,MAAM,sCAAsC;AACxD,aAAO,OAAO,KAAK,GAAG;AAAA,IACxB;AAEA,UAAM,aAAa,KAAK,IAAI,GAAG,OAAO,SAAS,GAAG;AAClD,UAAM,UAAU,CAAC,GAAG,OAAO,SAAS,KAAK,MAAM,UAAU,CAAC,EACvD,IAAI,CAAC,MAAM,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,EACjD,KAAK,GAAG;AACX,SAAK,IAAI,GAAG,MAAM,oBAAoB,UAAU,WAAW,OAAO,EAAE;AAGpE,QAAI,OAAO,GAAG,MAAM,SAAS;AAC3B,WAAK;AAAA,QACH,GAAG,MAAM,uCAAuC,QAAQ,SAAS,EAAE,CAAC;AAAA,MAAA;AAGtE,YAAM,EAAE,OAAO,SAAS,UAAA,IAAc,aAAa,QAAQ,MAAM,CAAC;AAClE,WAAK;AAAA,QACH,GAAG,MAAM,6BAA6B,OAAO,eAAe,SAAS;AAAA,MAAA;AAGvE,YAAM,QAAQ,MAAM,IAAI;AACxB,YAAM,MAAM,QAAQ;AACpB,WAAK;AAAA,QACH,GAAG,MAAM,+BAA+B,KAAK,KAAK,GAAG,MAAM,OAAO;AAAA,MAAA;AAGpE,UAAI,MAAM,OAAO,QAAQ;AACvB,aAAK,IAAI,GAAG,MAAM,8CAA8C;AAChE,eAAO;AAAA,MACT;AAEA,YAAM,eAAe,OAAO,SAAS,OAAO,GAAG;AAC/C,YAAM,OAAO,WAAW,YAAY;AACpC,WAAK,IAAI,GAAG,MAAM,iCAAiC,IAAI,GAAG;AAE1D,aAAO,KAAK,IAAI;AAChB,YAAM,MAAM,KAAK,UAAU,KAAK,QAAQ,YAAY,QAAQ,QAAQ,CAAC;AACrE,UAAI,QAAQ,KAAM,QAAO;AACzB,aAAO,IAAA;AACP,WAAK,IAAI,GAAG,MAAM,uCAAuC;AACzD,aAAO;AAAA,IACT;AAGA,eAAW,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG;AAC3B,UAAI,MAAM,MAAM,OAAO,QAAQ;AAC7B,aAAK,IAAI,GAAG,MAAM,wBAAwB,GAAG,sBAAsB;AACnE;AAAA,MACF;AAEA,YAAM,QAAQ,OAAO,SAAS,KAAK,MAAM,GAAG;AAC5C,YAAM,MAAM,MAAM,KAAK;AACvB,YAAM,WAAW,CAAC,GAAG,KAAK,EACvB,IAAI,CAAC,MAAM,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,EACjD,KAAK,GAAG;AAEX,WAAK;AAAA,QACH,GAAG,MAAM,sBAAsB,GAAG,WAAW,QAAQ,SAAS,GAAG;AAAA,MAAA;AAGnE,UAAI,WAAW,IAAI,GAAG,GAAG;AACvB,cAAM,OAAO,WAAW,IAAI,GAAG;AAC/B,aAAK,IAAI,GAAG,MAAM,uBAAuB,IAAI,UAAU,GAAG,GAAG;AAE7D,eAAO,KAAK,IAAI;AAChB,cAAM,MAAM,KAAK;AAAA,UACf,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,QAAA;AAEV,YAAI,QAAQ,KAAM,QAAO;AACzB,eAAO,IAAA;AACP,aAAK,IAAI,GAAG,MAAM,kCAAkC,IAAI,GAAG;AAAA,MAC7D,OAAO;AACL,aAAK,IAAI,GAAG,MAAM,4BAA4B,GAAG,EAAE;AAAA,MACrD;AAAA,IACF;AAEA,SAAK,IAAI,GAAG,MAAM,8CAA8C;AAChE,WAAO;AAAA,EACT;AACF;"}
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "1.0.8",
|
|
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,6 +39,9 @@
|
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "vite build",
|
|
42
|
+
"build:dict:v1": "npx tsx scripts/dictionaries/build-v1-bip39.ts",
|
|
43
|
+
"build:dict:v2": "npx tsx scripts/dictionaries/build-v2-dwyl.ts",
|
|
44
|
+
"build:dict:all": "npm run build:dict:v1 && npm run build:dict:v2",
|
|
42
45
|
"clean": "rimraf dist",
|
|
43
46
|
"prepack": "npm run build",
|
|
44
47
|
"dev": "vite",
|
|
@@ -53,7 +56,8 @@
|
|
|
53
56
|
"git-pull-origin-main": "git pull origin main --force"
|
|
54
57
|
},
|
|
55
58
|
"dependencies": {
|
|
56
|
-
"bip39": "^3.1.0"
|
|
59
|
+
"bip39": "^3.1.0",
|
|
60
|
+
"bs58": "^6.0.0"
|
|
57
61
|
},
|
|
58
62
|
"devDependencies": {
|
|
59
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
|
-
constructor(initialDict?: WordBinDictionary, options?: {
|
|
5
|
-
debug?: boolean;
|
|
6
|
-
});
|
|
7
|
-
private log;
|
|
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 getReverseMapForVersion;
|
|
14
|
-
encode(text: string | EncodeResult | Uint8Array, options?: {
|
|
15
|
-
dictVersion?: number;
|
|
16
|
-
}): Promise<EncodeResult>;
|
|
17
|
-
decode(data: Uint8Array | string): Promise<string>;
|
|
18
|
-
private tryDecode;
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dictionary-D3gr2Ala.js","sources":["../src/core/tiers.ts","../src/core/id.ts","../src/utils/buffer.ts","../src/dictionary.ts"],"sourcesContent":["export function getIdByteLength(wordLength: number): number {\r\n if (wordLength <= 4) return 2;\r\n if (wordLength <= 9) return 3;\r\n return 4;\r\n}\r\n\r\nexport function getWrapByteLength(wordLength: number): number {\r\n if (wordLength <= 4) return 2;\r\n if (wordLength <= 9) return 3;\r\n return 4;\r\n}\r\n\r\nexport async function getTextEncoder(): Promise<TextEncoder> {\r\n if (typeof TextEncoder !== \"undefined\") return new TextEncoder();\r\n const { TextEncoder: NodeTextEncoder } = await import(\"node:util\");\r\n // @ts-ignore Node typings\r\n return new NodeTextEncoder();\r\n}\r\n\r\nexport async function wrapBase64(data: string): Promise<Uint8Array> {\r\n const normalized = data.trim().toLowerCase();\r\n if (!normalized) throw new Error(\"Cannot generate ID for empty string\");\r\n\r\n const encoder = await getTextEncoder();\r\n const result = encoder.encode(normalized);\r\n\r\n // Browser + Node compatible SHA-256\r\n let hash: ArrayBuffer;\r\n const anyCrypto: any = (globalThis as any).crypto;\r\n if (anyCrypto && anyCrypto.subtle) {\r\n hash = await anyCrypto.subtle.digest(\"SHA-256\", result);\r\n } else {\r\n const { createHash } = await import(\"node:crypto\");\r\n hash = createHash(\"sha256\").update(Buffer.from(result)).digest().buffer;\r\n }\r\n\r\n const hashBytes = new Uint8Array(hash);\r\n const size = getWrapByteLength(normalized.length);\r\n return hashBytes.slice(0, size);\r\n}\r\n","import { getIdByteLength } from './tiers.js'\r\n\r\n/**\r\n * Deterministic word \t ID generator\r\n * Same output on browser and node (when using compatible input)\r\n */\r\nexport async function generateWordId(word: string): Promise<Uint8Array> {\r\n const normalized = word.trim().toLowerCase()\r\n if (!normalized) throw new Error('Cannot generate ID for empty string')\r\n\r\n const encoder = await getTextEncoder()\r\n const data = encoder.encode(normalized)\r\n\r\n // Browser + Node compatible SHA-256\r\n let hash: ArrayBuffer\r\n const anyCrypto: any = (globalThis as any).crypto\r\n if (anyCrypto && anyCrypto.subtle) {\r\n hash = await anyCrypto.subtle.digest('SHA-256', data)\r\n } else {\r\n const { createHash } = await import('node:crypto')\r\n hash = createHash('sha256').update(Buffer.from(data)).digest().buffer\r\n }\r\n\r\n const hashBytes = new Uint8Array(hash)\r\n const size = getIdByteLength(normalized.length)\r\n return hashBytes.slice(0, size)\r\n}\r\n\r\nasync function getTextEncoder(): Promise<TextEncoder> {\r\n if (typeof TextEncoder !== 'undefined') return new TextEncoder()\r\n const { TextEncoder: NodeTextEncoder } = await import('node:util')\r\n // @ts-ignore Node typings\r\n return new NodeTextEncoder()\r\n}\r\n","export function toHex(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\nexport function fromHex(hex: string): Uint8Array {\r\n if (hex.length % 2 !== 0) throw new Error('Invalid hex string length')\r\n const bytes = new Uint8Array(hex.length / 2)\r\n for (let i = 0; i < hex.length; i += 2) {\r\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\r\n }\r\n return bytes\r\n}\r\n\r\nexport function toBase64(bytes: Uint8Array): string {\r\n const b64 = (globalThis as any).btoa\r\n if (typeof b64 === 'function') {\r\n return b64(String.fromCharCode(...bytes))\r\n }\r\n // Node fallback\r\n return Buffer.from(bytes).toString('base64')\r\n}\r\n\r\nexport function fromBase64(base64: string): Uint8Array {\r\n const at = (globalThis as any).atob\r\n if (typeof at === 'function') {\r\n const binary = at(base64)\r\n const out = new Uint8Array(binary.length)\r\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i)\r\n return out\r\n }\r\n // Node fallback\r\n return new Uint8Array(Buffer.from(base64, 'base64'))\r\n}\r\n\r\n// UTF-8 helpers\r\nexport function utf8Encode(str: string): Uint8Array {\r\n if (typeof TextEncoder !== 'undefined') return new TextEncoder().encode(str)\r\n // Node fallback\r\n return new Uint8Array(Buffer.from(str, 'utf8'))\r\n}\r\n\r\nexport function utf8Decode(bytes: Uint8Array): string {\r\n if (typeof TextDecoder !== 'undefined') return new TextDecoder().decode(bytes)\r\n // Node fallback\r\n return Buffer.from(bytes).toString('utf8')\r\n}\r\n\r\n// Varint (LEB128 7-bit groups) helpers\r\nexport function encodeVarint(n: number): Uint8Array {\r\n if (n < 0) throw new Error('Varint cannot encode negative numbers')\r\n const out: number[] = []\r\n do {\r\n let byte = n & 0x7f\r\n n >>>= 7\r\n if (n !== 0) byte |= 0x80\r\n out.push(byte)\r\n } while (n !== 0)\r\n return new Uint8Array(out)\r\n}\r\n\r\nexport function decodeVarint(bytes: Uint8Array, offset: number): { value: number; bytesRead: number } {\r\n let result = 0\r\n let shift = 0\r\n let pos = offset\r\n while (pos < bytes.length) {\r\n const byte = bytes[pos++]\r\n result |= (byte & 0x7f) << shift\r\n if ((byte & 0x80) === 0) {\r\n return { value: result, bytesRead: pos - offset }\r\n }\r\n shift += 7\r\n if (shift > 35) throw new Error('Varint too large')\r\n }\r\n throw new Error('Truncated varint')\r\n}\r\n","// File: src\\dictionary.ts\r\n\r\nimport type { WordBinDictionary } from \"./types\";\r\nimport { generateWordId } from \"./core/id.js\";\r\nimport { toHex } from \"./utils/buffer.js\";\r\n\r\nexport interface BuildDictionaryOptions {\r\n /**\r\n * Dictionary version number (used in header and for format compatibility)\r\n * @default 1\r\n */\r\n version?: number;\r\n\r\n /**\r\n * Human-readable description of this dictionary\r\n * @default \"WordBin dictionary v${version}\"\r\n */\r\n description?: string;\r\n\r\n /**\r\n * Optional: custom prefix or identifier for this dictionary build\r\n * (can be used in logs, filenames, etc.)\r\n */\r\n name?: string;\r\n}\r\n\r\nexport async function buildDictionary(\r\n words: string[],\r\n options: BuildDictionaryOptions = {},\r\n): Promise<WordBinDictionary> {\r\n const { version = 1, description = `WordBin dictionary v${version}` } =\r\n options;\r\n\r\n const map: Record<string, string[]> = {};\r\n\r\n const normalizedWords = words\r\n .map((w) => w.trim().toLowerCase())\r\n .filter((w) => w);\r\n\r\n await Promise.all(\r\n normalizedWords.map(async (word) => {\r\n const id = await generateWordId(word);\r\n const key = toHex(id);\r\n if (!map[key]) map[key] = [];\r\n map[key].push(word);\r\n }),\r\n );\r\n\r\n Object.values(map).forEach((collisions) => {\r\n collisions.sort((a, b) => a.localeCompare(b));\r\n });\r\n\r\n return {\r\n version,\r\n description,\r\n words: map,\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
|