@geoprotocol/grc-20 0.1.0 → 0.1.4
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/dist/builder/edit.d.ts +5 -8
- package/dist/builder/edit.d.ts.map +1 -1
- package/dist/builder/edit.js +8 -19
- package/dist/builder/edit.js.map +1 -1
- package/dist/builder/entity.d.ts +4 -4
- package/dist/builder/entity.d.ts.map +1 -1
- package/dist/builder/entity.js +6 -6
- package/dist/builder/entity.js.map +1 -1
- package/dist/builder/index.d.ts +1 -0
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +1 -0
- package/dist/builder/index.js.map +1 -1
- package/dist/builder/relation.d.ts +4 -8
- package/dist/builder/relation.d.ts.map +1 -1
- package/dist/builder/relation.js +7 -14
- package/dist/builder/relation.js.map +1 -1
- package/dist/builder/update-relation.d.ts +64 -0
- package/dist/builder/update-relation.d.ts.map +1 -0
- package/dist/builder/update-relation.js +107 -0
- package/dist/builder/update-relation.js.map +1 -0
- package/dist/builder/update.d.ts +4 -4
- package/dist/builder/update.d.ts.map +1 -1
- package/dist/builder/update.js +6 -6
- package/dist/builder/update.js.map +1 -1
- package/dist/codec/compression.d.ts +132 -0
- package/dist/codec/compression.d.ts.map +1 -0
- package/dist/codec/compression.js +244 -0
- package/dist/codec/compression.js.map +1 -0
- package/dist/codec/index.d.ts +1 -0
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +9 -0
- package/dist/codec/index.js.map +1 -1
- package/dist/codec/op.d.ts.map +1 -1
- package/dist/codec/op.js +100 -37
- package/dist/codec/op.js.map +1 -1
- package/dist/codec/value.d.ts.map +1 -1
- package/dist/codec/value.js +35 -16
- package/dist/codec/value.js.map +1 -1
- package/dist/genesis/index.d.ts +14 -90
- package/dist/genesis/index.d.ts.map +1 -1
- package/dist/genesis/index.js +22 -149
- package/dist/genesis/index.js.map +1 -1
- package/dist/genesis/language.d.ts +33 -0
- package/dist/genesis/language.d.ts.map +1 -0
- package/dist/genesis/language.js +35 -0
- package/dist/genesis/language.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/test/basic.test.js +175 -26
- package/dist/test/basic.test.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/op.d.ts +17 -12
- package/dist/types/op.d.ts.map +1 -1
- package/dist/types/op.js.map +1 -1
- package/dist/types/value.d.ts +7 -6
- package/dist/types/value.d.ts.map +1 -1
- package/dist/types/value.js +11 -8
- package/dist/types/value.js.map +1 -1
- package/package.json +5 -1
- package/readme.md +76 -23
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zstd compression support for GRC-20 edits.
|
|
3
|
+
*
|
|
4
|
+
* This module uses lazy loading - the @bokuweb/zstd-wasm library is only
|
|
5
|
+
* imported when compression/decompression is actually used.
|
|
6
|
+
*/
|
|
7
|
+
import type { Edit } from "../types/edit.js";
|
|
8
|
+
import { type EncodeOptions } from "./edit.js";
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the compression module is loaded and ready.
|
|
11
|
+
*
|
|
12
|
+
* Use this to check if compression functions can be called synchronously
|
|
13
|
+
* (after preloading) or if they will need to load the WASM first.
|
|
14
|
+
*
|
|
15
|
+
* @returns true if WASM is loaded and compression is ready
|
|
16
|
+
*/
|
|
17
|
+
export declare function isCompressionReady(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Preloads the compression WASM module.
|
|
20
|
+
*
|
|
21
|
+
* Call this on app startup to ensure compression is ready when needed.
|
|
22
|
+
* The promise resolves when WASM is fully loaded and initialized.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // On app startup
|
|
27
|
+
* import { preloadCompression } from '@geoprotocol/grc-20';
|
|
28
|
+
*
|
|
29
|
+
* preloadCompression().then(() => {
|
|
30
|
+
* console.log('Compression ready!');
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @returns Promise that resolves when compression is ready
|
|
35
|
+
*/
|
|
36
|
+
export declare function preloadCompression(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Checks if data appears to be compressed (starts with GRC2Z magic).
|
|
39
|
+
*/
|
|
40
|
+
export declare function isCompressed(data: Uint8Array): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Compresses raw bytes using Zstd.
|
|
43
|
+
*
|
|
44
|
+
* @param data - The data to compress
|
|
45
|
+
* @param level - Compression level (default: 3)
|
|
46
|
+
* @returns The compressed data (without GRC2Z header)
|
|
47
|
+
*/
|
|
48
|
+
export declare function compress(data: Uint8Array, level?: number): Promise<Uint8Array>;
|
|
49
|
+
/**
|
|
50
|
+
* Decompresses raw Zstd-compressed bytes.
|
|
51
|
+
*
|
|
52
|
+
* @param data - The compressed data (without GRC2Z header)
|
|
53
|
+
* @returns The decompressed data
|
|
54
|
+
*/
|
|
55
|
+
export declare function decompress(data: Uint8Array): Promise<Uint8Array>;
|
|
56
|
+
/**
|
|
57
|
+
* Encodes an Edit to compressed binary format (GRC2Z).
|
|
58
|
+
*
|
|
59
|
+
* Format:
|
|
60
|
+
* - 5 bytes: "GRC2Z" magic
|
|
61
|
+
* - varint: uncompressed size
|
|
62
|
+
* - bytes: zstd-compressed GRC2 data
|
|
63
|
+
*
|
|
64
|
+
* @param edit - The edit to encode
|
|
65
|
+
* @param options - Encoding options (e.g., canonical mode)
|
|
66
|
+
* @returns The compressed binary data
|
|
67
|
+
*/
|
|
68
|
+
export declare function encodeEditCompressed(edit: Edit, options?: EncodeOptions): Promise<Uint8Array>;
|
|
69
|
+
/**
|
|
70
|
+
* Options for auto-encoding.
|
|
71
|
+
*/
|
|
72
|
+
export interface EncodeAutoOptions extends EncodeOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Minimum uncompressed size (in bytes) before compression is applied.
|
|
75
|
+
* If the uncompressed data is smaller than this threshold, it will
|
|
76
|
+
* be returned as-is (uncompressed GRC2 format).
|
|
77
|
+
*
|
|
78
|
+
* Default: 256 bytes
|
|
79
|
+
*
|
|
80
|
+
* Set to 0 to always compress.
|
|
81
|
+
* Set to Infinity to never compress.
|
|
82
|
+
*/
|
|
83
|
+
threshold?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Encodes an Edit to binary format, automatically choosing compression.
|
|
87
|
+
*
|
|
88
|
+
* This is the recommended encoding function for most use cases. It:
|
|
89
|
+
* - Encodes small edits without compression (faster, no WASM needed)
|
|
90
|
+
* - Compresses larger edits for better size efficiency
|
|
91
|
+
*
|
|
92
|
+
* The output can be decoded with `decodeEditAuto()`.
|
|
93
|
+
*
|
|
94
|
+
* @param edit - The edit to encode
|
|
95
|
+
* @param options - Encoding options including compression threshold
|
|
96
|
+
* @returns The binary data (GRC2 or GRC2Z format depending on size)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* // Auto-compress (default threshold: 256 bytes)
|
|
101
|
+
* const data = await encodeEditAuto(edit);
|
|
102
|
+
*
|
|
103
|
+
* // Always compress
|
|
104
|
+
* const compressed = await encodeEditAuto(edit, { threshold: 0 });
|
|
105
|
+
*
|
|
106
|
+
* // Never compress
|
|
107
|
+
* const uncompressed = await encodeEditAuto(edit, { threshold: Infinity });
|
|
108
|
+
*
|
|
109
|
+
* // Custom threshold (1KB)
|
|
110
|
+
* const data = await encodeEditAuto(edit, { threshold: 1024 });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare function encodeEditAuto(edit: Edit, options?: EncodeAutoOptions): Promise<Uint8Array>;
|
|
114
|
+
/**
|
|
115
|
+
* Decodes a compressed Edit from binary data (GRC2Z format).
|
|
116
|
+
*
|
|
117
|
+
* @param data - The compressed binary data
|
|
118
|
+
* @returns The decoded Edit
|
|
119
|
+
* @throws DecodeError if the data is invalid or not compressed
|
|
120
|
+
*/
|
|
121
|
+
export declare function decodeEditCompressed(data: Uint8Array): Promise<Edit>;
|
|
122
|
+
/**
|
|
123
|
+
* Decodes an Edit from binary data, automatically detecting compression.
|
|
124
|
+
*
|
|
125
|
+
* This is a convenience function that handles both compressed (GRC2Z)
|
|
126
|
+
* and uncompressed (GRC2) formats.
|
|
127
|
+
*
|
|
128
|
+
* @param data - The binary data (compressed or uncompressed)
|
|
129
|
+
* @returns The decoded Edit
|
|
130
|
+
*/
|
|
131
|
+
export declare function decodeEditAuto(data: Uint8Array): Promise<Edit>;
|
|
132
|
+
//# sourceMappingURL=compression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../src/codec/compression.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAmEvE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAMtD;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAGpF;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAGtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC1E;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpE"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zstd compression support for GRC-20 edits.
|
|
3
|
+
*
|
|
4
|
+
* This module uses lazy loading - the @bokuweb/zstd-wasm library is only
|
|
5
|
+
* imported when compression/decompression is actually used.
|
|
6
|
+
*/
|
|
7
|
+
import { DecodeError, Reader, Writer } from "./primitives.js";
|
|
8
|
+
import { encodeEdit, decodeEdit } from "./edit.js";
|
|
9
|
+
// Magic bytes for compressed format
|
|
10
|
+
const MAGIC_COMPRESSED = new TextEncoder().encode("GRC2Z");
|
|
11
|
+
// Default compression level (matches Rust implementation)
|
|
12
|
+
const DEFAULT_COMPRESSION_LEVEL = 3;
|
|
13
|
+
// Cached zstd functions
|
|
14
|
+
let zstdCompress = null;
|
|
15
|
+
let zstdDecompress = null;
|
|
16
|
+
let zstdLoadPromise = null;
|
|
17
|
+
/**
|
|
18
|
+
* Loads the zstd-wasm library.
|
|
19
|
+
*/
|
|
20
|
+
async function loadZstd() {
|
|
21
|
+
const zstd = await import("@bokuweb/zstd-wasm");
|
|
22
|
+
await zstd.init();
|
|
23
|
+
zstdCompress = zstd.compress;
|
|
24
|
+
zstdDecompress = zstd.decompress;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Starts preloading zstd in the background (non-blocking).
|
|
28
|
+
* Fails silently if the module can't be loaded (e.g., in browsers without bundler).
|
|
29
|
+
*/
|
|
30
|
+
function preloadZstd() {
|
|
31
|
+
if (zstdLoadPromise !== null)
|
|
32
|
+
return;
|
|
33
|
+
zstdLoadPromise = loadZstd().catch(() => {
|
|
34
|
+
// Preload failed (e.g., bare specifier in browser without bundler)
|
|
35
|
+
// Will retry on-demand when compression is actually used
|
|
36
|
+
zstdLoadPromise = null;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Start preloading in the background (non-blocking, fails silently)
|
|
40
|
+
preloadZstd();
|
|
41
|
+
/**
|
|
42
|
+
* Ensures zstd is loaded and ready.
|
|
43
|
+
* If preload failed, retries loading on-demand.
|
|
44
|
+
*/
|
|
45
|
+
async function ensureZstdLoaded() {
|
|
46
|
+
if (zstdCompress !== null && zstdDecompress !== null) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (zstdLoadPromise !== null) {
|
|
50
|
+
await zstdLoadPromise;
|
|
51
|
+
if (zstdCompress !== null)
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Preload failed or not started, try loading now
|
|
55
|
+
try {
|
|
56
|
+
zstdLoadPromise = loadZstd();
|
|
57
|
+
await zstdLoadPromise;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
throw new Error("Failed to load zstd-wasm. Compression requires a bundler (Vite, webpack, etc.) " +
|
|
61
|
+
"or an import map to resolve '@bokuweb/zstd-wasm'. " +
|
|
62
|
+
"Original error: " + (error instanceof Error ? error.message : String(error)));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the compression module is loaded and ready.
|
|
67
|
+
*
|
|
68
|
+
* Use this to check if compression functions can be called synchronously
|
|
69
|
+
* (after preloading) or if they will need to load the WASM first.
|
|
70
|
+
*
|
|
71
|
+
* @returns true if WASM is loaded and compression is ready
|
|
72
|
+
*/
|
|
73
|
+
export function isCompressionReady() {
|
|
74
|
+
return zstdCompress !== null && zstdDecompress !== null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Preloads the compression WASM module.
|
|
78
|
+
*
|
|
79
|
+
* Call this on app startup to ensure compression is ready when needed.
|
|
80
|
+
* The promise resolves when WASM is fully loaded and initialized.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // On app startup
|
|
85
|
+
* import { preloadCompression } from '@geoprotocol/grc-20';
|
|
86
|
+
*
|
|
87
|
+
* preloadCompression().then(() => {
|
|
88
|
+
* console.log('Compression ready!');
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @returns Promise that resolves when compression is ready
|
|
93
|
+
*/
|
|
94
|
+
export async function preloadCompression() {
|
|
95
|
+
await ensureZstdLoaded();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Checks if data appears to be compressed (starts with GRC2Z magic).
|
|
99
|
+
*/
|
|
100
|
+
export function isCompressed(data) {
|
|
101
|
+
if (data.length < 5)
|
|
102
|
+
return false;
|
|
103
|
+
for (let i = 0; i < 5; i++) {
|
|
104
|
+
if (data[i] !== MAGIC_COMPRESSED[i])
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Compresses raw bytes using Zstd.
|
|
111
|
+
*
|
|
112
|
+
* @param data - The data to compress
|
|
113
|
+
* @param level - Compression level (default: 3)
|
|
114
|
+
* @returns The compressed data (without GRC2Z header)
|
|
115
|
+
*/
|
|
116
|
+
export async function compress(data, level) {
|
|
117
|
+
await ensureZstdLoaded();
|
|
118
|
+
return zstdCompress(data, level ?? DEFAULT_COMPRESSION_LEVEL);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Decompresses raw Zstd-compressed bytes.
|
|
122
|
+
*
|
|
123
|
+
* @param data - The compressed data (without GRC2Z header)
|
|
124
|
+
* @returns The decompressed data
|
|
125
|
+
*/
|
|
126
|
+
export async function decompress(data) {
|
|
127
|
+
await ensureZstdLoaded();
|
|
128
|
+
return zstdDecompress(data);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Encodes an Edit to compressed binary format (GRC2Z).
|
|
132
|
+
*
|
|
133
|
+
* Format:
|
|
134
|
+
* - 5 bytes: "GRC2Z" magic
|
|
135
|
+
* - varint: uncompressed size
|
|
136
|
+
* - bytes: zstd-compressed GRC2 data
|
|
137
|
+
*
|
|
138
|
+
* @param edit - The edit to encode
|
|
139
|
+
* @param options - Encoding options (e.g., canonical mode)
|
|
140
|
+
* @returns The compressed binary data
|
|
141
|
+
*/
|
|
142
|
+
export async function encodeEditCompressed(edit, options) {
|
|
143
|
+
// First encode to uncompressed format
|
|
144
|
+
const uncompressed = encodeEdit(edit, options);
|
|
145
|
+
// Compress the data
|
|
146
|
+
const compressed = await compress(uncompressed);
|
|
147
|
+
// Build the final output: magic + uncompressed size + compressed data
|
|
148
|
+
const writer = new Writer(5 + 10 + compressed.length);
|
|
149
|
+
writer.writeBytes(MAGIC_COMPRESSED);
|
|
150
|
+
writer.writeVarintNumber(uncompressed.length);
|
|
151
|
+
writer.writeBytes(compressed);
|
|
152
|
+
return writer.finish();
|
|
153
|
+
}
|
|
154
|
+
// Default threshold for auto-compression (256 bytes)
|
|
155
|
+
const DEFAULT_COMPRESSION_THRESHOLD = 256;
|
|
156
|
+
/**
|
|
157
|
+
* Encodes an Edit to binary format, automatically choosing compression.
|
|
158
|
+
*
|
|
159
|
+
* This is the recommended encoding function for most use cases. It:
|
|
160
|
+
* - Encodes small edits without compression (faster, no WASM needed)
|
|
161
|
+
* - Compresses larger edits for better size efficiency
|
|
162
|
+
*
|
|
163
|
+
* The output can be decoded with `decodeEditAuto()`.
|
|
164
|
+
*
|
|
165
|
+
* @param edit - The edit to encode
|
|
166
|
+
* @param options - Encoding options including compression threshold
|
|
167
|
+
* @returns The binary data (GRC2 or GRC2Z format depending on size)
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* // Auto-compress (default threshold: 256 bytes)
|
|
172
|
+
* const data = await encodeEditAuto(edit);
|
|
173
|
+
*
|
|
174
|
+
* // Always compress
|
|
175
|
+
* const compressed = await encodeEditAuto(edit, { threshold: 0 });
|
|
176
|
+
*
|
|
177
|
+
* // Never compress
|
|
178
|
+
* const uncompressed = await encodeEditAuto(edit, { threshold: Infinity });
|
|
179
|
+
*
|
|
180
|
+
* // Custom threshold (1KB)
|
|
181
|
+
* const data = await encodeEditAuto(edit, { threshold: 1024 });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export async function encodeEditAuto(edit, options) {
|
|
185
|
+
const threshold = options?.threshold ?? DEFAULT_COMPRESSION_THRESHOLD;
|
|
186
|
+
// First encode to uncompressed format
|
|
187
|
+
const uncompressed = encodeEdit(edit, options);
|
|
188
|
+
// If below threshold, return uncompressed
|
|
189
|
+
if (uncompressed.length < threshold) {
|
|
190
|
+
return uncompressed;
|
|
191
|
+
}
|
|
192
|
+
// Compress the data
|
|
193
|
+
const compressed = await compress(uncompressed);
|
|
194
|
+
// Build the final output: magic + uncompressed size + compressed data
|
|
195
|
+
const writer = new Writer(5 + 10 + compressed.length);
|
|
196
|
+
writer.writeBytes(MAGIC_COMPRESSED);
|
|
197
|
+
writer.writeVarintNumber(uncompressed.length);
|
|
198
|
+
writer.writeBytes(compressed);
|
|
199
|
+
return writer.finish();
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Decodes a compressed Edit from binary data (GRC2Z format).
|
|
203
|
+
*
|
|
204
|
+
* @param data - The compressed binary data
|
|
205
|
+
* @returns The decoded Edit
|
|
206
|
+
* @throws DecodeError if the data is invalid or not compressed
|
|
207
|
+
*/
|
|
208
|
+
export async function decodeEditCompressed(data) {
|
|
209
|
+
// Check magic
|
|
210
|
+
if (!isCompressed(data)) {
|
|
211
|
+
throw new DecodeError("E001", "invalid magic bytes: expected GRC2Z for compressed data");
|
|
212
|
+
}
|
|
213
|
+
const reader = new Reader(data);
|
|
214
|
+
// Skip magic
|
|
215
|
+
reader.readBytes(5);
|
|
216
|
+
// Read declared uncompressed size
|
|
217
|
+
const declaredSize = reader.readVarintNumber();
|
|
218
|
+
// Read compressed data
|
|
219
|
+
const compressedData = reader.readBytes(reader.remaining());
|
|
220
|
+
// Decompress
|
|
221
|
+
const decompressed = await decompress(compressedData);
|
|
222
|
+
// Verify size
|
|
223
|
+
if (decompressed.length !== declaredSize) {
|
|
224
|
+
throw new DecodeError("E001", `uncompressed size mismatch: declared ${declaredSize}, actual ${decompressed.length}`);
|
|
225
|
+
}
|
|
226
|
+
// Decode the uncompressed edit
|
|
227
|
+
return decodeEdit(decompressed);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Decodes an Edit from binary data, automatically detecting compression.
|
|
231
|
+
*
|
|
232
|
+
* This is a convenience function that handles both compressed (GRC2Z)
|
|
233
|
+
* and uncompressed (GRC2) formats.
|
|
234
|
+
*
|
|
235
|
+
* @param data - The binary data (compressed or uncompressed)
|
|
236
|
+
* @returns The decoded Edit
|
|
237
|
+
*/
|
|
238
|
+
export async function decodeEditAuto(data) {
|
|
239
|
+
if (isCompressed(data)) {
|
|
240
|
+
return decodeEditCompressed(data);
|
|
241
|
+
}
|
|
242
|
+
return decodeEdit(data);
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=compression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compression.js","sourceRoot":"","sources":["../../src/codec/compression.ts"],"names":[],"mappings":"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"}
|
package/dist/codec/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { encodeEdit, decodeEdit, type EncodeOptions, } from "./edit.js";
|
|
2
2
|
export { Writer, Reader, DecodeError, zigzagEncode, zigzagDecode, } from "./primitives.js";
|
|
3
|
+
export { preloadCompression, isCompressionReady, encodeEditAuto, decodeEditAuto, type EncodeAutoOptions, encodeEditCompressed, decodeEditCompressed, isCompressed, compress, decompress, } from "./compression.js";
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/codec/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EACV,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/codec/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EACV,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAEL,kBAAkB,EAClB,kBAAkB,EAElB,cAAc,EACd,cAAc,EACd,KAAK,iBAAiB,EAEtB,oBAAoB,EACpB,oBAAoB,EAEpB,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/codec/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
export { encodeEdit, decodeEdit, } from "./edit.js";
|
|
2
2
|
export { Writer, Reader, DecodeError, zigzagEncode, zigzagDecode, } from "./primitives.js";
|
|
3
|
+
export {
|
|
4
|
+
// Preloading
|
|
5
|
+
preloadCompression, isCompressionReady,
|
|
6
|
+
// Auto encode/decode (recommended)
|
|
7
|
+
encodeEditAuto, decodeEditAuto,
|
|
8
|
+
// Explicit compressed encode/decode
|
|
9
|
+
encodeEditCompressed, decodeEditCompressed,
|
|
10
|
+
// Utilities
|
|
11
|
+
isCompressed, compress, decompress, } from "./compression.js";
|
|
3
12
|
//# sourceMappingURL=index.js.map
|
package/dist/codec/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codec/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,GAEX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codec/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,GAEX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO;AACL,aAAa;AACb,kBAAkB,EAClB,kBAAkB;AAClB,mCAAmC;AACnC,cAAc,EACd,cAAc;AAEd,oCAAoC;AACpC,oBAAoB,EACpB,oBAAoB;AACpB,YAAY;AACZ,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/codec/op.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"op.d.ts","sourceRoot":"","sources":["../../src/codec/op.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAMV,EAAE,
|
|
1
|
+
{"version":3,"file":"op.d.ts","sourceRoot":"","sources":["../../src/codec/op.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAMV,EAAE,EAQH,MAAM,gBAAgB,CAAC;AAaxB,OAAO,EAAe,MAAM,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,cAAc,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;IAC7B,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;CACpC;AA4BD;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,GAAG,IAAI,CA8BjF;AA0JD;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,EAAE,CAyBvE"}
|
package/dist/codec/op.js
CHANGED
|
@@ -11,8 +11,18 @@ const RELATION_HAS_TO_SPACE = 0x04;
|
|
|
11
11
|
const RELATION_HAS_TO_VERSION = 0x08;
|
|
12
12
|
const RELATION_HAS_ENTITY = 0x10;
|
|
13
13
|
const RELATION_HAS_POSITION = 0x20;
|
|
14
|
-
// UpdateRelation flags
|
|
15
|
-
const
|
|
14
|
+
// UpdateRelation set flags
|
|
15
|
+
const UPDATE_REL_SET_FROM_SPACE = 0x01;
|
|
16
|
+
const UPDATE_REL_SET_FROM_VERSION = 0x02;
|
|
17
|
+
const UPDATE_REL_SET_TO_SPACE = 0x04;
|
|
18
|
+
const UPDATE_REL_SET_TO_VERSION = 0x08;
|
|
19
|
+
const UPDATE_REL_SET_POSITION = 0x10;
|
|
20
|
+
// UpdateRelation unset flags
|
|
21
|
+
const UPDATE_REL_UNSET_FROM_SPACE = 0x01;
|
|
22
|
+
const UPDATE_REL_UNSET_FROM_VERSION = 0x02;
|
|
23
|
+
const UPDATE_REL_UNSET_TO_SPACE = 0x04;
|
|
24
|
+
const UPDATE_REL_UNSET_TO_VERSION = 0x08;
|
|
25
|
+
const UPDATE_REL_UNSET_POSITION = 0x10;
|
|
16
26
|
/**
|
|
17
27
|
* Encodes a single operation.
|
|
18
28
|
*/
|
|
@@ -104,14 +114,8 @@ function encodeRestoreEntity(writer, op, dicts) {
|
|
|
104
114
|
}
|
|
105
115
|
function encodeCreateRelation(writer, op, dicts) {
|
|
106
116
|
writer.writeByte(OP_TYPE_CREATE_RELATION);
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
writer.writeByte(0);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
writer.writeByte(1);
|
|
113
|
-
writer.writeId(op.idMode.id);
|
|
114
|
-
}
|
|
117
|
+
// Relation ID (always explicit)
|
|
118
|
+
writer.writeId(op.id);
|
|
115
119
|
// Type, from, to
|
|
116
120
|
writer.writeVarintNumber(dicts.getRelationTypeIndex(op.relationType));
|
|
117
121
|
writer.writeVarintNumber(dicts.getObjectIndex(op.from));
|
|
@@ -148,13 +152,52 @@ function encodeCreateRelation(writer, op, dicts) {
|
|
|
148
152
|
function encodeUpdateRelation(writer, op, dicts) {
|
|
149
153
|
writer.writeByte(OP_TYPE_UPDATE_RELATION);
|
|
150
154
|
writer.writeVarintNumber(dicts.getObjectIndex(op.id));
|
|
151
|
-
|
|
155
|
+
// Set flags
|
|
156
|
+
let setFlags = 0;
|
|
157
|
+
if (op.fromSpace !== undefined)
|
|
158
|
+
setFlags |= UPDATE_REL_SET_FROM_SPACE;
|
|
159
|
+
if (op.fromVersion !== undefined)
|
|
160
|
+
setFlags |= UPDATE_REL_SET_FROM_VERSION;
|
|
161
|
+
if (op.toSpace !== undefined)
|
|
162
|
+
setFlags |= UPDATE_REL_SET_TO_SPACE;
|
|
163
|
+
if (op.toVersion !== undefined)
|
|
164
|
+
setFlags |= UPDATE_REL_SET_TO_VERSION;
|
|
152
165
|
if (op.position !== undefined)
|
|
153
|
-
|
|
154
|
-
writer.writeByte(
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
setFlags |= UPDATE_REL_SET_POSITION;
|
|
167
|
+
writer.writeByte(setFlags);
|
|
168
|
+
// Unset flags
|
|
169
|
+
let unsetFlags = 0;
|
|
170
|
+
for (const field of op.unset) {
|
|
171
|
+
switch (field) {
|
|
172
|
+
case "fromSpace":
|
|
173
|
+
unsetFlags |= UPDATE_REL_UNSET_FROM_SPACE;
|
|
174
|
+
break;
|
|
175
|
+
case "fromVersion":
|
|
176
|
+
unsetFlags |= UPDATE_REL_UNSET_FROM_VERSION;
|
|
177
|
+
break;
|
|
178
|
+
case "toSpace":
|
|
179
|
+
unsetFlags |= UPDATE_REL_UNSET_TO_SPACE;
|
|
180
|
+
break;
|
|
181
|
+
case "toVersion":
|
|
182
|
+
unsetFlags |= UPDATE_REL_UNSET_TO_VERSION;
|
|
183
|
+
break;
|
|
184
|
+
case "position":
|
|
185
|
+
unsetFlags |= UPDATE_REL_UNSET_POSITION;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
157
188
|
}
|
|
189
|
+
writer.writeByte(unsetFlags);
|
|
190
|
+
// Write set field values
|
|
191
|
+
if (op.fromSpace !== undefined)
|
|
192
|
+
writer.writeId(op.fromSpace);
|
|
193
|
+
if (op.fromVersion !== undefined)
|
|
194
|
+
writer.writeId(op.fromVersion);
|
|
195
|
+
if (op.toSpace !== undefined)
|
|
196
|
+
writer.writeId(op.toSpace);
|
|
197
|
+
if (op.toVersion !== undefined)
|
|
198
|
+
writer.writeId(op.toVersion);
|
|
199
|
+
if (op.position !== undefined)
|
|
200
|
+
writer.writeString(op.position);
|
|
158
201
|
}
|
|
159
202
|
function encodeDeleteRelation(writer, op, dicts) {
|
|
160
203
|
writer.writeByte(OP_TYPE_DELETE_RELATION);
|
|
@@ -260,17 +303,8 @@ function decodeRestoreEntity(reader, dicts) {
|
|
|
260
303
|
return { type: "restoreEntity", id };
|
|
261
304
|
}
|
|
262
305
|
function decodeCreateRelation(reader, dicts) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (mode === 0) {
|
|
266
|
-
idMode = { type: "unique" };
|
|
267
|
-
}
|
|
268
|
-
else if (mode === 1) {
|
|
269
|
-
idMode = { type: "many", id: reader.readId() };
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
throw new DecodeError("E005", `invalid relation mode: ${mode}`);
|
|
273
|
-
}
|
|
306
|
+
// Relation ID (always explicit)
|
|
307
|
+
const id = reader.readId();
|
|
274
308
|
const relationType = dicts.getRelationType(reader.readVarintNumber());
|
|
275
309
|
const from = dicts.getObject(reader.readVarintNumber());
|
|
276
310
|
const to = dicts.getObject(reader.readVarintNumber());
|
|
@@ -285,13 +319,9 @@ function decodeCreateRelation(reader, dicts) {
|
|
|
285
319
|
const toVersion = flags & RELATION_HAS_TO_VERSION ? reader.readId() : undefined;
|
|
286
320
|
const entity = flags & RELATION_HAS_ENTITY ? reader.readId() : undefined;
|
|
287
321
|
const position = flags & RELATION_HAS_POSITION ? reader.readString() : undefined;
|
|
288
|
-
// Validate: unique mode cannot have explicit entity
|
|
289
|
-
if (mode === 0 && entity) {
|
|
290
|
-
throw new DecodeError("E005", "unique mode relation cannot have explicit entity");
|
|
291
|
-
}
|
|
292
322
|
return {
|
|
293
323
|
type: "createRelation",
|
|
294
|
-
|
|
324
|
+
id,
|
|
295
325
|
relationType,
|
|
296
326
|
from,
|
|
297
327
|
to,
|
|
@@ -305,13 +335,46 @@ function decodeCreateRelation(reader, dicts) {
|
|
|
305
335
|
}
|
|
306
336
|
function decodeUpdateRelation(reader, dicts) {
|
|
307
337
|
const id = dicts.getObject(reader.readVarintNumber());
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
338
|
+
// Read set flags
|
|
339
|
+
const setFlags = reader.readByte();
|
|
340
|
+
// Check reserved bits in set flags
|
|
341
|
+
if ((setFlags & 0xe0) !== 0) {
|
|
342
|
+
throw new DecodeError("E005", "reserved bits are non-zero in UpdateRelation set flags");
|
|
343
|
+
}
|
|
344
|
+
// Read unset flags
|
|
345
|
+
const unsetFlags = reader.readByte();
|
|
346
|
+
// Check reserved bits in unset flags
|
|
347
|
+
if ((unsetFlags & 0xe0) !== 0) {
|
|
348
|
+
throw new DecodeError("E005", "reserved bits are non-zero in UpdateRelation unset flags");
|
|
312
349
|
}
|
|
313
|
-
|
|
314
|
-
|
|
350
|
+
// Read set field values
|
|
351
|
+
const fromSpace = setFlags & UPDATE_REL_SET_FROM_SPACE ? reader.readId() : undefined;
|
|
352
|
+
const fromVersion = setFlags & UPDATE_REL_SET_FROM_VERSION ? reader.readId() : undefined;
|
|
353
|
+
const toSpace = setFlags & UPDATE_REL_SET_TO_SPACE ? reader.readId() : undefined;
|
|
354
|
+
const toVersion = setFlags & UPDATE_REL_SET_TO_VERSION ? reader.readId() : undefined;
|
|
355
|
+
const position = setFlags & UPDATE_REL_SET_POSITION ? reader.readString() : undefined;
|
|
356
|
+
// Decode unset fields
|
|
357
|
+
const unset = [];
|
|
358
|
+
if (unsetFlags & UPDATE_REL_UNSET_FROM_SPACE)
|
|
359
|
+
unset.push("fromSpace");
|
|
360
|
+
if (unsetFlags & UPDATE_REL_UNSET_FROM_VERSION)
|
|
361
|
+
unset.push("fromVersion");
|
|
362
|
+
if (unsetFlags & UPDATE_REL_UNSET_TO_SPACE)
|
|
363
|
+
unset.push("toSpace");
|
|
364
|
+
if (unsetFlags & UPDATE_REL_UNSET_TO_VERSION)
|
|
365
|
+
unset.push("toVersion");
|
|
366
|
+
if (unsetFlags & UPDATE_REL_UNSET_POSITION)
|
|
367
|
+
unset.push("position");
|
|
368
|
+
return {
|
|
369
|
+
type: "updateRelation",
|
|
370
|
+
id,
|
|
371
|
+
fromSpace,
|
|
372
|
+
fromVersion,
|
|
373
|
+
toSpace,
|
|
374
|
+
toVersion,
|
|
375
|
+
position,
|
|
376
|
+
unset,
|
|
377
|
+
};
|
|
315
378
|
}
|
|
316
379
|
function decodeDeleteRelation(reader, dicts) {
|
|
317
380
|
const id = dicts.getObject(reader.readVarintNumber());
|