@bigdreamsweb3/wordbin 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -36,15 +36,27 @@ import { WordBin } from "@bigdreamsweb3/wordbin";
36
36
  // Use latest dictionary (v1 bundled, v2 if built)
37
37
  const wb = await WordBin.create();
38
38
 
39
- const phrase = "abandon ability able about above";
39
+ const phrase =
40
+ "pet either learn purse candy leader craft undo spoil forum slot spirit";
40
41
  const encoded = await wb.encode(phrase);
41
42
 
42
- console.log("Base64 payload:", encoded.encodedBase64);
43
+ console.log("Base64 payload:", encoded.payload);
44
+ // → Base64 payload: Aru6lPEGao2lRWajTRYITVtmNVVD8BWvHGhOtBplWKaJmQ==
45
+
46
+ console.log("Dictionary Version used (header byte):", encoded.dictVersion);
47
+ // → Dictionary Version used (header byte):: 2
48
+
43
49
  console.log("Encoded bytes:", encoded.encodedBytes);
50
+ // → Encoded bytes: 34
51
+
44
52
  console.log("Original bytes:", encoded.originalBytes);
53
+ // → Original bytes: 70
54
+
55
+ console.log("Bytes saved:", encoded.bytesSaved);
56
+ // → Bytes saved: 36
45
57
 
46
58
  const decoded = await wb.decode(encoded.encoded);
