scxq2-cc 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,426 @@
1
+ /**
2
+ * @asx/scxq2-cc - SCXQ2 Compression Calculus Engine
3
+ * TypeScript Type Definitions
4
+ *
5
+ * @version 1.0.0
6
+ */
7
+
8
+ /* =============================================================================
9
+ Engine Constants
10
+ ============================================================================= */
11
+
12
+ /**
13
+ * CC Engine identity object (frozen)
14
+ */
15
+ export declare const CC_ENGINE: Readonly<{
16
+ "@id": "asx://cc/engine/scxq2.v1";
17
+ "@type": "cc.engine";
18
+ "@version": "1.0.0";
19
+ "@status": "frozen";
20
+ "$schema": "xjson://schema/core/v1";
21
+ }>;
22
+
23
+ /**
24
+ * SCXQ2 encoding mode constants (frozen)
25
+ */
26
+ export declare const SCXQ2_ENCODING: Readonly<{
27
+ mode: "SCXQ2-DICT16-B64";
28
+ encoding: "SCXQ2-1";
29
+ }>;
30
+
31
+ /**
32
+ * CC operator identifiers (frozen)
33
+ */
34
+ export declare const CC_OPS: Readonly<{
35
+ NORM: "cc.norm.v1";
36
+ DICT: "cc.dict.v1";
37
+ FIELD: "cc.field.v1";
38
+ LANE: "cc.lane.v1";
39
+ EDGE: "cc.edge.v1";
40
+ }>;
41
+
42
+ /* =============================================================================
43
+ Compression Options
44
+ ============================================================================= */
45
+
46
+ /**
47
+ * Options for compression operations
48
+ */
49
+ export interface CCCompressOptions {
50
+ /** Maximum dictionary entries (1-65535, default: 1024) */
51
+ maxDict?: number;
52
+ /** Minimum token length (2-128, default: 3) */
53
+ minLen?: number;
54
+ /** Skip string literal tokens */
55
+ noStrings?: boolean;
56
+ /** Skip whitespace tokens */
57
+ noWS?: boolean;
58
+ /** Skip punctuation tokens */
59
+ noPunct?: boolean;
60
+ /** Enable JSON key extraction (CC.FIELD operator) */
61
+ enableFieldOps?: boolean;
62
+ /** Enable edge witnesses (CC.EDGE operator) */
63
+ enableEdgeOps?: boolean;
64
+ /** ISO timestamp (auto-generated if omitted) */
65
+ created_utc?: string;
66
+ /** Source file identifier */
67
+ source_file?: string | null;
68
+ }
69
+
70
+ /**
71
+ * Flags indicating which token types were processed
72
+ */
73
+ export interface SCXQ2Flags {
74
+ noStrings: boolean;
75
+ noWS: boolean;
76
+ noPunct: boolean;
77
+ }
78
+
79
+ /* =============================================================================
80
+ SCXQ2 Dictionary
81
+ ============================================================================= */
82
+
83
+ /**
84
+ * SCXQ2 Dictionary object
85
+ */
86
+ export interface SCXQ2Dict {
87
+ "@type": "scxq2.dict";
88
+ "@version": string;
89
+ mode: "SCXQ2-DICT16-B64";
90
+ encoding: "SCXQ2-1";
91
+ created_utc: string;
92
+ source_sha256_utf8: string;
93
+ max_dict: number;
94
+ min_len: number;
95
+ flags: SCXQ2Flags;
96
+ dict: string[];
97
+ dict_sha256_canon: string;
98
+ }
99
+
100
+ /* =============================================================================
101
+ SCXQ2 Block
102
+ ============================================================================= */
103
+
104
+ /**
105
+ * Edge witness tuple [from_index, to_index]
106
+ */
107
+ export type EdgeWitness = [number, number];
108
+
109
+ /**
110
+ * SCXQ2 Block object
111
+ */
112
+ export interface SCXQ2Block {
113
+ "@type": "scxq2.block";
114
+ "@version": string;
115
+ mode: "SCXQ2-DICT16-B64";
116
+ encoding: "SCXQ2-1";
117
+ created_utc: string;
118
+ source_sha256_utf8: string;
119
+ dict_sha256_canon: string;
120
+ original_bytes_utf8: number;
121
+ b64: string;
122
+ block_sha256_canon: string;
123
+ /** Lane identifier (multi-lane packs only) */
124
+ lane_id?: string;
125
+ /** Edge witnesses (when enableEdgeOps is true) */
126
+ edges?: EdgeWitness[];
127
+ }
128
+
129
+ /* =============================================================================
130
+ CC Proof
131
+ ============================================================================= */
132
+
133
+ /**
134
+ * Proof step in the compression trace
135
+ */
136
+ export interface CCProofStep {
137
+ op: string;
138
+ sha?: string;
139
+ dict_entries?: number;
140
+ block_sha?: string;
141
+ roundtrip_sha?: string;
142
+ }
143
+
144
+ /**
145
+ * Compression Calculus proof object
146
+ */
147
+ export interface CCProof {
148
+ "@type": "cc.proof";
149
+ "@version": string;
150
+ engine: string;
151
+ created_utc: string;
152
+ source_sha256_utf8: string;
153
+ dict_sha256_canon: string;
154
+ block_sha256_canon: string;
155
+ roundtrip_sha256_utf8: string;
156
+ ok: boolean;
157
+ steps: CCProofStep[];
158
+ }
159
+
160
+ /**
161
+ * Multi-lane proof object
162
+ */
163
+ export interface CCLanesProof {
164
+ "@type": "cc.lanes.proof";
165
+ "@version": string;
166
+ engine: string;
167
+ created_utc: string;
168
+ dict_sha256_canon: string;
169
+ lanes: Array<{
170
+ lane_id: string;
171
+ source_sha256_utf8: string;
172
+ block_sha256_canon: string;
173
+ }>;
174
+ ok: boolean;
175
+ steps?: CCProofStep[];
176
+ }
177
+
178
+ /* =============================================================================
179
+ CC Audit
180
+ ============================================================================= */
181
+
182
+ /**
183
+ * Top token info for audit
184
+ */
185
+ export interface TokenInfo {
186
+ tok: string;
187
+ count: number;
188
+ totalSavings: number;
189
+ }
190
+
191
+ /**
192
+ * Compression audit object
193
+ */
194
+ export interface CCAudit {
195
+ "@type": "cc.audit";
196
+ "@version": string;
197
+ engine: string;
198
+ created_utc: string;
199
+ sizes: {
200
+ original_bytes_utf8: number;
201
+ encoded_b64_bytes_utf8: number;
202
+ ratio: number | null;
203
+ };
204
+ dict: {
205
+ entries: number;
206
+ max_dict: number;
207
+ min_len: number;
208
+ flags: SCXQ2Flags;
209
+ };
210
+ top_tokens: TokenInfo[];
211
+ }
212
+
213
+ /**
214
+ * Multi-lane audit object
215
+ */
216
+ export interface CCLanesAudit {
217
+ "@type": "cc.lanes.audit";
218
+ "@version": string;
219
+ engine: string;
220
+ created_utc: string;
221
+ dict_entries: number;
222
+ lane_count: number;
223
+ }
224
+
225
+ /* =============================================================================
226
+ Compression Results
227
+ ============================================================================= */
228
+
229
+ /**
230
+ * Single-lane compression result
231
+ */
232
+ export interface CCResult {
233
+ dict: SCXQ2Dict;
234
+ block: SCXQ2Block;
235
+ proof: CCProof;
236
+ audit: CCAudit;
237
+ }
238
+
239
+ /**
240
+ * Multi-lane compression result
241
+ */
242
+ export interface CCLanesResult {
243
+ dict: SCXQ2Dict;
244
+ lanes: SCXQ2Block[];
245
+ proof: CCLanesProof;
246
+ audit: CCLanesAudit;
247
+ }
248
+
249
+ /**
250
+ * Lane input for multi-lane compression
251
+ */
252
+ export interface LaneInput {
253
+ lane_id: string;
254
+ text: string | Uint8Array;
255
+ }
256
+
257
+ /**
258
+ * Multi-lane compression input
259
+ */
260
+ export interface LanesInput {
261
+ lanes: LaneInput[];
262
+ }
263
+
264
+ /* =============================================================================
265
+ Main API Functions
266
+ ============================================================================= */
267
+
268
+ /**
269
+ * Compresses input text into an SCXQ2 language pack.
270
+ * Uses async hashing for universal compatibility (Node.js, Browser, Worker).
271
+ *
272
+ * @param input - Source text or bytes to compress
273
+ * @param opts - Compression options
274
+ * @returns Promise resolving to compression result
275
+ */
276
+ export declare function ccCompress(
277
+ input: string | Uint8Array,
278
+ opts?: CCCompressOptions
279
+ ): Promise<CCResult>;
280
+
281
+ /**
282
+ * Synchronous compression (Node.js only).
283
+ *
284
+ * @param input - Source text or bytes to compress
285
+ * @param opts - Compression options
286
+ * @returns Compression result
287
+ * @throws If not running in Node.js
288
+ */
289
+ export declare function ccCompressSync(
290
+ input: string | Uint8Array,
291
+ opts?: CCCompressOptions
292
+ ): CCResult;
293
+
294
+ /**
295
+ * Compresses multiple lanes with a shared dictionary.
296
+ *
297
+ * @param laneInput - Object containing array of lanes
298
+ * @param opts - Compression options
299
+ * @returns Promise resolving to multi-lane compression result
300
+ */
301
+ export declare function ccCompressLanes(
302
+ laneInput: LanesInput,
303
+ opts?: CCCompressOptions
304
+ ): Promise<CCLanesResult>;
305
+
306
+ /**
307
+ * Synchronous multi-lane compression (Node.js only).
308
+ *
309
+ * @param laneInput - Object containing array of lanes
310
+ * @param opts - Compression options
311
+ * @returns Multi-lane compression result
312
+ * @throws If not running in Node.js
313
+ */
314
+ export declare function ccCompressLanesSync(
315
+ laneInput: LanesInput,
316
+ opts?: CCCompressOptions
317
+ ): CCLanesResult;
318
+
319
+ /**
320
+ * Decompresses an SCXQ2 block using its dictionary.
321
+ *
322
+ * @param dictJson - SCXQ2 dictionary object
323
+ * @param blockJson - SCXQ2 block object
324
+ * @returns Decompressed text
325
+ * @throws On invalid pack or decoding error
326
+ */
327
+ export declare function ccDecompress(
328
+ dictJson: SCXQ2Dict,
329
+ blockJson: SCXQ2Block
330
+ ): string;
331
+
332
+ /**
333
+ * Verifies structural validity of an SCXQ2 pack.
334
+ *
335
+ * @param dictJson - Dictionary object
336
+ * @param blockJson - Block object
337
+ * @returns Success indicator
338
+ * @throws On verification failure
339
+ */
340
+ export declare function verifyPack(
341
+ dictJson: SCXQ2Dict,
342
+ blockJson: SCXQ2Block
343
+ ): { ok: true };
344
+
345
+ /* =============================================================================
346
+ Utility Functions
347
+ ============================================================================= */
348
+
349
+ /**
350
+ * Produces canonical JSON string with sorted keys.
351
+ *
352
+ * @param obj - Object to serialize
353
+ * @returns Canonical JSON string
354
+ */
355
+ export declare function canon(obj: unknown): string;
356
+
357
+ /**
358
+ * Recursively sorts object keys.
359
+ *
360
+ * @param value - Any value
361
+ * @returns Value with sorted object keys
362
+ */
363
+ export declare function sortKeysDeep<T>(value: T): T;
364
+
365
+ /**
366
+ * Creates shallow copy excluding specified fields.
367
+ *
368
+ * @param obj - Source object
369
+ * @param fields - Fields to exclude
370
+ * @returns New object without excluded fields
371
+ */
372
+ export declare function strip<T extends object>(
373
+ obj: T,
374
+ fields: string[]
375
+ ): Partial<T>;
376
+
377
+ /**
378
+ * Computes SHA-256 hash of UTF-8 text (async).
379
+ *
380
+ * @param text - Text to hash
381
+ * @returns Promise resolving to hex-encoded hash
382
+ */
383
+ export declare function sha256HexUtf8(text: string): Promise<string>;
384
+
385
+ /**
386
+ * Computes SHA-256 hash of UTF-8 text (sync, Node.js only).
387
+ *
388
+ * @param text - Text to hash
389
+ * @param nodeCrypto - Optional pre-imported crypto module
390
+ * @returns Hex-encoded hash
391
+ */
392
+ export declare function sha256HexUtf8Sync(
393
+ text: string,
394
+ nodeCrypto?: unknown
395
+ ): string;
396
+
397
+ /**
398
+ * Gets Node.js crypto module if available.
399
+ *
400
+ * @returns Crypto module or null
401
+ */
402
+ export declare function getNodeCrypto(): unknown | null;
403
+
404
+ /**
405
+ * Encodes bytes to base64 string.
406
+ *
407
+ * @param bytes - Bytes to encode
408
+ * @returns Base64-encoded string
409
+ */
410
+ export declare function bytesToBase64(bytes: Uint8Array | number[]): string;
411
+
412
+ /**
413
+ * Decodes base64 string to bytes.
414
+ *
415
+ * @param b64 - Base64-encoded string
416
+ * @returns Decoded bytes
417
+ */
418
+ export declare function base64ToBytes(b64: string): Uint8Array;
419
+
420
+ /**
421
+ * Validates that a string is valid base64.
422
+ *
423
+ * @param b64 - String to validate
424
+ * @returns True if valid base64
425
+ */
426
+ export declare function isValidBase64(b64: string): boolean;
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @asx/scxq2-cc - SCXQ2 Compression Calculus Engine
3
+ *
4
+ * A deterministic, proof-generating compression engine that produces
5
+ * content-addressable language packs following the frozen SCXQ2 specification.
6
+ *
7
+ * @module @asx/scxq2-cc
8
+ * @version 1.0.0
9
+ *
10
+ * @example
11
+ * // Basic compression
12
+ * import { ccCompress, ccDecompress } from '@asx/scxq2-cc';
13
+ *
14
+ * const pack = await ccCompress('function hello() { console.log("Hello"); }');
15
+ * console.log(pack.proof.ok); // true
16
+ *
17
+ * const roundtrip = ccDecompress(pack.dict, pack.block);
18
+ * // roundtrip === original input
19
+ *
20
+ * @example
21
+ * // Multi-lane compression
22
+ * import { ccCompressLanes } from '@asx/scxq2-cc';
23
+ *
24
+ * const pack = await ccCompressLanes({
25
+ * lanes: [
26
+ * { lane_id: 'main', text: 'function main() {}' },
27
+ * { lane_id: 'util', text: 'function util() {}' }
28
+ * ]
29
+ * });
30
+ */
31
+
32
+ // Re-export engine API
33
+ export {
34
+ CC_ENGINE,
35
+ SCXQ2_ENCODING,
36
+ CC_OPS,
37
+ ccCompress,
38
+ ccCompressSync,
39
+ ccCompressLanes,
40
+ ccCompressLanesSync,
41
+ ccDecompress,
42
+ verifyPack
43
+ } from "./engine.js";
44
+
45
+ // Re-export utilities for advanced use
46
+ export { canon, sortKeysDeep, strip } from "./canon.js";
47
+ export { sha256HexUtf8, sha256HexUtf8Sync, getNodeCrypto } from "./sha.js";
48
+ export { bytesToBase64, base64ToBytes, isValidBase64 } from "./base64.js";
package/dist/sha.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * SCXQ2 SHA-256 Utilities
3
+ *
4
+ * Universal SHA-256 hashing that works in Node.js, browsers, and workers.
5
+ * Provides both async (WebCrypto) and sync (Node crypto) implementations.
6
+ *
7
+ * @module @asx/scxq2-cc/sha
8
+ * @version 1.0.0
9
+ */
10
+
11
+ /**
12
+ * Computes SHA-256 hash of UTF-8 text, returning hex string.
13
+ * Uses WebCrypto when available, falls back to Node crypto.
14
+ *
15
+ * @param {string} text - UTF-8 text to hash
16
+ * @returns {Promise<string>} Hex-encoded SHA-256 hash
17
+ */
18
+ export async function sha256HexUtf8(text) {
19
+ // WebCrypto (browser / worker)
20
+ if (globalThis.crypto?.subtle) {
21
+ const data = new TextEncoder().encode(text);
22
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", data);
23
+ return [...new Uint8Array(digest)]
24
+ .map(b => b.toString(16).padStart(2, "0"))
25
+ .join("");
26
+ }
27
+
28
+ // Node.js
29
+ const { createHash } = await import("crypto");
30
+ return createHash("sha256").update(text, "utf8").digest("hex");
31
+ }
32
+
33
+ /**
34
+ * Synchronous SHA-256 hash (Node.js only).
35
+ * Throws if crypto module is not available.
36
+ *
37
+ * @param {string} text - UTF-8 text to hash
38
+ * @param {Object} [nodeCrypto] - Pre-imported crypto module (optional)
39
+ * @returns {string} Hex-encoded SHA-256 hash
40
+ */
41
+ export function sha256HexUtf8Sync(text, nodeCrypto = null) {
42
+ if (nodeCrypto) {
43
+ return nodeCrypto.createHash("sha256").update(text, "utf8").digest("hex");
44
+ }
45
+
46
+ // Dynamic require for Node.js environments
47
+ if (typeof process !== "undefined" && process.versions?.node) {
48
+ // Use dynamic import trick for sync context
49
+ const crypto = require("crypto");
50
+ return crypto.createHash("sha256").update(text, "utf8").digest("hex");
51
+ }
52
+
53
+ throw new Error("SCXQ2: sync hashing requires Node.js crypto module");
54
+ }
55
+
56
+ /**
57
+ * Gets Node.js crypto module if available.
58
+ * Returns null in browser/worker environments.
59
+ *
60
+ * @returns {Object|null} Node crypto module or null
61
+ */
62
+ export function getNodeCrypto() {
63
+ if (typeof process !== "undefined" && process.versions?.node) {
64
+ try {
65
+ return require("crypto");
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ return null;
71
+ }