boom-format 0.9.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.
- package/LICENSE +127 -0
- package/README.md +1079 -0
- package/SPECIFICATION.md +404 -0
- package/deno.json +15 -0
- package/dist/boom.min.cjs +17 -0
- package/dist/boom.min.js +1 -0
- package/dist/boom.obf.js +1 -0
- package/dist/chunk-5PQH6SJJ.js +5148 -0
- package/dist/cli.cjs +4241 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.global.js +4249 -0
- package/dist/cli.js +313 -0
- package/dist/index.cjs +5211 -0
- package/dist/index.d.cts +779 -0
- package/dist/index.d.ts +779 -0
- package/dist/index.global.js +5172 -0
- package/dist/index.js +82 -0
- package/package.json +96 -0
- package/samples/README.md +114 -0
- package/samples/api-response.boom +0 -0
- package/samples/api-response.boom.txt +1 -0
- package/samples/api-response.json +19 -0
- package/samples/config.boom +0 -0
- package/samples/config.boom.txt +1 -0
- package/samples/config.json +22 -0
- package/samples/users.boom +0 -0
- package/samples/users.boom.txt +1 -0
- package/samples/users.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
# BOOM
|
|
2
|
+
|
|
3
|
+
**Binary Object Optimised Markup**
|
|
4
|
+
|
|
5
|
+
A compact binary serialisation format with an optional human-readable debug mode. Smaller than JSON, faster to parse, yet still debuggable.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/boom-format)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
**[Documentation](https://boomformat.dev)** | **[Getting Started](https://boomformat.dev/guide/getting-started.html)** | **[Playground](https://boomformat.dev/converter.html)** | **[Benchmarks](https://boomformat.dev/benchmarks.html)**
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🗜️ **40-70% smaller** than JSON
|
|
15
|
+
- 🧠 **50-85% fewer LLM tokens** - best-in-class for AI applications
|
|
16
|
+
- ⚡ **1.8-19x faster** than JSON (encode & decode)
|
|
17
|
+
- 📖 **299-entry dictionary** - single-byte encoding for common keys
|
|
18
|
+
- 🔍 **Human-readable debug format** - `.boom.txt`
|
|
19
|
+
- 🔄 **Self-describing** - no schema required
|
|
20
|
+
- 📦 **String interning** - automatic deduplication
|
|
21
|
+
- 🌍 **13 implementations** - JS, Go, Rust, PHP, Java, .NET, Swift, C++, Python
|
|
22
|
+
- 📝 **TypeScript-first** - full type safety
|
|
23
|
+
- 🏷️ **Script type support** - `<script type="text/boom">`
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install boom-format
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { encode, decode, stringify, parseText } from 'boom-format';
|
|
35
|
+
|
|
36
|
+
// Binary format
|
|
37
|
+
const data = {
|
|
38
|
+
name: 'Tom',
|
|
39
|
+
skills: ['TypeScript', 'Node.js'],
|
|
40
|
+
nested: { deep: { value: 42 } }
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const binary = encode(data); // Uint8Array
|
|
44
|
+
const restored = decode(binary); // Back to object
|
|
45
|
+
|
|
46
|
+
// Text format (for debugging)
|
|
47
|
+
const text = stringify(data); // Human-readable
|
|
48
|
+
const parsed = parseText(text); // Back to object
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Command Line Interface
|
|
52
|
+
|
|
53
|
+
BOOM includes a CLI for converting files between JSON and BOOM formats:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Install globally
|
|
57
|
+
npm install -g boom-format
|
|
58
|
+
|
|
59
|
+
# Or use with npx
|
|
60
|
+
npx boom --help
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Basic Usage
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Encode JSON to BOOM binary
|
|
67
|
+
boom encode data.json # Output: data.boom
|
|
68
|
+
|
|
69
|
+
# Encode JSON to BOOM text (human-readable)
|
|
70
|
+
boom encode data.json --text # Output: data.boom.txt
|
|
71
|
+
|
|
72
|
+
# Decode BOOM to JSON
|
|
73
|
+
boom decode data.boom # Output: data.json
|
|
74
|
+
boom decode data.boom.txt # Decode text format
|
|
75
|
+
|
|
76
|
+
# Show file info
|
|
77
|
+
boom info data.boom
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### CLI Options
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Usage:
|
|
84
|
+
boom encode <input.json> [output] Encode JSON to BOOM format
|
|
85
|
+
boom decode <input.boom> [output.json] Decode BOOM to JSON
|
|
86
|
+
boom info <input.boom> Show info about a BOOM file
|
|
87
|
+
boom <input.json> Shorthand for encode
|
|
88
|
+
|
|
89
|
+
Output Formats:
|
|
90
|
+
--binary, -b Output BOOM binary format (default)
|
|
91
|
+
--text, -t Output BOOM text format (.boom.txt)
|
|
92
|
+
--json, -j Output JSON format (for decode)
|
|
93
|
+
|
|
94
|
+
Options:
|
|
95
|
+
--help, -h Show this help message
|
|
96
|
+
--version, -v Show version
|
|
97
|
+
--pretty, -p Pretty-print output (JSON and text)
|
|
98
|
+
--dict, -d Use shared dictionary (default: true)
|
|
99
|
+
--no-dict Disable shared dictionary
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Stdin/Stdout Support
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Pipe from stdin
|
|
106
|
+
cat data.json | boom encode - > data.boom
|
|
107
|
+
cat data.boom | boom decode - > data.json
|
|
108
|
+
|
|
109
|
+
# Convert and pipe to another command
|
|
110
|
+
boom encode data.json | curl -X POST -H "Content-Type: application/x-boom" --data-binary @- https://api.example.com
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Sample Files
|
|
114
|
+
|
|
115
|
+
The package includes sample files in `samples/` to help you understand the format:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# View sample files
|
|
119
|
+
cat node_modules/boom-format/samples/users.boom.txt
|
|
120
|
+
|
|
121
|
+
# Test round-trip conversion
|
|
122
|
+
boom decode node_modules/boom-format/samples/users.boom --pretty
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Size Comparison
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { compare } from 'boom-format';
|
|
129
|
+
|
|
130
|
+
const data = {
|
|
131
|
+
users: [
|
|
132
|
+
{ id: 1, name: 'Alice', active: true },
|
|
133
|
+
{ id: 2, name: 'Bob', active: false },
|
|
134
|
+
{ id: 3, name: 'Charlie', active: true }
|
|
135
|
+
],
|
|
136
|
+
count: 3,
|
|
137
|
+
page: 1
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
console.log(compare(data));
|
|
141
|
+
// {
|
|
142
|
+
// jsonSize: 156,
|
|
143
|
+
// jsonMinSize: 128,
|
|
144
|
+
// boomBinarySize: 52,
|
|
145
|
+
// boomTextSize: 98,
|
|
146
|
+
// savings: { vsJson: '66.7%', vsJsonMin: '59.4%' }
|
|
147
|
+
// }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## API Reference
|
|
151
|
+
|
|
152
|
+
### Binary Format
|
|
153
|
+
|
|
154
|
+
#### `encode(value, options?): Uint8Array`
|
|
155
|
+
|
|
156
|
+
Encode a value to BOOM binary format.
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const binary = encode({ hello: 'world' });
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `decode(buffer, options?): BoomValue`
|
|
163
|
+
|
|
164
|
+
Decode BOOM binary format to a value.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const value = decode(binary);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Text Format
|
|
171
|
+
|
|
172
|
+
#### `stringify(value, options?): string`
|
|
173
|
+
|
|
174
|
+
Convert a value to BOOM text format.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const text = stringify({ name: 'Tom', age: 42 });
|
|
178
|
+
// {
|
|
179
|
+
// name: "Tom"
|
|
180
|
+
// age: 42
|
|
181
|
+
// }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### `parseText(input, options?): BoomValue`
|
|
185
|
+
|
|
186
|
+
Parse BOOM text format.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const value = parseText(`{
|
|
190
|
+
name: "Tom"
|
|
191
|
+
age: 42
|
|
192
|
+
tags: ["web" "ai"]
|
|
193
|
+
}`);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### JSON Interop
|
|
197
|
+
|
|
198
|
+
#### `fromJSON(json, options?): Uint8Array`
|
|
199
|
+
|
|
200
|
+
Convert JSON string to BOOM binary.
|
|
201
|
+
|
|
202
|
+
#### `toJSON(buffer, options?): string`
|
|
203
|
+
|
|
204
|
+
Convert BOOM binary to JSON string.
|
|
205
|
+
|
|
206
|
+
### Options
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
interface BoomOptions {
|
|
210
|
+
maxDepth?: number; // Max nesting (default: 64)
|
|
211
|
+
maxStringLength?: number; // Max string bytes (default: 16MB)
|
|
212
|
+
maxArrayLength?: number; // Max array items (default: 1M)
|
|
213
|
+
enableInterning?: boolean; // String dedup (default: true)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
interface BoomTextOptions extends BoomOptions {
|
|
217
|
+
compact?: boolean; // Single-line output
|
|
218
|
+
indentString?: string; // Indent chars (default: " ")
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Framework Integration
|
|
223
|
+
|
|
224
|
+
### React
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import { encode, decode } from 'boom-format';
|
|
228
|
+
import { useState, useEffect } from 'react';
|
|
229
|
+
|
|
230
|
+
// Custom hook for BOOM API calls
|
|
231
|
+
function useBoom<T>(url: string) {
|
|
232
|
+
const [data, setData] = useState<T | null>(null);
|
|
233
|
+
const [loading, setLoading] = useState(true);
|
|
234
|
+
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
fetch(url, { headers: { Accept: 'application/x-boom' } })
|
|
237
|
+
.then(res => res.arrayBuffer())
|
|
238
|
+
.then(buf => setData(decode(new Uint8Array(buf)) as T))
|
|
239
|
+
.finally(() => setLoading(false));
|
|
240
|
+
}, [url]);
|
|
241
|
+
|
|
242
|
+
return { data, loading };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Usage in component
|
|
246
|
+
function UserList() {
|
|
247
|
+
const { data: users, loading } = useBoom<User[]>('/api/users');
|
|
248
|
+
|
|
249
|
+
if (loading) return <div>Loading...</div>;
|
|
250
|
+
return <ul>{users?.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Next.js
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// app/api/users/route.ts (App Router)
|
|
258
|
+
import { encode, decode } from 'boom-format';
|
|
259
|
+
|
|
260
|
+
export async function GET() {
|
|
261
|
+
const users = await db.users.findMany();
|
|
262
|
+
return new Response(encode(users), {
|
|
263
|
+
headers: { 'Content-Type': 'application/x-boom' }
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export async function POST(req: Request) {
|
|
268
|
+
const body = decode(new Uint8Array(await req.arrayBuffer()));
|
|
269
|
+
const user = await db.users.create({ data: body });
|
|
270
|
+
return new Response(encode(user), {
|
|
271
|
+
headers: { 'Content-Type': 'application/x-boom' }
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Client component with Server Actions
|
|
276
|
+
'use client';
|
|
277
|
+
import { boomFetch } from 'boom-format';
|
|
278
|
+
|
|
279
|
+
export default function Dashboard() {
|
|
280
|
+
const [users, setUsers] = useState([]);
|
|
281
|
+
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
boomFetch('/api/users').then(setUsers);
|
|
284
|
+
}, []);
|
|
285
|
+
|
|
286
|
+
return <UserTable users={users} />;
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Vue 3
|
|
291
|
+
|
|
292
|
+
```vue
|
|
293
|
+
<script setup lang="ts">
|
|
294
|
+
import { ref, onMounted } from 'vue';
|
|
295
|
+
import { decode } from 'boom-format';
|
|
296
|
+
|
|
297
|
+
const users = ref<User[]>([]);
|
|
298
|
+
const loading = ref(true);
|
|
299
|
+
|
|
300
|
+
onMounted(async () => {
|
|
301
|
+
const res = await fetch('/api/users', {
|
|
302
|
+
headers: { Accept: 'application/x-boom' }
|
|
303
|
+
});
|
|
304
|
+
users.value = decode(new Uint8Array(await res.arrayBuffer()));
|
|
305
|
+
loading.value = false;
|
|
306
|
+
});
|
|
307
|
+
</script>
|
|
308
|
+
|
|
309
|
+
<template>
|
|
310
|
+
<div v-if="loading">Loading...</div>
|
|
311
|
+
<ul v-else>
|
|
312
|
+
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
|
|
313
|
+
</ul>
|
|
314
|
+
</template>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Nuxt 3
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// server/api/users.ts
|
|
321
|
+
import { encode, decode } from 'boom-format';
|
|
322
|
+
|
|
323
|
+
export default defineEventHandler(async (event) => {
|
|
324
|
+
const accept = getHeader(event, 'accept');
|
|
325
|
+
const users = await $fetch('/external-api/users');
|
|
326
|
+
|
|
327
|
+
if (accept === 'application/x-boom') {
|
|
328
|
+
setHeader(event, 'Content-Type', 'application/x-boom');
|
|
329
|
+
return encode(users);
|
|
330
|
+
}
|
|
331
|
+
return users;
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// composables/useBoom.ts
|
|
335
|
+
export function useBoom<T>(url: string) {
|
|
336
|
+
return useFetch<T>(url, {
|
|
337
|
+
headers: { Accept: 'application/x-boom' },
|
|
338
|
+
transform: (data) => decode(new Uint8Array(data))
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Redux / Redux Toolkit
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { encode, decode } from 'boom-format';
|
|
347
|
+
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
|
348
|
+
|
|
349
|
+
// Async thunk with BOOM encoding
|
|
350
|
+
export const fetchUsers = createAsyncThunk('users/fetch', async () => {
|
|
351
|
+
const res = await fetch('/api/users', {
|
|
352
|
+
headers: { Accept: 'application/x-boom' }
|
|
353
|
+
});
|
|
354
|
+
return decode(new Uint8Array(await res.arrayBuffer()));
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Persist Redux state with BOOM (40-70% smaller than JSON)
|
|
358
|
+
const persistBoom = {
|
|
359
|
+
save: (state: RootState) => {
|
|
360
|
+
localStorage.setItem('app-state',
|
|
361
|
+
btoa(String.fromCharCode(...encode(state)))
|
|
362
|
+
);
|
|
363
|
+
},
|
|
364
|
+
load: (): RootState | undefined => {
|
|
365
|
+
const saved = localStorage.getItem('app-state');
|
|
366
|
+
if (!saved) return undefined;
|
|
367
|
+
const bytes = Uint8Array.from(atob(saved), c => c.charCodeAt(0));
|
|
368
|
+
return decode(bytes) as RootState;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Mobile Development
|
|
374
|
+
|
|
375
|
+
BOOM is ideal for mobile apps - smaller payloads mean faster loads on cellular networks and better battery life.
|
|
376
|
+
|
|
377
|
+
### React Native
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { encode, decode } from 'boom-format';
|
|
381
|
+
|
|
382
|
+
// Custom fetch wrapper for React Native
|
|
383
|
+
async function boomRequest<T>(url: string, options?: RequestInit): Promise<T> {
|
|
384
|
+
const res = await fetch(url, {
|
|
385
|
+
...options,
|
|
386
|
+
headers: {
|
|
387
|
+
...options?.headers,
|
|
388
|
+
Accept: 'application/x-boom',
|
|
389
|
+
'Content-Type': options?.body ? 'application/x-boom' : undefined,
|
|
390
|
+
},
|
|
391
|
+
body: options?.body ? encode(options.body) : undefined,
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
const buffer = await res.arrayBuffer();
|
|
395
|
+
return decode(new Uint8Array(buffer)) as T;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Usage
|
|
399
|
+
const users = await boomRequest<User[]>('https://api.example.com/users');
|
|
400
|
+
|
|
401
|
+
// Offline storage with AsyncStorage (60% smaller than JSON)
|
|
402
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
403
|
+
|
|
404
|
+
const saveOffline = async (key: string, data: any) => {
|
|
405
|
+
const encoded = encode(data);
|
|
406
|
+
await AsyncStorage.setItem(key, btoa(String.fromCharCode(...encoded)));
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const loadOffline = async <T>(key: string): Promise<T | null> => {
|
|
410
|
+
const saved = await AsyncStorage.getItem(key);
|
|
411
|
+
if (!saved) return null;
|
|
412
|
+
const bytes = Uint8Array.from(atob(saved), c => c.charCodeAt(0));
|
|
413
|
+
return decode(bytes) as T;
|
|
414
|
+
};
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### iOS (Swift)
|
|
418
|
+
|
|
419
|
+
```swift
|
|
420
|
+
import Boom
|
|
421
|
+
|
|
422
|
+
// Network request with BOOM
|
|
423
|
+
func fetchUsers() async throws -> [User] {
|
|
424
|
+
var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
|
|
425
|
+
request.setValue("application/x-boom", forHTTPHeaderField: "Accept")
|
|
426
|
+
|
|
427
|
+
let (data, _) = try await URLSession.shared.data(for: request)
|
|
428
|
+
return try Boom.decode([User].self, from: data)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Encode for POST
|
|
432
|
+
func createUser(_ user: User) async throws -> User {
|
|
433
|
+
var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
|
|
434
|
+
request.httpMethod = "POST"
|
|
435
|
+
request.setValue("application/x-boom", forHTTPHeaderField: "Content-Type")
|
|
436
|
+
request.httpBody = try Boom.encode(user)
|
|
437
|
+
|
|
438
|
+
let (data, _) = try await URLSession.shared.data(for: request)
|
|
439
|
+
return try Boom.decode(User.self, from: data)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Cache to disk (uses 60% less storage than JSON)
|
|
443
|
+
let encoded = try Boom.encode(users)
|
|
444
|
+
try encoded.write(to: cacheURL)
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Android (Java/Kotlin)
|
|
448
|
+
|
|
449
|
+
```kotlin
|
|
450
|
+
import io.boomformat.Boom
|
|
451
|
+
|
|
452
|
+
// With Retrofit + custom converter
|
|
453
|
+
val retrofit = Retrofit.Builder()
|
|
454
|
+
.baseUrl("https://api.example.com/")
|
|
455
|
+
.addConverterFactory(BoomConverterFactory.create())
|
|
456
|
+
.build()
|
|
457
|
+
|
|
458
|
+
interface ApiService {
|
|
459
|
+
@GET("users")
|
|
460
|
+
@Headers("Accept: application/x-boom")
|
|
461
|
+
suspend fun getUsers(): List<User>
|
|
462
|
+
|
|
463
|
+
@POST("users")
|
|
464
|
+
@Headers("Content-Type: application/x-boom")
|
|
465
|
+
suspend fun createUser(@Body user: User): User
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Direct usage
|
|
469
|
+
val users = Boom.decode<List<User>>(response.bytes())
|
|
470
|
+
val encoded = Boom.encode(newUser)
|
|
471
|
+
|
|
472
|
+
// Room database with BOOM serialization (smaller DB files)
|
|
473
|
+
@TypeConverter
|
|
474
|
+
fun fromBoom(data: ByteArray): UserData = Boom.decode(data)
|
|
475
|
+
|
|
476
|
+
@TypeConverter
|
|
477
|
+
fun toBoom(userData: UserData): ByteArray = Boom.encode(userData)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Why BOOM for Mobile?
|
|
481
|
+
|
|
482
|
+
| Benefit | Impact |
|
|
483
|
+
|---------|--------|
|
|
484
|
+
| **40-70% smaller payloads** | Faster downloads on 3G/4G/5G |
|
|
485
|
+
| **2-5x faster parsing** | Smoother UI, less jank |
|
|
486
|
+
| **Less data transfer** | Lower cellular bills, data caps |
|
|
487
|
+
| **Reduced battery drain** | Less radio usage, less CPU |
|
|
488
|
+
| **Offline storage** | 60% smaller cache files |
|
|
489
|
+
| **Native SDKs** | Swift, Java, C++ - no bridging overhead |
|
|
490
|
+
|
|
491
|
+
## Browser Usage
|
|
492
|
+
|
|
493
|
+
### Script Type
|
|
494
|
+
|
|
495
|
+
BOOM supports inline data via `<script type="text/boom">`:
|
|
496
|
+
|
|
497
|
+
```html
|
|
498
|
+
<script type="text/boom" id="config">
|
|
499
|
+
{
|
|
500
|
+
apiUrl: "https://api.example.com"
|
|
501
|
+
features: {
|
|
502
|
+
darkMode: true
|
|
503
|
+
analytics: false
|
|
504
|
+
}
|
|
505
|
+
limits: [100 200 500]
|
|
506
|
+
}
|
|
507
|
+
</script>
|
|
508
|
+
|
|
509
|
+
<script type="module">
|
|
510
|
+
import { processBoomScripts, getBoomData } from 'boom-format';
|
|
511
|
+
|
|
512
|
+
// Process all boom scripts
|
|
513
|
+
processBoomScripts();
|
|
514
|
+
|
|
515
|
+
// Get specific data
|
|
516
|
+
const config = getBoomData('config');
|
|
517
|
+
console.log(config.apiUrl);
|
|
518
|
+
</script>
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Auto-initialisation
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
import { autoInit } from 'boom-format';
|
|
525
|
+
|
|
526
|
+
// Automatically process boom scripts when DOM is ready
|
|
527
|
+
autoInit();
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### CDN Usage
|
|
531
|
+
|
|
532
|
+
```html
|
|
533
|
+
<script type="module">
|
|
534
|
+
import * as boom from 'https://esm.sh/boom-format';
|
|
535
|
+
|
|
536
|
+
const data = boom.parseText('{name: "Tom"}');
|
|
537
|
+
</script>
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## Text Format Syntax
|
|
541
|
+
|
|
542
|
+
```boom
|
|
543
|
+
# Comments start with #
|
|
544
|
+
|
|
545
|
+
# Strings (quoted)
|
|
546
|
+
name: "Tom Taylor"
|
|
547
|
+
|
|
548
|
+
# Numbers (bare)
|
|
549
|
+
age: 42
|
|
550
|
+
price: 19.99
|
|
551
|
+
bignum: 9007199254740993n # BigInt
|
|
552
|
+
|
|
553
|
+
# Booleans & null
|
|
554
|
+
active: true
|
|
555
|
+
deleted: false
|
|
556
|
+
metadata: null
|
|
557
|
+
|
|
558
|
+
# Arrays (space or newline separated)
|
|
559
|
+
tags: ["web" "ai" "performance"]
|
|
560
|
+
matrix: [
|
|
561
|
+
[1 2 3]
|
|
562
|
+
[4 5 6]
|
|
563
|
+
]
|
|
564
|
+
|
|
565
|
+
# Nested objects
|
|
566
|
+
user: {
|
|
567
|
+
name: "Tom"
|
|
568
|
+
address: {
|
|
569
|
+
city: "Liverpool"
|
|
570
|
+
country: "UK"
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
# Arrays of objects
|
|
575
|
+
users: [
|
|
576
|
+
{ id: 1 name: "Alice" }
|
|
577
|
+
{ id: 2 name: "Bob" }
|
|
578
|
+
]
|
|
579
|
+
|
|
580
|
+
# Binary data (base64)
|
|
581
|
+
avatar: <binary:SGVsbG8gV29ybGQ=>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Binary Format Specification
|
|
585
|
+
|
|
586
|
+
See [SPECIFICATION.md](./SPECIFICATION.md) for the full binary format specification.
|
|
587
|
+
|
|
588
|
+
### Header
|
|
589
|
+
|
|
590
|
+
| Offset | Size | Description |
|
|
591
|
+
|--------|------|-------------|
|
|
592
|
+
| 0 | 4 | Magic: `BOOM` (0x42 0x4F 0x4F 0x4D) |
|
|
593
|
+
| 4 | 1 | Version: 0x01 |
|
|
594
|
+
| 5 | 1 | Flags (reserved) |
|
|
595
|
+
| 6 | ... | Root value |
|
|
596
|
+
|
|
597
|
+
### Type Markers
|
|
598
|
+
|
|
599
|
+
| Byte | Type |
|
|
600
|
+
|------|------|
|
|
601
|
+
| 0x00 | null |
|
|
602
|
+
| 0x01 | false |
|
|
603
|
+
| 0x02 | true |
|
|
604
|
+
| 0x10-0x19 | integers (various sizes) |
|
|
605
|
+
| 0x20-0x21 | floats |
|
|
606
|
+
| 0x30 | string |
|
|
607
|
+
| 0x31 | binary |
|
|
608
|
+
| 0x40 | array |
|
|
609
|
+
| 0x50 | object |
|
|
610
|
+
| 0x60 | string reference (local interning) |
|
|
611
|
+
| 0x61 | dictionary reference (shared dictionary) |
|
|
612
|
+
|
|
613
|
+
## Built-in Dictionary
|
|
614
|
+
|
|
615
|
+
BOOM includes a shared dictionary of **299 common strings** optimized for API responses, LLM streaming, and analytics data. Strings in the dictionary are encoded as 1-2 byte references instead of full UTF-8. The first 128 entries (indices 0-127) use single-byte varint encoding for maximum efficiency.
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import { encode, decode, BOOM_DICTIONARY_V1, analyzeDictionary } from 'boom-format';
|
|
619
|
+
|
|
620
|
+
// Dictionary is used automatically
|
|
621
|
+
const data = {
|
|
622
|
+
id: 1,
|
|
623
|
+
status: 'active', // "id" and "status" are in dictionary
|
|
624
|
+
role: 'assistant', // "role" and "assistant" are in dictionary
|
|
625
|
+
content: 'Hello!' // "content" is in dictionary
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
const encoded = encode(data); // Keys encoded as 1-byte refs
|
|
629
|
+
|
|
630
|
+
// Analyze dictionary coverage
|
|
631
|
+
const analysis = analyzeDictionary(data);
|
|
632
|
+
console.log(analysis.stats.dictionaryHitRate); // e.g., 0.85 (85% hit rate)
|
|
633
|
+
console.log(analysis.missingStrings); // Strings not in dictionary
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Dictionary Contents (First 128 = 1-byte encoding)
|
|
637
|
+
|
|
638
|
+
The first 128 entries get optimal 1-byte encoding:
|
|
639
|
+
|
|
640
|
+
- **Core keys**: id, type, name, status, data, value, content, message, error
|
|
641
|
+
- **AI/LLM**: role, model, choices, delta, finish_reason, usage, prompt_tokens, completion_tokens
|
|
642
|
+
- **API patterns**: request, response, params, headers, body, method, url, path
|
|
643
|
+
- **Timestamps**: created_at, updated_at, timestamp, expires_at
|
|
644
|
+
- **Status values**: active, pending, completed, failed, enabled, disabled
|
|
645
|
+
- **HTTP**: GET, POST, PUT, DELETE, Content-Type, Authorization
|
|
646
|
+
|
|
647
|
+
### Disable Dictionary
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
const encoded = encode(data, { useBuiltInDictionary: false });
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### Strict Binary Mode (Production Security)
|
|
654
|
+
|
|
655
|
+
Reject non-BOOM input to prevent JSON injection attacks:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
const decoded = decode(buffer, { strictBinaryMode: true });
|
|
659
|
+
// Throws if buffer doesn't start with BOOM magic bytes
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
## TypeScript Support
|
|
663
|
+
|
|
664
|
+
Full type definitions included:
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
import type { BoomValue, BoomObject, BoomArray, BoomOptions } from 'boom-format';
|
|
668
|
+
|
|
669
|
+
const data: BoomObject = {
|
|
670
|
+
name: 'Tom',
|
|
671
|
+
scores: [100, 95, 88] as BoomArray,
|
|
672
|
+
};
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
## Error Handling
|
|
676
|
+
|
|
677
|
+
```typescript
|
|
678
|
+
import { encode, decode, BoomError } from 'boom-format';
|
|
679
|
+
|
|
680
|
+
try {
|
|
681
|
+
const value = decode(corruptedData);
|
|
682
|
+
} catch (error) {
|
|
683
|
+
if (error instanceof BoomError) {
|
|
684
|
+
console.error('Invalid BOOM data:', error.message);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
## Benchmarks
|
|
690
|
+
|
|
691
|
+
Run benchmarks:
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
npm run benchmark # Size/token benchmarks
|
|
695
|
+
npm run benchmark:compare # Full format comparison with speed tests
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Speed Benchmarks (Node.js v22)
|
|
699
|
+
|
|
700
|
+
BOOM is optimised for real-world data with repeated strings (API responses, logs, exports):
|
|
701
|
+
|
|
702
|
+
| Data Type | JSON Size | BOOM Size | Savings | Encode Speed | Decode Speed |
|
|
703
|
+
|-----------|-----------|-----------|---------|--------------|--------------|
|
|
704
|
+
| **Small** | 37 bytes | 35 bytes | **5.4%** | **2x faster** | **2x faster** |
|
|
705
|
+
| **Medium** | 9,727 bytes | 5,389 bytes | **44.6%** | **1.3x faster** | **1.1x faster** |
|
|
706
|
+
| **Tabular (500 rows)** | 52,226 bytes | 18,093 bytes | **65.4%** | **2x faster** | **2.5x faster** |
|
|
707
|
+
| **Large (float matrix)** | 192,966 bytes | 80,291 bytes | **58.4%** | **8x faster** | **19x faster** |
|
|
708
|
+
|
|
709
|
+
For typical API data, BOOM is **1.3-2x faster** than JSON for encoding and **1.1-2.5x faster** for decoding.
|
|
710
|
+
Float matrices benefit most from native binary encoding: **8-19x faster**.
|
|
711
|
+
|
|
712
|
+
### Cross-Language Performance
|
|
713
|
+
|
|
714
|
+
BOOM is available in 13 implementations with consistent performance:
|
|
715
|
+
|
|
716
|
+
| Language | Encode Speed | Decode Speed | Size Savings |
|
|
717
|
+
|----------|-------------|--------------|--------------|
|
|
718
|
+
| **JavaScript** | **1.3-2x faster** | **1.1-2.5x faster** | 40-65% |
|
|
719
|
+
| **Go** | **2.0-2.6x faster** | **3.6-4.1x faster** | 40-70% |
|
|
720
|
+
| **Rust** | **2x+ faster** | **2x+ faster** | 40-70% |
|
|
721
|
+
| **C++** | **1.3-3.2x faster** | **1.5-1.6x faster** | 29-69% |
|
|
722
|
+
| **Java** | ~1x (Jackson optimized) | **2.8-5.3x faster** | 36-73% |
|
|
723
|
+
| **.NET** | **1.3-2.7x faster** | **3.4-4.9x faster** | 36-72% |
|
|
724
|
+
| **PHP** (C ext) | **1.2x faster** | **1.4x faster** | 40-70% |
|
|
725
|
+
| **Swift** | **2.2x faster** | **3.5x faster** | 40-70% |
|
|
726
|
+
|
|
727
|
+
**Key findings:**
|
|
728
|
+
- BOOM decode is **1.5-5x faster** than JSON across all languages
|
|
729
|
+
- BOOM encode is **1.2-3x faster** in most languages
|
|
730
|
+
- Float/binary data sees **8-19x** speedup
|
|
731
|
+
- Size savings of **36-73%** depending on data structure
|
|
732
|
+
- Tabular data with repeated strings shows the best improvements
|
|
733
|
+
|
|
734
|
+
### Cross-Platform Compatibility (Production-Safe)
|
|
735
|
+
|
|
736
|
+
BOOM is **100% compatible** across all backend providers and mobile/frontend consumers. Every provider-consumer combination is automatically tested on every commit.
|
|
737
|
+
|
|
738
|
+
| Backend Provider | iOS (Swift) | Android (Java) | Web (JS) | Native (C++) |
|
|
739
|
+
|-----------------|-------------|----------------|----------|--------------|
|
|
740
|
+
| **Go** | ✅ | ✅ | ✅ | ✅ |
|
|
741
|
+
| **PHP** | ✅ | ✅ | ✅ | ✅ |
|
|
742
|
+
| **Rust** | ✅ | ✅ | ✅ | ✅ |
|
|
743
|
+
| **Java** | ✅ | ✅ | ✅ | ✅ |
|
|
744
|
+
| **.NET** | ✅ | ✅ | ✅ | ✅ |
|
|
745
|
+
| **Node.js** | ✅ | ✅ | ✅ | ✅ |
|
|
746
|
+
|
|
747
|
+
**Why this matters:**
|
|
748
|
+
- **Safe for production** - Any backend can serve any mobile app
|
|
749
|
+
- **CI-verified** - Automated tests on every commit via GitHub Actions
|
|
750
|
+
- **No surprises** - Binary format is byte-for-byte consistent
|
|
751
|
+
- **Mix and match** - Use different providers for different services
|
|
752
|
+
|
|
753
|
+
See [Interoperability Tests](https://boomformat.dev/interoperability.html) for live CI results.
|
|
754
|
+
|
|
755
|
+
#### Go Performance
|
|
756
|
+
|
|
757
|
+
```
|
|
758
|
+
go test -bench=. -benchmem
|
|
759
|
+
|
|
760
|
+
Encode Small: BOOM 775ns vs JSON 1,619ns = 2.1x faster
|
|
761
|
+
Encode Medium: BOOM 131µs vs JSON 312µs = 2.4x faster
|
|
762
|
+
Decode Small: BOOM 787ns vs JSON 3,210ns = 4.1x faster
|
|
763
|
+
Decode Medium: BOOM 111µs vs JSON 352µs = 3.2x faster
|
|
764
|
+
Size savings: 48.3%
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### Java Performance (vs Jackson)
|
|
768
|
+
|
|
769
|
+
```
|
|
770
|
+
mvn exec:java
|
|
771
|
+
|
|
772
|
+
Decode Small: BOOM 1,083K ops/s vs Jackson 204K ops/s = 5.3x faster
|
|
773
|
+
Decode Medium: BOOM 20.4K ops/s vs Jackson 7.3K ops/s = 2.8x faster
|
|
774
|
+
Decode Tabular: BOOM 5.1K ops/s vs Jackson 1.2K ops/s = 4.4x faster
|
|
775
|
+
Size savings: 36% (medium), 73% (tabular)
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
#### .NET Performance (vs System.Text.Json)
|
|
779
|
+
|
|
780
|
+
```
|
|
781
|
+
dotnet run -c Release
|
|
782
|
+
|
|
783
|
+
Decode Small: BOOM 411ns vs JSON 1,572ns = 3.8x faster
|
|
784
|
+
Decode Medium: BOOM 72µs vs JSON 349µs = 4.9x faster
|
|
785
|
+
Decode Tabular: BOOM 578µs vs JSON 1,973µs = 3.4x faster
|
|
786
|
+
Encode Small: BOOM 447ns vs JSON 588ns = 1.3x faster
|
|
787
|
+
Encode Medium: BOOM 48µs vs JSON 101µs = 2.1x faster
|
|
788
|
+
Encode Tabular: BOOM 255µs vs JSON 700µs = 2.7x faster
|
|
789
|
+
Size savings: 36% (medium), 72% (tabular)
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
#### PHP Performance (Native C Extension)
|
|
793
|
+
|
|
794
|
+
```
|
|
795
|
+
php benchmark.php
|
|
796
|
+
|
|
797
|
+
Decode: BOOM Native 1.92x faster than json_decode
|
|
798
|
+
Size savings: 49%
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
#### Rust Performance
|
|
802
|
+
|
|
803
|
+
Rust's `serde_json` is highly optimized. BOOM trades speed for size:
|
|
804
|
+
|
|
805
|
+
```
|
|
806
|
+
cargo bench
|
|
807
|
+
|
|
808
|
+
Size savings: 66.3% on tabular data
|
|
809
|
+
Note: serde_json is faster for pure speed, but BOOM reduces network transfer significantly
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Payload Size Thresholds (Optional)
|
|
813
|
+
|
|
814
|
+
BOOM includes an **optional** threshold system for automatic format selection based on payload size. This is a tuning mechanism for users who want to optimize for their specific use case.
|
|
815
|
+
|
|
816
|
+
> **Note:** This feature is entirely optional. BOOM aims to be faster than JSON for all sizes, but the threshold system allows fine-tuning for edge cases where native JSON implementations may have slightly less overhead for very small payloads.
|
|
817
|
+
|
|
818
|
+
#### Default Thresholds (Benchmark-Based)
|
|
819
|
+
|
|
820
|
+
| Payload Size | Default Format | Reason |
|
|
821
|
+
|--------------|----------------|--------|
|
|
822
|
+
| < 1KB | JSON | Native JSON may have less overhead |
|
|
823
|
+
| 1KB - 100KB | BOOM Binary | Good balance of speed and size |
|
|
824
|
+
| > 100KB | BOOM Binary (forced) | Significant size/speed benefits |
|
|
825
|
+
|
|
826
|
+
#### Configuration
|
|
827
|
+
|
|
828
|
+
```typescript
|
|
829
|
+
import { setThresholdConfig, selectFormat, estimateSize } from 'boom-format';
|
|
830
|
+
|
|
831
|
+
// Configure thresholds (optional - defaults work well for most cases)
|
|
832
|
+
setThresholdConfig({
|
|
833
|
+
minSize: 1024, // Below: may use JSON (default: 1KB)
|
|
834
|
+
preferSize: 10240, // Above: prefer BOOM (default: 10KB)
|
|
835
|
+
forceSize: 102400, // Above: always BOOM (default: 100KB)
|
|
836
|
+
autoDetect: true, // Enable auto format selection
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// Auto-select format based on estimated size
|
|
840
|
+
const data = { users: [...] };
|
|
841
|
+
const { mode, reason } = selectFormat(estimateSize(data));
|
|
842
|
+
// mode: 'boom-binary' or 'json'
|
|
843
|
+
// reason: 'size-below-threshold', 'size-above-force', etc.
|
|
844
|
+
|
|
845
|
+
// Or use with boomFetch for automatic selection
|
|
846
|
+
const result = await boomFetch('/api/data', {
|
|
847
|
+
body: largePayload,
|
|
848
|
+
autoFormat: true, // Automatically selects format based on size
|
|
849
|
+
});
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
#### HTTP Header Negotiation
|
|
853
|
+
|
|
854
|
+
Servers can announce their threshold policy, and clients can hint expected payload sizes:
|
|
855
|
+
|
|
856
|
+
```
|
|
857
|
+
# Server response headers
|
|
858
|
+
X-Boom-Min-Size: 1024
|
|
859
|
+
X-Boom-Prefer-Size: 10240
|
|
860
|
+
X-Boom-Force-Size: 102400
|
|
861
|
+
|
|
862
|
+
# Client request header
|
|
863
|
+
X-Boom-Expected-Size: large # or 'small', or byte count like '50000'
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
```typescript
|
|
867
|
+
import { createThresholdHeaders, parseThresholdHeaders } from 'boom-format';
|
|
868
|
+
|
|
869
|
+
// Server: Create headers to announce policy
|
|
870
|
+
app.use((req, res, next) => {
|
|
871
|
+
const headers = createThresholdHeaders();
|
|
872
|
+
Object.entries(headers).forEach(([k, v]) => res.setHeader(k, v));
|
|
873
|
+
next();
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
// Client: Parse server's threshold policy
|
|
877
|
+
const serverConfig = parseThresholdHeaders(response.headers);
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
#### When to Use Thresholds
|
|
881
|
+
|
|
882
|
+
- **Most users:** Don't need to configure thresholds - defaults work well
|
|
883
|
+
- **API developers:** May want to tune based on typical payload sizes
|
|
884
|
+
- **Performance-critical apps:** Can fine-tune based on their specific data patterns
|
|
885
|
+
- **Hybrid environments:** Useful when some clients don't support BOOM
|
|
886
|
+
|
|
887
|
+
### BOOM vs JSON + HTTP Compression
|
|
888
|
+
|
|
889
|
+
Modern HTTP/2 and HTTP/3 use compression (gzip, brotli, deflate). BOOM still wins:
|
|
890
|
+
|
|
891
|
+
| Data Type | JSON | JSON+gzip | JSON+brotli | BOOM | BOOM+brotli |
|
|
892
|
+
|-----------|------|-----------|-------------|------|-------------|
|
|
893
|
+
| **Small** (3 keys) | 39 B | 59 B | 43 B | **37 B** | 41 B |
|
|
894
|
+
| **Medium** (100 rows) | 8,109 B | 1,064 B | 597 B | **4,623 B** | **624 B** |
|
|
895
|
+
| **Tabular** (500 rows) | 75,176 B | 523 B | 137 B | **39,587 B** | 191 B |
|
|
896
|
+
| **API Response** | 6,967 B | 719 B | 462 B | **3,071 B** | 554 B |
|
|
897
|
+
|
|
898
|
+
**Key findings:**
|
|
899
|
+
|
|
900
|
+
1. **BOOM uncompressed is 40-70% smaller than JSON** - before any HTTP compression
|
|
901
|
+
2. **For tabular data, BOOM is smaller than JSON+gzip** - string interning eliminates redundancy at source
|
|
902
|
+
3. **BOOM + HTTP compression works** - BOOM can be further compressed via gzip/brotli
|
|
903
|
+
4. **No CPU overhead difference** - both formats get HTTP-compressed anyway
|
|
904
|
+
|
|
905
|
+
**For HTTP/2 and HTTP/3:**
|
|
906
|
+
```
|
|
907
|
+
# Server returns BOOM binary
|
|
908
|
+
Content-Type: application/x-boom
|
|
909
|
+
Content-Encoding: br # Brotli compression by HTTP layer
|
|
910
|
+
|
|
911
|
+
# Result: Smallest possible payload + fast binary parsing
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
**Recommendation:**
|
|
915
|
+
- API servers: Return BOOM binary, let HTTP layer handle compression
|
|
916
|
+
- Mobile apps: Accept BOOM binary, benefit from smaller downloads + faster parsing
|
|
917
|
+
- Web apps: Accept BOOM binary, faster parsing than JSON even after decompression
|
|
918
|
+
|
|
919
|
+
Run the compression comparison:
|
|
920
|
+
```bash
|
|
921
|
+
node benchmark/compression-comparison.cjs
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
### Why BOOM Wins for LLM Use Cases
|
|
925
|
+
|
|
926
|
+
| Metric | JSON | BOOM Binary | Winner |
|
|
927
|
+
|--------|------|-------------|--------|
|
|
928
|
+
| Decoding speed | Baseline | **240% faster** | **BOOM** |
|
|
929
|
+
| Encoding speed | Baseline | **125%** | **BOOM** |
|
|
930
|
+
| Payload size | 52KB | 18KB | **BOOM (65% smaller)** |
|
|
931
|
+
| Token count | ~13,000 | ~5,700 | **BOOM (56% fewer)** |
|
|
932
|
+
| Network transfer | Slower | **Faster** | **BOOM** |
|
|
933
|
+
| LLM processing | Slower | **Faster** | **BOOM** |
|
|
934
|
+
| API cost | $X | **$0.44X** | **BOOM (56% cheaper)** |
|
|
935
|
+
|
|
936
|
+
For the typical LLM workflow:
|
|
937
|
+
- Network latency (50-200ms) dominates
|
|
938
|
+
- LLM inference time (500-5000ms) is the bottleneck
|
|
939
|
+
- BOOM's size reduction speeds up both network AND inference
|
|
940
|
+
- BOOM decode being 2.4x faster helps when processing responses
|
|
941
|
+
|
|
942
|
+
## Format Comparison
|
|
943
|
+
|
|
944
|
+
BOOM vs JSON, TRON, TOON, YAML, XML, CSV, and VSC - comprehensive benchmarks across different data structures.
|
|
945
|
+
|
|
946
|
+
### Token Efficiency Rankings (LLM cost savings vs JSON)
|
|
947
|
+
|
|
948
|
+
| Rank | Format | Avg Token Reduction | Data Support |
|
|
949
|
+
|------|--------|---------------------|--------------|
|
|
950
|
+
| **1** | **BOOM binary** | **68.6%** | **All data types** |
|
|
951
|
+
| 2 | VSC | 64.5% | Flat tabular only |
|
|
952
|
+
| 3 | CSV | 63.8% | Flat tabular only |
|
|
953
|
+
| 4 | TRON | 55.2% | Uniform arrays only |
|
|
954
|
+
| 5 | TOON | 50.8% | Uniform arrays only |
|
|
955
|
+
| 6 | YAML | 20.6% | All data types |
|
|
956
|
+
| 7 | BOOM text | 3.9% | All data types |
|
|
957
|
+
| 8 | XML | -46.3% (more!) | All data types |
|
|
958
|
+
|
|
959
|
+
**Key insight:** BOOM binary beats CSV/VSC on token efficiency while supporting ALL data structures, including nested objects.
|
|
960
|
+
|
|
961
|
+
### Size Efficiency (bytes saved vs JSON)
|
|
962
|
+
|
|
963
|
+
| Format | Simple Data | Employees (100) | Nested Orders | Deep Config | API Response |
|
|
964
|
+
|--------|-------------|-----------------|---------------|-------------|--------------|
|
|
965
|
+
| **BOOM binary** | **6%** | **63%** | **53%** | **24%** | **36%** |
|
|
966
|
+
| TRON | 12% | 48% | 58% | -12% | 24% |
|
|
967
|
+
| TOON | 16% | 51% | 64% | -18% | 27% |
|
|
968
|
+
| CSV/VSC* | - | 57% | 65% | - | - |
|
|
969
|
+
| YAML | 13% | -11% | -23% | -18% | -25% |
|
|
970
|
+
| XML | -67% | -87% | -124% | -106% | -157% |
|
|
971
|
+
|
|
972
|
+
*CSV/VSC only work for flat tabular data
|
|
973
|
+
|
|
974
|
+
### Why BOOM Beats TRON & TOON
|
|
975
|
+
|
|
976
|
+
[TRON](https://github.com/nicois/tron) and [TOON](https://toonformat.dev) claim fewer tokens than JSON. Our benchmarks show:
|
|
977
|
+
- **BOOM binary: 80.6% fewer tokens than JSON**
|
|
978
|
+
- **TRON: 55.2% fewer tokens than JSON**
|
|
979
|
+
- **TOON: 50.8% fewer tokens than JSON**
|
|
980
|
+
- **BOOM uses 31.2% fewer tokens than TRON**
|
|
981
|
+
- **BOOM uses 37.8% fewer tokens than TOON**
|
|
982
|
+
|
|
983
|
+
| Metric | BOOM Binary | TRON | TOON | Winner |
|
|
984
|
+
|--------|-------------|------|------|--------|
|
|
985
|
+
| Token savings vs JSON | 80.6% | 55.2% | 50.8% | **BOOM** |
|
|
986
|
+
| Nested structures | Excellent | Poor | Poor | **BOOM** |
|
|
987
|
+
| Mixed data types | Full support | Limited | Limited | **BOOM** |
|
|
988
|
+
| Binary data | Native | None | None | **BOOM** |
|
|
989
|
+
| Schema required | No | No | No | Tie |
|
|
990
|
+
| Human readable | Via .boom.txt | Yes | Yes | TRON/TOON |
|
|
991
|
+
|
|
992
|
+
**TRON & TOON limitations:**
|
|
993
|
+
- Only efficient for uniform arrays of objects
|
|
994
|
+
- Nested structures lose efficiency
|
|
995
|
+
- No binary format option
|
|
996
|
+
- No string interning
|
|
997
|
+
|
|
998
|
+
**BOOM advantages:**
|
|
999
|
+
- Efficient for ALL data structures
|
|
1000
|
+
- Binary format for maximum compression
|
|
1001
|
+
- String interning for repeated values
|
|
1002
|
+
- Native BigInt and binary data support
|
|
1003
|
+
- Self-describing (no schema needed)
|
|
1004
|
+
|
|
1005
|
+
### Real-World Example
|
|
1006
|
+
|
|
1007
|
+
```javascript
|
|
1008
|
+
// 100-employee directory
|
|
1009
|
+
const data = {
|
|
1010
|
+
context: { task: 'Employee directory', department: 'Engineering' },
|
|
1011
|
+
employees: Array.from({ length: 100 }, (_, i) => ({
|
|
1012
|
+
id: i + 1,
|
|
1013
|
+
name: `Employee ${i + 1}`,
|
|
1014
|
+
email: `emp${i + 1}@company.com`,
|
|
1015
|
+
department: ['Engineering', 'Sales', 'Marketing', 'HR'][i % 4],
|
|
1016
|
+
salary: 50000 + (i * 500),
|
|
1017
|
+
active: i % 5 !== 0
|
|
1018
|
+
})),
|
|
1019
|
+
total: 100
|
|
1020
|
+
};
|
|
1021
|
+
|
|
1022
|
+
// Results:
|
|
1023
|
+
// JSON: 11,165 bytes | 5,993 tokens
|
|
1024
|
+
// TRON: 5,812 bytes | 2,687 tokens (48% smaller, 55% fewer tokens)
|
|
1025
|
+
// TOON: 5,499 bytes | 2,299 tokens (51% smaller, 62% fewer tokens)
|
|
1026
|
+
// BOOM binary: 4,134 bytes | 1,378 tokens (63% smaller, 77% fewer tokens)
|
|
1027
|
+
// CSV: 5,209 bytes | 2,261 tokens (flat array only)
|
|
1028
|
+
// VSC: 4,850 bytes | 2,224 tokens (flat array only)
|
|
1029
|
+
// XML: 20,837 bytes | 8,417 tokens (87% larger!)
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
**BOOM wins on both size AND tokens** - with tabular encoding, BOOM binary beats CSV/VSC for flat data too.
|
|
1033
|
+
|
|
1034
|
+
### When to Use Each Format
|
|
1035
|
+
|
|
1036
|
+
| Format | Use When |
|
|
1037
|
+
|--------|----------|
|
|
1038
|
+
| **BOOM binary** | LLM API calls, AI agents, maximum efficiency |
|
|
1039
|
+
| **BOOM text** | Debugging, config files, human editing |
|
|
1040
|
+
| JSON | Interoperability with existing systems |
|
|
1041
|
+
| TRON | Uniform tabular data, human-readable priority |
|
|
1042
|
+
| TOON | Uniform tabular data, human-readable priority |
|
|
1043
|
+
| YAML | Human-edited config files |
|
|
1044
|
+
| CSV/VSC | Flat tabular data, spreadsheet export |
|
|
1045
|
+
| XML | Never for LLMs (2x the tokens of JSON) |
|
|
1046
|
+
|
|
1047
|
+
Run the full comparison benchmark:
|
|
1048
|
+
```bash
|
|
1049
|
+
node benchmark/format-comparison.js
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
## Contributing
|
|
1053
|
+
|
|
1054
|
+
1. Fork the repository
|
|
1055
|
+
2. Create a feature branch
|
|
1056
|
+
3. Run tests: `npm test`
|
|
1057
|
+
4. Submit a merge request
|
|
1058
|
+
|
|
1059
|
+
## License
|
|
1060
|
+
|
|
1061
|
+
MIT © Tom Taylor
|
|
1062
|
+
|
|
1063
|
+
## Links
|
|
1064
|
+
|
|
1065
|
+
- **Website**: [boomformat.dev](https://boomformat.dev)
|
|
1066
|
+
- **npm**: [npmjs.com/package/boom-format](https://www.npmjs.com/package/boom-format)
|
|
1067
|
+
- **Go**: [pkg.go.dev/github.com/t0mtaylor/boom-format/go](https://pkg.go.dev/github.com/t0mtaylor/boom-format/go)
|
|
1068
|
+
- **Rust**: [crates.io/crates/boom-format](https://crates.io/crates/boom-format)
|
|
1069
|
+
- **Java**: [Maven Central](https://central.sonatype.com/artifact/io.boom-format/boom)
|
|
1070
|
+
- **.NET**: [NuGet](https://www.nuget.org/packages/BoomFormat)
|
|
1071
|
+
- **PHP**: [Packagist](https://packagist.org/packages/boom-format/boom)
|
|
1072
|
+
- **Swift**: [Swift Package](https://github.com/t0mtaylor/boom-format)
|
|
1073
|
+
- **C++**: [Header-only](https://github.com/t0mtaylor/boom-format/tree/main/plugins/cpp)
|
|
1074
|
+
|
|
1075
|
+
---
|
|
1076
|
+
|
|
1077
|
+
Made with ❤️ by [The Tom Taylor Company](https://tomtaylor.co.uk) • [𝕏 @tom_taylor](https://x.com/tom_taylor)
|
|
1078
|
+
|
|
1079
|
+

|