47
- console.log("Decoded:", decoded); // → "abandon ability able about above"
59
+ console.log("Decoded:", decoded); // → "pet either learn purse candy leader craft undo spoil forum slot spirit"
48
60
  ```
49
61
 
50
62
  ### Browser Example
@@ -78,21 +90,21 @@ npx wordbin build --custom ./my-local-words.txt
78
90
 
79
91
  ## Dictionary Versions
80
92
 
81
- | Version | Filename | Words | Source | ID bytes | Best for |
82
- | ------- | --------------------- | ----- | ------------------ | -------- | --------------------------------------- |
83
- | v1 | wordbin-v1-bip39.json | 2,048 | BIP-39 English | ~2 | Crypto recovery seeds, high reliability |
84
- | v2 | wordbin-v2-dwyl.json | ~466k | dwyl/english-words | 2–4 | General English, tags, keywords |
85
-
86
- > **v2 note**: The dwyl list contains capitalized words. Encoding/decoding is case-sensitive. Normalize to lowercase for case-insensitive behavior.
93
+ | Version | Filename | Words | Source | ID bytes | Best for |
94
+ | ------- | --------------------- | -------- | ------------------ | -------- | --------------------------------------- |
95
+ | v1 | wordbin-v1-bip39.json | 2,048 | BIP-39 English | ~2 | Crypto recovery seeds, high reliability |
96
+ | v2 | wordbin-v2-dwyl.json | ~479,000 | dwyl/english-words | 2–4 | General English, tags, keywords |
87
97
 
88
98
  ---
89
99
 
90
100
  ## How It Works
91
101
 
92
- 1. Each word SHA-256 → first **2–4 bytes** = deterministic ID.
93
- 2. Encoded payload: `[MAGIC_BYTES ('WB') | VERSION | WORD_IDS...]`
94
- 3. Decoding reverses IDs original words using the same dictionary.
95
- 4. Optimized for **short sequences**, not arbitrary long text.
102
+ 1. Each word is hashed → first **2–4 bytes** = its fixed ID.
103
+ 2. If the ID is in the dictionary → use the short ID.
104
+ Otherwise store the word as a compact literal block.
105
+ 3. Payload begins with one byte: **dictionary version**.
106
+ 4. Decoding uses the same dictionary to reverse IDs → original words.
107
+ 5. Backtracking handles any ID length ambiguity → guaranteed correct output.
96
108
 
97
109
  ---
98
110
 
package/dist/index.mjs CHANGED
@@ -82,7 +82,6 @@ async function loadLatestDictionary() {
82
82
  return loadDictionaryByVersion(latestVersion);
83
83
  }
84
84
  class WordBin {
85
- // private debug: boolean;
86
85
  constructor(initialDict, options) {
87
86
  this.primaryDictVersion = initialDict?.version ?? 2;
88
87
  this.log = options?.debug ? (...args) => console.log("[WordBin]", ...args) : () => {
@@ -116,6 +115,7 @@ class WordBin {
116
115
  if (!textStr.trim()) {
117
116
  return {
118
117
  originalText: "",
118
+ dictVersion: 0,
119
119
  encoded: new Uint8Array(0),
120
120
  payload: "",
121
121
  encodedBase64: "",
@@ -129,12 +129,9 @@ class WordBin {
129
129
  this.log(`[encode] Input words (${words.length}):`, words);
130
130
  const useVersion = options.dictVersion ?? this.primaryDictVersion;
131
131
  this.log(`[encode] Using dictionary version: ${useVersion}`);
132
- const header = new Uint8Array([MAGIC[0], MAGIC[1], useVersion]);
132
+ const header = new Uint8Array([useVersion]);
133
133
  this.log(`[encode] Header bytes: [${[...header].join(", ")}]`);
134
134
  this.log(`[encode] Header hex: ${toHex(header)}`);
135
- this.log(
136
- `[encode] Header as text (non-printable chars expected): "${new TextDecoder().decode(header)}"`
137
- );
138
135
  const chunks = [header];
139
136
  const reverseMap = await this.getReverseMapForVersion(useVersion);
140
137
  this.log(`[encode] Reverse map loaded — size: ${reverseMap.size} entries`);
@@ -143,7 +140,6 @@ class WordBin {
143
140
  const id = await generateWordId(w);
144
141
  const key = toHex(id);
145
142
  this.log(` "${w}" → ID bytes: [${[...id].join(", ")}] | hex: ${key}`);
146
- console.log(` "${w}" → ID bytes: [${[...id].join(", ")}] | hex: ${key}`);
147
143
  if (reverseMap.has(key)) {
148
144
  reverseMap.get(key);
149
145
  this.log(` → Found in dictionary → using ${id.length}-byte ID`);
@@ -183,6 +179,7 @@ class WordBin {
183
179
  this.log(`[encode] Base64 starts with: ${base64Result.slice(0, 12)}...`);
184
180
  return {
185
181
  originalText: textStr,
182
+ dictVersion: result[0],
186
183
  encoded: result,
187
184
  payload: base64Result,
188
185
  encodedBase64: base64Result,
@@ -208,19 +205,15 @@ class WordBin {
208
205
  this.log(
209
206
  `[decode] First 16 bytes: [${[...buffer.subarray(0, Math.min(16, buffer.length))].join(", ")}]`
210
207
  );
211
- if (buffer.length < 3) {
208
+ if (buffer.length < 1) {
212
209
  throw new Error("Data too short");
213
210
  }
214
- const magicReceived = [buffer[0], buffer[1]];
215
- this.log(
216
- `[decode] Magic bytes: expected [${MAGIC[0]}, ${MAGIC[1]}], got [${magicReceived.join(", ")}]`
217
- );
218
- if (buffer[0] !== MAGIC[0] || buffer[1] !== MAGIC[1]) {
219
- throw new Error("Invalid magic bytes");
220
- }
221
- const version = buffer[2];
211
+ const version = buffer[0];
222
212
  this.log(`[decode] Dictionary version from header: ${version}`);
223
- const pos = 3;
213
+ if (version < 1 || version > 100) {
214
+ this.log(`[decode] Warning: unusual dictionary version ${version}`);
215
+ }
216
+ let pos = 1;
224
217
  this.log(`[decode] Starting decode at position ${pos}`);
225
218
  const reverseMap = await this.getReverseMapForVersion(version);
226
219
  this.log(
@@ -272,18 +265,14 @@ class WordBin {
272
265
  this.log(`${indent}[tryDecode] Decoded literal: "${word}"`);
273
266
  result.push(word);
274
267
  const res = this.tryDecode(end, buffer, reverseMap, result, depth + 1);
275
- if (res !== null) {
276
- return res;
277
- }
268
+ if (res !== null) return res;
278
269
  result.pop();
279
270
  this.log(`${indent}[tryDecode] Backtracking from literal`);
280
271
  return null;
281
272
  }
282
273
  for (const len of [4, 3, 2]) {
283
274
  if (pos + len > buffer.length) {
284
- this.log(
285
- `${indent}[tryDecode] Skipping ${len}-byte (would exceed: need ${pos + len}, have ${buffer.length})`
286
- );
275
+ this.log(`${indent}[tryDecode] Skipping ${len}-byte (would exceed)`);
287
276
  continue;
288
277
  }
289
278
  const slice = buffer.subarray(pos, pos + len);
@@ -303,9 +292,7 @@ class WordBin {
303
292
  result,
304
293
  depth + 1
305
294
  );
306
- if (res !== null) {
307
- return res;
308
- }
295
+ if (res !== null) return res;
309
296
  result.pop();
310
297
  this.log(`${indent}[tryDecode] Backtracking from "${word}"`);
311
298
  } else {
@@ -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 { MAGIC, 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 // private debug: boolean;\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 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 creation\r\n // ──────────────────────────────────────────────\r\n const header = new Uint8Array([MAGIC[0], MAGIC[1], useVersion]);\r\n this.log(`[encode] Header bytes: [${[...header].join(\", \")}]`);\r\n this.log(`[encode] Header hex: ${toHex(header)}`);\r\n this.log(\r\n `[encode] Header as text (non-printable chars expected): \"${new TextDecoder().decode(header)}\"`,\r\n );\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 → show ID mapping\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); // Uint8Array (usually 2–4 bytes)\r\n const key = toHex(id); // hex string for lookup\r\n\r\n this.log(` \"${w}\" → ID bytes: [${[...id].join(\", \")}] | hex: ${key}`);\r\n\r\n console.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 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 < 3) {\r\n throw new Error(\"Data too short\");\r\n }\r\n\r\n // Check magic bytes\r\n const magicReceived = [buffer[0], buffer[1]];\r\n this.log(\r\n `[decode] Magic bytes: expected [${MAGIC[0]}, ${MAGIC[1]}], got [${magicReceived.join(\", \")}]`,\r\n );\r\n\r\n if (buffer[0] !== MAGIC[0] || buffer[1] !== MAGIC[1]) {\r\n throw new Error(\"Invalid magic bytes\");\r\n }\r\n\r\n const version = buffer[2];\r\n this.log(`[decode] Dictionary version from header: ${version}`);\r\n\r\n const pos = 3; // start right after 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); // 0 is depth for logging\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, // for indented logging\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 // Show context\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) {\r\n return res;\r\n }\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 (long to short, but backtrack allows exploring shorter if long fails downstream)\r\n for (const len of [4, 3, 2]) {\r\n if (pos + len > buffer.length) {\r\n this.log(\r\n `${indent}[tryDecode] Skipping ${len}-byte (would exceed: need ${pos + len}, have ${buffer.length})`,\r\n );\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) {\r\n return res;\r\n }\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 // If no branches worked, fail this path\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":"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"}
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":"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"}
package/dist/types.d.ts CHANGED
@@ -7,6 +7,7 @@ export interface EncodeResult {
7
7
  originalText: string;
8
8
  payload: string;
9
9
  encoded: Uint8Array;
10
+ dictVersion: number;
10
11
  encodedBase64: string;
11
12
  originalBytes: number;
12
13
  encodedBytes: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigdreamsweb3/wordbin",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
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",