Skip to content

Commit 87a901f

Browse files
committed
feat(dlx): unify .dlx-metadata.json schema across TypeScript and C++
Standardize metadata format for cached binaries to match socket-lib's canonical DlxMetadata schema. TypeScript changes (packages/cli/src/utils/dlx/binary.mts): - Update DlxMetadata interface to match socket-lib canonical schema - Add comprehensive documentation with examples for both download and decompression use cases - Update writeMetadata() to include cache_key and size parameters - Modify listDlxCache() to read from unified source.url field - Reference socket-lib as canonical schema documentation C++ changes (packages/node-smol-builder/additions/tools/socket_macho_decompress.cc): - Restructure metadata output to use unified schema format - Add platform/arch detection with preprocessor directives - Move compression-specific data to extra object (compressed_size, compression_algorithm, compression_ratio) - Convert timestamp to milliseconds for JavaScript compatibility - Add source.type and source.path fields for decompression tracking Unified schema structure: - Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source - Extra fields: Implementation-specific data (compression metrics for C++) References socket-lib's exported DlxMetadata interface as canonical source.
1 parent de7f728 commit 87a901f

File tree

2 files changed

+131
-19
lines changed

2 files changed

+131
-19
lines changed

packages/cli/src/utils/dlx/binary.mts

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,82 @@ import { InputError } from '../error/errors.mts'
4040
import type { SpawnExtra, SpawnOptions } from '@socketsecurity/lib/spawn'
4141

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

53121
export interface DlxBinaryOptions {
@@ -101,7 +169,7 @@ async function isCacheValid(
101169
const metadata = (await readJson(metaPath, {
102170
throws: false,
103171
})) as DlxMetadata | null
104-
if (!metadata) {
172+
if (!metadata || !metadata.timestamp) {
105173
return false
106174
}
107175
const now = Date.now()
@@ -179,17 +247,25 @@ async function downloadBinary(
179247
*/
180248
async function writeMetadata(
181249
cacheEntryPath: string,
250+
cacheKey: string,
182251
url: string,
183252
checksum: string,
253+
size: number,
184254
): Promise<void> {
185255
const metaPath = getMetadataPath(cacheEntryPath)
186-
const metadata = {
187-
url,
188-
checksum,
256+
const metadata: DlxMetadata = {
257+
version: '1.0.0',
258+
cache_key: cacheKey,
189259
timestamp: Date.now(),
260+
checksum,
261+
checksum_algorithm: 'sha512',
190262
platform: os.platform(),
191263
arch: os.arch(),
192-
version: '1.0.0',
264+
size,
265+
source: {
266+
type: 'download',
267+
url,
268+
},
193269
}
194270
await fs.writeFile(metaPath, JSON.stringify(metadata, null, 2))
195271
}
@@ -319,7 +395,10 @@ export async function dlxBinary(
319395

320396
// Download the binary.
321397
computedChecksum = await downloadBinary(url, binaryPath, checksum)
322-
await writeMetadata(cacheEntryDir, url, computedChecksum || '')
398+
399+
// Get file size for metadata.
400+
const stats = await fs.stat(binaryPath)
401+
await writeMetadata(cacheEntryDir, cacheKey, url, computedChecksum || '', stats.size)
323402
}
324403

325404
// Execute the binary.
@@ -392,7 +471,13 @@ export async function listDlxCache(): Promise<
392471
const metadata = (await readJson(metaPath, {
393472
throws: false,
394473
})) as DlxMetadata | null
395-
if (!metadata || !metadata.url || !metadata.timestamp) {
474+
if (!metadata || !metadata.timestamp) {
475+
continue
476+
}
477+
478+
// Get URL from source field for unified schema.
479+
const url = metadata.source?.url || ''
480+
if (!url) {
396481
continue
397482
}
398483

@@ -408,7 +493,7 @@ export async function listDlxCache(): Promise<
408493

409494
results.push({
410495
name: binaryFile,
411-
url: metadata.url,
496+
url,
412497
size: binaryStats.size,
413498
age: now - metadata.timestamp,
414499
platform: metadata.platform || 'unknown',

packages/node-smol-builder/additions/tools/socket_macho_decompress.cc

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,17 +461,44 @@ int DecompressAndExecute(const std::string& compressed_path, int argc, char* arg
461461

462462
printf(" ✓ Cached binary: %s\n\n", cached_binary.c_str());
463463

464-
// Write metadata (follows npm/cacache pattern).
464+
// Write metadata (unified schema with TypeScript dlxBinary).
465+
// Canonical documentation: @socketsecurity/lib/src/dlx-binary.ts (DlxMetadata interface)
466+
// Also documented in: packages/cli/src/utils/dlx/binary.mts
467+
// Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source
468+
// Extra fields: compressed_size, compression_algorithm, compression_ratio (C++ decompression specific)
465469
std::ostringstream metadata;
466470
metadata << "{\n";
467-
metadata << " \"timestamp\": " << time(nullptr) << ",\n";
468-
metadata << " \"compressed_path\": \"" << compressed_path << "\",\n";
471+
metadata << " \"version\": \"1.0.0\",\n";
469472
metadata << " \"cache_key\": \"" << cacheKey << "\",\n";
473+
metadata << " \"timestamp\": " << (time(nullptr) * 1000LL) << ",\n"; // Milliseconds for JS compat.
470474
metadata << " \"checksum\": \"" << decompressed_sha512 << "\",\n";
471475
metadata << " \"checksum_algorithm\": \"sha512\",\n";
472-
metadata << " \"original_size\": " << header->original_size << ",\n";
473-
metadata << " \"compressed_size\": " << header->compressed_size << ",\n";
474-
metadata << " \"algorithm\": " << header->algorithm << "\n";
476+
#if defined(__APPLE__)
477+
metadata << " \"platform\": \"darwin\",\n";
478+
#elif defined(__linux__)
479+
metadata << " \"platform\": \"linux\",\n";
480+
#elif defined(_WIN32)
481+
metadata << " \"platform\": \"win32\",\n";
482+
#else
483+
metadata << " \"platform\": \"unknown\",\n";
484+
#endif
485+
#if defined(__x86_64__) || defined(_M_X64)
486+
metadata << " \"arch\": \"x64\",\n";
487+
#elif defined(__aarch64__) || defined(_M_ARM64)
488+
metadata << " \"arch\": \"arm64\",\n";
489+
#else
490+
metadata << " \"arch\": \"unknown\",\n";
491+
#endif
492+
metadata << " \"size\": " << header->original_size << ",\n";
493+
metadata << " \"source\": {\n";
494+
metadata << " \"type\": \"decompression\",\n";
495+
metadata << " \"path\": \"" << compressed_path << "\"\n";
496+
metadata << " },\n";
497+
metadata << " \"extra\": {\n";
498+
metadata << " \"compressed_size\": " << header->compressed_size << ",\n";
499+
metadata << " \"compression_algorithm\": " << header->algorithm << ",\n";
500+
metadata << " \"compression_ratio\": " << (double)header->original_size / header->compressed_size << "\n";
501+
metadata << " }\n";
475502
metadata << "}\n";
476503

477504
WriteFile(metadata_file, metadata.str().c_str(), metadata.str().size());

0 commit comments

Comments
 (0)