Skip to content

Commit 6ee0fb3

Browse files
committed
feat(dlx): unify .dlx-metadata.json schema across implementations
Standardize metadata format for cached binaries to be consistent across TypeScript dlxBinary and C++ socket_macho_decompress implementations. Changes: - Add DlxMetadata interface with comprehensive documentation - Update writeMetadata() to use unified schema with core fields - Add support for source tracking (download vs decompression) - Include cache_key, size, and checksum_algorithm fields - Maintain backward compatibility in listDlxCache() reader - Export DlxMetadata interface as canonical schema reference Schema structure: - Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source - Extra fields: Reserved for implementation-specific data (e.g., compression metrics for C++ decompressor) Note: Uses SHA-256 for checksums (C++ uses SHA-512)
1 parent 8d24c85 commit 6ee0fb3

File tree

1 file changed

+129
-8
lines changed

1 file changed

+129
-8
lines changed

src/dlx-binary.ts

Lines changed: 129 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,90 @@ export interface DlxBinaryResult {
4141
spawnPromise: ReturnType<typeof spawn>
4242
}
4343

44+
/**
45+
* Metadata structure for cached binaries (.dlx-metadata.json).
46+
* Unified schema shared across TypeScript (dlxBinary) and C++ (socket_macho_decompress).
47+
*
48+
* Core Fields (present in all implementations):
49+
* - version: Schema version (currently "1.0.0")
50+
* - cache_key: First 16 chars of SHA-512 hash (matches directory name)
51+
* - timestamp: Unix timestamp in milliseconds
52+
* - checksum: Full hash of cached binary (SHA-512 for C++, SHA-256 for TypeScript)
53+
* - checksum_algorithm: "sha512" or "sha256"
54+
* - platform: "darwin" | "linux" | "win32"
55+
* - arch: "x64" | "arm64"
56+
* - size: Size of cached binary in bytes
57+
* - source: Origin information
58+
* - type: "download" (from URL) or "decompression" (from embedded binary)
59+
* - url: Download URL (if type is "download")
60+
* - path: Source binary path (if type is "decompression")
61+
*
62+
* Extra Fields (implementation-specific):
63+
* - For C++ decompression:
64+
* - compressed_size: Size of compressed data in bytes
65+
* - compression_algorithm: Brotli level (numeric)
66+
* - compression_ratio: original_size / compressed_size
67+
*
68+
* Example (TypeScript download):
69+
* ```json
70+
* {
71+
* "version": "1.0.0",
72+
* "cache_key": "a1b2c3d4e5f67890",
73+
* "timestamp": 1730332800000,
74+
* "checksum": "sha256-abc123...",
75+
* "checksum_algorithm": "sha256",
76+
* "platform": "darwin",
77+
* "arch": "arm64",
78+
* "size": 15000000,
79+
* "source": {
80+
* "type": "download",
81+
* "url": "https://example.com/binary"
82+
* }
83+
* }
84+
* ```
85+
*
86+
* Example (C++ decompression):
87+
* ```json
88+
* {
89+
* "version": "1.0.0",
90+
* "cache_key": "0123456789abcdef",
91+
* "timestamp": 1730332800000,
92+
* "checksum": "sha512-def456...",
93+
* "checksum_algorithm": "sha512",
94+
* "platform": "darwin",
95+
* "arch": "arm64",
96+
* "size": 13000000,
97+
* "source": {
98+
* "type": "decompression",
99+
* "path": "/usr/local/bin/socket"
100+
* },
101+
* "extra": {
102+
* "compressed_size": 1700000,
103+
* "compression_algorithm": 3,
104+
* "compression_ratio": 7.647
105+
* }
106+
* }
107+
* ```
108+
*
109+
* @internal This interface documents the metadata file format.
110+
*/
111+
export interface DlxMetadata {
112+
version: string
113+
cache_key: string
114+
timestamp: number
115+
checksum: string
116+
checksum_algorithm: string
117+
platform: string
118+
arch: string
119+
size: number
120+
source?: {
121+
type: 'download' | 'decompression'
122+
url?: string
123+
path?: string
124+
}
125+
extra?: Record<string, unknown>
126+
}
127+
44128
/**
45129
* Get metadata file path for a cached binary.
46130
*/
@@ -153,20 +237,32 @@ async function downloadBinaryFile(
153237

154238
/**
155239
* Write metadata for a cached binary.
240+
* Uses unified schema shared with C++ decompressor and CLI dlxBinary.
241+
* Schema documentation: See DlxMetadata interface in this file (exported).
242+
* Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source
243+
* Note: This implementation uses SHA-256 checksums instead of SHA-512.
156244
*/
157245
async function writeMetadata(
158246
cacheEntryPath: string,
247+
cacheKey: string,
159248
url: string,
160249
checksum: string,
250+
size: number,
161251
): Promise<void> {
162252
const metaPath = getMetadataPath(cacheEntryPath)
163253
const metadata = {
164-
arch: os.arch(),
254+
version: '1.0.0',
255+
cache_key: cacheKey,
256+
timestamp: Date.now(),
165257
checksum,
258+
checksum_algorithm: 'sha256',
166259
platform: os.platform(),
167-
timestamp: Date.now(),
168-
url,
169-
version: '1.0.0',
260+
arch: os.arch(),
261+
size,
262+
source: {
263+
type: 'download',
264+
url,
265+
},
170266
}
171267
await fs.writeFile(metaPath, JSON.stringify(metadata, null, 2))
172268
}
@@ -325,7 +421,16 @@ export async function dlxBinary(
325421

326422
// Download the binary.
327423
computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)
328-
await writeMetadata(cacheEntryDir, url, computedChecksum || '')
424+
425+
// Get file size for metadata.
426+
const stats = await fs.stat(binaryPath)
427+
await writeMetadata(
428+
cacheEntryDir,
429+
cacheKey,
430+
url,
431+
computedChecksum || '',
432+
stats.size,
433+
)
329434
}
330435

