@bigdreamsweb3/wordbin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,114 @@
1
+ function getIdByteLength(wordLength) {
2
+ if (wordLength <= 4) return 2;
3
+ if (wordLength <= 9) return 3;
4
+ return 4;
5
+ }
6
+ async function generateWordId(word) {
7
+ const normalized = word.trim().toLowerCase();
8
+ if (!normalized) throw new Error("Cannot generate ID for empty string");
9
+ const encoder = await getTextEncoder();
10
+ const data = encoder.encode(normalized);
11
+ let hash;
12
+ const anyCrypto = globalThis.crypto;
13
+ if (anyCrypto && anyCrypto.subtle) {
14
+ hash = await anyCrypto.subtle.digest("SHA-256", data);
15
+ } else {
16
+ const { createHash } = await import("node:crypto");
17
+ hash = createHash("sha256").update(Buffer.from(data)).digest().buffer;
18
+ }
19
+ const hashBytes = new Uint8Array(hash);
20
+ const size = getIdByteLength(normalized.length);
21
+ return hashBytes.slice(0, size);
22
+ }
23
+ async function getTextEncoder() {
24
+ if (typeof TextEncoder !== "undefined") return new TextEncoder();
25
+ const { TextEncoder: NodeTextEncoder } = await import("node:util");
26
+ return new NodeTextEncoder();
27
+ }
28
+ function toHex(bytes) {
29
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
30
+ }
31
+ function toBase64(bytes) {
32
+ const b64 = globalThis.btoa;
33
+ if (typeof b64 === "function") {
34
+ return b64(String.fromCharCode(...bytes));
35
+ }
36
+ return Buffer.from(bytes).toString("base64");
37
+ }
38
+ function fromBase64(base64) {
39
+ const at = globalThis.atob;
40
+ if (typeof at === "function") {
41
+ const binary = at(base64);
42
+ const out = new Uint8Array(binary.length);
43
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
44
+ return out;
45
+ }
46
+ return new Uint8Array(Buffer.from(base64, "base64"));
47
+ }
48
+ function utf8Encode(str) {
49
+ if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(str);
50
+ return new Uint8Array(Buffer.from(str, "utf8"));
51
+ }
52
+ function utf8Decode(bytes) {
53
+ if (typeof TextDecoder !== "undefined") return new TextDecoder().decode(bytes);
54
+ return Buffer.from(bytes).toString("utf8");
55
+ }
56
+ function encodeVarint(n) {
57
+ if (n < 0) throw new Error("Varint cannot encode negative numbers");
58
+ const out = [];
59
+ do {
60
+ let byte = n & 127;
61
+ n >>>= 7;
62
+ if (n !== 0) byte |= 128;
63
+ out.push(byte);
64
+ } while (n !== 0);
65
+ return new Uint8Array(out);
66
+ }
67
+ function decodeVarint(bytes, offset) {
68
+ let result = 0;
69
+ let shift = 0;
70
+ let pos = offset;
71
+ while (pos < bytes.length) {
72
+ const byte = bytes[pos++];
73
+ result |= (byte & 127) << shift;
74
+ if ((byte & 128) === 0) {
75
+ return { value: result, bytesRead: pos - offset };
76
+ }
77
+ shift += 7;
78
+ if (shift > 35) throw new Error("Varint too large");
79
+ }
80
+ throw new Error("Truncated varint");
81
+ }
82
+ async function buildDictionary(words, options = {}) {
83
+ const { version = 1, description = `WordBin dictionary v${version}` } = options;
84
+ const map = {};
85
+ const normalizedWords = words.map((w) => w.trim().toLowerCase()).filter((w) => w);
86
+ await Promise.all(
87
+ normalizedWords.map(async (word) => {
88
+ const id = await generateWordId(word);
89
+ const key = toHex(id);
90
+ if (!map[key]) map[key] = [];
91
+ map[key].push(word);
92
+ })
93
+ );
94
+ Object.values(map).forEach((collisions) => {
95
+ collisions.sort((a, b) => a.localeCompare(b));
96
+ });
97
+ return {
98
+ version,
99
+ description,
100
+ words: map
101
+ };
102
+ }
103
+ export {
104
+ toHex as a,
105
+ buildDictionary as b,
106
+ utf8Decode as c,
107
+ decodeVarint as d,
108
+ encodeVarint as e,
109
+ fromBase64 as f,
110
+ generateWordId as g,
111
+ toBase64 as t,
112
+ utf8Encode as u
113
+ };
114
+ //# sourceMappingURL=dictionary-D3gr2Ala.js.map
@@ -0,0 +1 @@
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":"AAAO,SAAS,gBAAgB,YAA4B;AAC1D,MAAI,cAAc,EAAG,QAAO;AAC5B,MAAI,cAAc,EAAG,QAAO;AAC5B,SAAO;AACT;ACEA,eAAsB,eAAe,MAAmC;AACtE,QAAM,aAAa,KAAK,KAAA,EAAO,YAAA;AAC/B,MAAI,CAAC,WAAY,OAAM,IAAI,MAAM,qCAAqC;AAEtE,QAAM,UAAU,MAAM,eAAA;AACtB,QAAM,OAAO,QAAQ,OAAO,UAAU;AAGtC,MAAI;AACJ,QAAM,YAAkB,WAAmB;AAC3C,MAAI,aAAa,UAAU,QAAQ;AACjC,WAAO,MAAM,UAAU,OAAO,OAAO,WAAW,IAAI;AAAA,EACtD,OAAO;AACL,UAAM,EAAE,WAAA,IAAe,MAAM,OAAO,aAAa;AACjD,WAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE,OAAA,EAAS;AAAA,EACjE;AAEA,QAAM,YAAY,IAAI,WAAW,IAAI;AACrC,QAAM,OAAO,gBAAgB,WAAW,MAAM;AAC9C,SAAO,UAAU,MAAM,GAAG,IAAI;AAChC;AAEA,eAAe,iBAAuC;AACpD,MAAI,OAAO,gBAAgB,YAAa,QAAO,IAAI,YAAA;AACnD,QAAM,EAAE,aAAa,oBAAoB,MAAM,OAAO,WAAW;AAEjE,SAAO,IAAI,gBAAA;AACb;ACjCO,SAAS,MAAM,OAA2B;AAC/C,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;AAWO,SAAS,SAAS,OAA2B;AAClD,QAAM,MAAO,WAAmB;AAChC,MAAI,OAAO,QAAQ,YAAY;AAC7B,WAAO,IAAI,OAAO,aAAa,GAAG,KAAK,CAAC;AAAA,EAC1C;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAC7C;AAEO,SAAS,WAAW,QAA4B;AACrD,QAAM,KAAM,WAAmB;AAC/B,MAAI,OAAO,OAAO,YAAY;AAC5B,UAAM,SAAS,GAAG,MAAM;AACxB,UAAM,MAAM,IAAI,WAAW,OAAO,MAAM;AACxC,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,KAAI,CAAC,IAAI,OAAO,WAAW,CAAC;AACpE,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,WAAW,OAAO,KAAK,QAAQ,QAAQ,CAAC;AACrD;AAGO,SAAS,WAAW,KAAyB;AAClD,MAAI,OAAO,gBAAgB,YAAa,QAAO,IAAI,YAAA,EAAc,OAAO,GAAG;AAE3E,SAAO,IAAI,WAAW,OAAO,KAAK,KAAK,MAAM,CAAC;AAChD;AAEO,SAAS,WAAW,OAA2B;AACpD,MAAI,OAAO,gBAAgB,YAAa,QAAO,IAAI,YAAA,EAAc,OAAO,KAAK;AAE7E,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,MAAM;AAC3C;AAGO,SAAS,aAAa,GAAuB;AAClD,MAAI,IAAI,EAAG,OAAM,IAAI,MAAM,uCAAuC;AAClE,QAAM,MAAgB,CAAA;AACtB,KAAG;AACD,QAAI,OAAO,IAAI;AACf,WAAO;AACP,QAAI,MAAM,EAAG,SAAQ;AACrB,QAAI,KAAK,IAAI;AAAA,EACf,SAAS,MAAM;AACf,SAAO,IAAI,WAAW,GAAG;AAC3B;AAEO,SAAS,aAAa,OAAmB,QAAsD;AACpG,MAAI,SAAS;AACb,MAAI,QAAQ;AACZ,MAAI,MAAM;AACV,SAAO,MAAM,MAAM,QAAQ;AACzB,UAAM,OAAO,MAAM,KAAK;AACxB,eAAW,OAAO,QAAS;AAC3B,SAAK,OAAO,SAAU,GAAG;AACvB,aAAO,EAAE,OAAO,QAAQ,WAAW,MAAM,OAAA;AAAA,IAC3C;AACA,aAAS;AACT,QAAI,QAAQ,GAAI,OAAM,IAAI,MAAM,kBAAkB;AAAA,EACpD;AACA,QAAM,IAAI,MAAM,kBAAkB;AACpC;AClDA,eAAsB,gBACpB,OACA,UAAkC,IACN;AAC5B,QAAM,EAAE,UAAU,GAAG,cAAc,uBAAuB,OAAO,OAC/D;AAEF,QAAM,MAAgC,CAAA;AAEtC,QAAM,kBAAkB,MACrB,IAAI,CAAC,MAAM,EAAE,KAAA,EAAO,YAAA,CAAa,EACjC,OAAO,CAAC,MAAM,CAAC;AAElB,QAAM,QAAQ;AAAA,IACZ,gBAAgB,IAAI,OAAO,SAAS;AAClC,YAAM,KAAK,MAAM,eAAe,IAAI;AACpC,YAAM,MAAM,MAAM,EAAE;AACpB,UAAI,CAAC,IAAI,GAAG,EAAG,KAAI,GAAG,IAAI,CAAA;AAC1B,UAAI,GAAG,EAAE,KAAK,IAAI;AAAA,IACpB,CAAC;AAAA,EAAA;AAGH,SAAO,OAAO,GAAG,EAAE,QAAQ,CAAC,eAAe;AACzC,eAAW,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EAAA;AAEX;"}
@@ -0,0 +1,19 @@
1
+ import { WordBinDictionary } from './types.js';
2
+ /**
3
+ * Get all available dictionary versions by scanning the data directory
4
+ * Looks for files matching pattern: wordbin-v*.json or wordbin-v*-*.json
5
+ */
6
+ export declare function getAllAvailableDictionaryVersions(): Promise<number[]>;
7
+ /**
8
+ * Load a specific dictionary version
9
+ * Throws error if version not found
10
+ */
11
+ export declare function loadDictionaryByVersion(version: number): Promise<WordBinDictionary>;
12
+ /**
13
+ * Load the latest available dictionary version
14
+ */
15
+ export declare function loadLatestDictionary(): Promise<WordBinDictionary>;
16
+ /**
17
+ * Check if a specific version exists
18
+ */
19
+ export declare function hasDictionaryVersion(version: number): Promise<boolean>;
@@ -0,0 +1,19 @@
1
+ import { WordBinDictionary } from './types';
2
+ export interface BuildDictionaryOptions {
3
+ /**
4
+ * Dictionary version number (used in header and for format compatibility)
5
+ * @default 1
6
+ */
7
+ version?: number;
8
+ /**
9
+ * Human-readable description of this dictionary
10
+ * @default "WordBin dictionary v${version}"
11
+ */
12
+ description?: string;
13
+ /**
14
+ * Optional: custom prefix or identifier for this dictionary build
15
+ * (can be used in logs, filenames, etc.)
16
+ */
17
+ name?: string;
18
+ }
19
+ export declare function buildDictionary(words: string[], options?: BuildDictionaryOptions): Promise<WordBinDictionary>;
@@ -0,0 +1,4 @@
1
+ export { MAGIC } from './constants.js';
2
+ export { buildDictionary } from './dictionary';
3
+ export { WordBin } from './core.js';
4
+ export type { EncodeResult, WordBinDictionary } from './types';
package/dist/index.mjs ADDED
@@ -0,0 +1,232 @@
1
+ import { b as buildDictionary, t as toBase64, a as toHex, g as generateWordId, u as utf8Encode, e as encodeVarint, f as fromBase64, d as decodeVarint, c as utf8Decode } from "./dictionary-D3gr2Ala.js";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ const MAGIC = new Uint8Array([87, 66]);
6
+ const LITERAL = 255;
7
+ const __filename$1 = fileURLToPath(import.meta.url);
8
+ const __dirname$1 = path.dirname(__filename$1);
9
+ const DICT_DIR = path.join(__dirname$1, "../data");
10
+ async function getAllAvailableDictionaryVersions() {
11
+ try {
12
+ const files = await fs.readdir(DICT_DIR);
13
+ const versions = /* @__PURE__ */ new Set();
14
+ for (const file of files) {
15
+ const match = file.match(/wordbin-v(\d+)/i);
16
+ if (match) {
17
+ versions.add(parseInt(match[1], 10));
18
+ }
19
+ }
20
+ return Array.from(versions).sort((a, b) => a - b);
21
+ } catch (error) {
22
+ console.error(`Failed to scan dictionary directory: ${DICT_DIR}`, error);
23
+ return [];
24
+ }
25
+ }
26
+ async function loadDictionaryByVersion(version) {
27
+ const availableVersions = await getAllAvailableDictionaryVersions();
28
+ if (!availableVersions.includes(version)) {
29
+ throw new Error(
30
+ `Dictionary version ${version} not found. Available versions: ${availableVersions.join(", ")}`
31
+ );
32
+ }
33
+ const files = await fs.readdir(DICT_DIR);
34
+ const versionFile = files.find(
35
+ (f) => f.match(new RegExp(`wordbin-v${version}(?:\\.|-)`, "i"))
36
+ );
37
+ if (!versionFile) {
38
+ throw new Error(
39
+ `Dictionary file for version ${version} not found in ${DICT_DIR}`
40
+ );
41
+ }
42
+ const filePath = path.join(DICT_DIR, versionFile);
43
+ const data = await fs.readFile(filePath, "utf-8");
44
+ const dict = JSON.parse(data);
45
+ if (dict.version !== version) {
46
+ throw new Error(
47
+ `Version mismatch: file ${versionFile} claims to be v${dict.version}, but loaded as v${version}`
48
+ );
49
+ }
50
+ return dict;
51
+ }
52
+ async function loadLatestDictionary() {
53
+ const versions = await getAllAvailableDictionaryVersions();
54
+ if (versions.length === 0) {
55
+ throw new Error(
56
+ `No dictionary files found in ${DICT_DIR}. Expected files like wordbin-v1.json`
57
+ );
58
+ }
59
+ const latestVersion = Math.max(...versions);
60
+ console.log(
61
+ `Loading latest dictionary: version ${latestVersion} (available: ${versions.join(", ")})`
62
+ );
63
+ return loadDictionaryByVersion(latestVersion);
64
+ }
65
+ class WordBin {
66
+ // private debug: boolean;
67
+ constructor(initialDict, options) {
68
+ this.primaryDictVersion = initialDict?.version ?? 2;
69
+ this.log = options?.debug ? (...args) => console.log("[WordBin]", ...args) : () => {
70
+ };
71
+ }
72
+ static async createFromWords(words) {
73
+ console.warn("Building dictionary from scratch – consider pre-built files");
74
+ const dict = await buildDictionary(words);
75
+ return new WordBin(dict);
76
+ }
77
+ static async createFromJson(dictJson) {
78
+ return new WordBin(dictJson);
79
+ }
80
+ static async create() {
81
+ const latestDict = await loadLatestDictionary();
82
+ return new WordBin(latestDict);
83
+ }
84
+ async getReverseMapForVersion(version) {
85
+ const dict = await loadDictionaryByVersion(version);
86
+ const reverseMap = /* @__PURE__ */ new Map();
87
+ for (const [hex, words] of Object.entries(dict.words)) {
88
+ if (words.length > 0) reverseMap.set(hex, words[0]);
89
+ }
90
+ return reverseMap;
91
+ }
92
+ async encode(text, options = {}) {
93
+ let textStr;
94
+ if (typeof text === "string") textStr = text;
95
+ else if (text instanceof Uint8Array) textStr = toBase64(text);
96
+ else textStr = text.encodedBase64;
97
+ if (!textStr.trim()) {
98
+ return {
99
+ originalText: "",
100
+ encoded: new Uint8Array(0),
101
+ payload: "",
102
+ encodedBase64: "",
103
+ originalBytes: 0,
104
+ encodedBytes: 0,
105
+ bytesSaved: 0,
106
+ ratioPercent: 100
107
+ };
108
+ }
109
+ const words = textStr.split(/\s+/).filter(Boolean);
110
+ this.log(`[encode] Input words (${words.length}):`, words);
111
+ const useVersion = options.dictVersion ?? this.primaryDictVersion;
112
+ this.log(`[encode] Using dictionary version: ${useVersion}`);
113
+ const header = new Uint8Array([MAGIC[0], MAGIC[1], useVersion]);
114
+ this.log(`[encode] Header bytes: [${[...header].join(", ")}]`);
115
+ this.log(`[encode] Header hex: ${toHex(header)}`);
116
+ this.log(
117
+ `[encode] Header as text (non-printable chars expected): "${new TextDecoder().decode(header)}"`
118
+ );
119
+ const chunks = [header];
120
+ const reverseMap = await this.getReverseMapForVersion(useVersion);
121
+ this.log(`[encode] Reverse map loaded — size: ${reverseMap.size} entries`);
122
+ this.log("[encode] Word → ID mapping:");
123
+ for (const w of words) {
124
+ const id = await generateWordId(w);
125
+ const key = toHex(id);
126
+ this.log(` "${w}" → ID bytes: [${[...id].join(", ")}] | hex: ${key}`);
127
+ if (reverseMap.has(key)) {
128
+ reverseMap.get(key);
129
+ this.log(` → Found in dictionary → using ${id.length}-byte ID`);
130
+ chunks.push(id);
131
+ } else {
132
+ const utf8 = utf8Encode(w);
133
+ const lenVarint = encodeVarint(utf8.length);
134
+ this.log(` → NOT in dictionary → literal mode`);
135
+ this.log(
136
+ ` Literal length varint bytes: [${[...lenVarint].join(", ")}] (value = ${utf8.length})`
137
+ );
138
+ this.log(` Word UTF-8 bytes length: ${utf8.length}`);
139
+ const out = new Uint8Array(1 + lenVarint.length + utf8.length);
140
+ out[0] = LITERAL;
141
+ out.set(lenVarint, 1);
142
+ out.set(utf8, 1 + lenVarint.length);
143
+ this.log(` Literal chunk bytes: [${[...out].join(", ")}]`);
144
+ chunks.push(out);
145
+ }
146
+ }
147
+ const totalLength = chunks.reduce((n, c) => n + c.length, 0);
148
+ const result = new Uint8Array(totalLength);
149
+ this.log(`[encode] Total encoded length: ${totalLength} bytes`);
150
+ let off = 0;
151
+ chunks.forEach((chunk, i) => {
152
+ result.set(chunk, off);
153
+ off += chunk.length;
154
+ this.log(
155
+ ` Chunk ${i}: ${chunk.length} bytes → offset ${off - chunk.length}`
156
+ );
157
+ });
158
+ this.log(
159
+ `[encode] Final encoded bytes (first 32): [${[...result.subarray(0, Math.min(32, result.length))].join(", ")}]`
160
+ );
161
+ const originalBytes = new TextEncoder().encode(textStr).length;
162
+ const base64Result = toBase64(result);
163
+ this.log(`[encode] Base64 starts with: ${base64Result.slice(0, 12)}...`);
164
+ return {
165
+ originalText: textStr,
166
+ encoded: result,
167
+ payload: base64Result,
168
+ encodedBase64: base64Result,
169
+ originalBytes,
170
+ encodedBytes: totalLength,
171
+ bytesSaved: originalBytes - totalLength,
172
+ ratioPercent: totalLength === 0 ? 100 : Math.round(totalLength / originalBytes * 100)
173
+ };
174
+ }
175
+ async decode(data) {
176
+ let buffer;
177
+ if (typeof data === "string") {
178
+ buffer = fromBase64(data);
179
+ } else {
180
+ buffer = data;
181
+ }
182
+ if (buffer.length < 3) {
183
+ throw new Error("Data too short");
184
+ }
185
+ if (buffer[0] !== MAGIC[0] || buffer[1] !== MAGIC[1]) {
186
+ throw new Error("Invalid magic bytes");
187
+ }
188
+ const version = buffer[2];
189
+ let pos = 3;
190
+ const reverseMap = await this.getReverseMapForVersion(version);
191
+ const result = [];
192
+ while (pos < buffer.length) {
193
+ let matched = false;
194
+ if (buffer[pos] === LITERAL) {
195
+ const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);
196
+ const start = pos + 1 + bytesRead;
197
+ const end = start + byteLen;
198
+ if (end > buffer.length) {
199
+ throw new Error("Truncated literal block");
200
+ }
201
+ const word = utf8Decode(buffer.subarray(start, end));
202
+ result.push(word);
203
+ pos = end;
204
+ matched = true;
205
+ }
206
+ if (!matched) {
207
+ for (const len of [4, 3, 2]) {
208
+ if (pos + len > buffer.length) continue;
209
+ const slice = buffer.subarray(pos, pos + len);
210
+ const key = toHex(slice);
211
+ if (reverseMap.has(key)) {
212
+ result.push(reverseMap.get(key));
213
+ pos += len;
214
+ matched = true;
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ if (!matched) {
220
+ result.push(`[??:${buffer[pos].toString(16).padStart(2, "0")}]`);
221
+ pos += 1;
222
+ }
223
+ }
224
+ return result.join(" ");
225
+ }
226
+ }
227
+ export {
228
+ MAGIC,
229
+ WordBin,
230
+ buildDictionary
231
+ };
232
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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\nconst DICT_DIR = path.join(__dirname, \"../data\");\r\n\r\n/**\r\n * Get all available dictionary versions by scanning the data directory\r\n * Looks for files matching pattern: wordbin-v*.json or wordbin-v*-*.json\r\n */\r\nexport async function getAllAvailableDictionaryVersions(): Promise<number[]> {\r\n try {\r\n const files = await fs.readdir(DICT_DIR);\r\n\r\n const versions = new Set<number>();\r\n\r\n for (const file of files) {\r\n // Match patterns like: wordbin-v1.json, wordbin-v1-bip39.json, etc.\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\r\n return Array.from(versions).sort((a, b) => a - b);\r\n } catch (error) {\r\n console.error(`Failed to scan dictionary directory: ${DICT_DIR}`, error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Load a specific dictionary version\r\n * Throws error if version not found\r\n */\r\nexport async function loadDictionaryByVersion(\r\n version: number,\r\n): Promise<WordBinDictionary> {\r\n const availableVersions = await getAllAvailableDictionaryVersions();\r\n\r\n if (!availableVersions.includes(version)) {\r\n throw new Error(\r\n `Dictionary version ${version} not found. Available versions: ${availableVersions.join(\", \")}`,\r\n );\r\n }\r\n\r\n // Look for exact file match first\r\n const files = await fs.readdir(DICT_DIR);\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 throw new Error(\r\n `Dictionary file for version ${version} not found in ${DICT_DIR}`,\r\n );\r\n }\r\n\r\n const filePath = path.join(DICT_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 // Validate version matches\r\n if (dict.version !== version) {\r\n throw new Error(\r\n `Version mismatch: file ${versionFile} claims to be v${dict.version}, but loaded as v${version}`,\r\n );\r\n }\r\n\r\n return dict;\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 in ${DICT_DIR}. Expected files like wordbin-v1.json`,\r\n );\r\n }\r\n\r\n const latestVersion = Math.max(...versions);\r\n console.log(\r\n `Loading latest dictionary: version ${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}","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(): Promise<WordBin> {\r\n const latestDict = await loadLatestDictionary();\r\n return new WordBin(latestDict);\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 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 buffer = fromBase64(data);\r\n } else {\r\n buffer = data;\r\n }\r\n\r\n if (buffer.length < 3) {\r\n throw new Error(\"Data too short\");\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 let pos = 3; // start right after version byte\r\n\r\n const reverseMap = await this.getReverseMapForVersion(version);\r\n\r\n const result: string[] = [];\r\n\r\n while (pos < buffer.length) {\r\n let matched = false;\r\n\r\n // Literal block\r\n if (buffer[pos] === LITERAL) {\r\n const { value: byteLen, bytesRead } = decodeVarint(buffer, pos + 1);\r\n const start = pos + 1 + bytesRead;\r\n const end = start + byteLen;\r\n\r\n if (end > buffer.length) {\r\n throw new Error(\"Truncated literal block\");\r\n }\r\n\r\n const word = utf8Decode(buffer.subarray(start, end));\r\n result.push(word);\r\n pos = end;\r\n matched = true;\r\n }\r\n\r\n // Known word reference\r\n if (!matched) {\r\n for (const len of [4, 3, 2]) {\r\n if (pos + len > buffer.length) continue;\r\n const slice = buffer.subarray(pos, pos + len);\r\n const key = toHex(slice);\r\n\r\n if (reverseMap.has(key)) {\r\n result.push(reverseMap.get(key)!);\r\n pos += len;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!matched) {\r\n result.push(`[??:${buffer[pos].toString(16).padStart(2, \"0\")}]`);\r\n pos += 1;\r\n }\r\n }\r\n\r\n return result.join(\" \");\r\n }\r\n}\r\n"],"names":["__filename","__dirname"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface WordBinDictionary {
2
+ version: number;
3
+ description: string;
4
+ words: Record<string, string[]>;
5
+ }
6
+ export interface EncodeResult {
7
+ originalText: string;
8
+ payload: string;
9
+ encoded: Uint8Array;
10
+ encodedBase64: string;
11
+ originalBytes: number;
12
+ encodedBytes: number;
13
+ bytesSaved: number;
14
+ ratioPercent: number;
15
+ wrapped?: {
16
+ encodedBase64: string;
17
+ encodedBytes: number;
18
+ bytesSaved: number;
19
+ ratioPercent: number;
20
+ };
21
+ }
@@ -0,0 +1,11 @@
1
+ export declare function toHex(bytes: Uint8Array): string;
2
+ export declare function fromHex(hex: string): Uint8Array;
3
+ export declare function toBase64(bytes: Uint8Array): string;
4
+ export declare function fromBase64(base64: string): Uint8Array;
5
+ export declare function utf8Encode(str: string): Uint8Array;
6
+ export declare function utf8Decode(bytes: Uint8Array): string;
7
+ export declare function encodeVarint(n: number): Uint8Array;
8
+ export declare function decodeVarint(bytes: Uint8Array, offset: number): {
9
+ value: number;
10
+ bytesRead: number;
11
+ };
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@bigdreamsweb3/wordbin",
3
+ "version": "1.0.0",
4
+ "description": "WordBin – Encode words & short text into tiny, reversible binary for storage, URLs, IoT, QR codes, metadata, blockchain, or Web3 apps.",
5
+ "author": "Agbaka Daniel Ugonna <99cratson@gmail.com>",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/bigdreamsweb3/wordbin#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/bigdreamsweb3/wordbin.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/bigdreamsweb3/wordbin/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.mjs",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.mjs"
22
+ }
23
+ },
24
+ "bin": {
25
+ "wordbin": "./dist/cli.mjs"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE",
31
+ "CONTRIBUTING.md"
32
+ ],
33
+ "sideEffects": false,
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "vite build",
42
+ "clean": "rimraf dist",
43
+ "prepack": "npm run build",
44
+ "dev": "vite",
45
+ "test": "vitest",
46
+ "publish": "npm publish --access public",
47
+ "release:patch": "npm run version:patch && npm run build && npm publish --access public",
48
+ "release:minor": "npm run version:minor && npm run build && npm publish --access public",
49
+ "release:major": "npm run version:major && npm run build && npm publish --access public",
50
+ "// Git Commands": "--------------------Git Commands-------------------",
51
+ "git-commit-push": "git diff-index --quiet HEAD || (git add . && git commit -m \"Something just got updated!\" --allow-empty && git push origin main)",
52
+ "git-commit-push-force": "git add . && git commit -m \"Something just got updated!\" --no-verify --allow-empty && git push origin main --force",
53
+ "git-pull-origin-main": "git pull origin main --force"
54
+ },
55
+ "dependencies": {
56
+ "bip39": "^3.1.0"
57
+ },
58
+ "devDependencies": {
59
+ "@types/node": "^20.11.30",
60
+ "rimraf": "^6.0.1",
61
+ "rollup-plugin-copy": "^3.5.0",
62
+ "typescript": "^5.6.3",
63
+ "vite": "^5.4.8",
64
+ "vite-plugin-dts": "^4.2.1",
65
+ "vitest": "^2.0.5"
66
+ },
67
+ "keywords": [
68
+ "wordbin",
69
+ "compression",
70
+ "bip39",
71
+ "dictionary",
72
+ "binary",
73
+ "encoding",
74
+ "solana",
75
+ "ethereum",
76
+ "blockchain",
77
+ "nft",
78
+ "dapp",
79
+ "qr",
80
+ "nfc",
81
+ "iot"
82
+ ]
83
+ }