331436
// Execute the binary.
@@ -431,7 +536,16 @@ export async function downloadBinary(
431536

432537
// Download the binary.
433538
const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)
434-
await writeMetadata(cacheEntryDir, url, computedChecksum || '')
539+
540+
// Get file size for metadata.
541+
const stats = await fs.stat(binaryPath)
542+
await writeMetadata(
543+
cacheEntryDir,
544+
cacheKey,
545+
url,
546+
computedChecksum || '',
547+
stats.size,
548+
)
435549
downloaded = true
436550
}
437551

@@ -537,6 +651,14 @@ export async function listDlxCache(): Promise<
537651
continue
538652
}
539653

654+
const metaObj = metadata as Record<string, unknown>
655+
656+
// Get URL from unified schema (source.url) or legacy schema (url).
657+
// Allow empty URL for backward compatibility with partial metadata.
658+
const source = metaObj['source'] as Record<string, unknown> | undefined
659+
const url =
660+
(source?.['url'] as string) || (metaObj['url'] as string) || ''
661+
540662
// Find the binary file in the directory.
541663
// eslint-disable-next-line no-await-in-loop
542664
const files = await fs.readdir(entryPath)
@@ -547,15 +669,14 @@ export async function listDlxCache(): Promise<
547669
// eslint-disable-next-line no-await-in-loop
548670
const binaryStats = await fs.stat(binaryPath)
549671

550-
const metaObj = metadata as Record<string, unknown>
551672
results.push({
552673
age: now - ((metaObj['timestamp'] as number) || 0),
553674
arch: (metaObj['arch'] as string) || 'unknown',
554675
checksum: (metaObj['checksum'] as string) || '',
555676
name: binaryFile,
556677
platform: (metaObj['platform'] as string) || 'unknown',
557678
size: binaryStats.size,
558-
url: (metaObj['url'] as string) || '',
679+
url,
559680
})
560681
}
561682
} catch {}

0 commit comments

Comments
 (0)