@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.
Files changed (63) hide show
  1. package/dist/builder/edit.d.ts +5 -8
  2. package/dist/builder/edit.d.ts.map +1 -1
  3. package/dist/builder/edit.js +8 -19
  4. package/dist/builder/edit.js.map +1 -1
  5. package/dist/builder/entity.d.ts +4 -4
  6. package/dist/builder/entity.d.ts.map +1 -1
  7. package/dist/builder/entity.js +6 -6
  8. package/dist/builder/entity.js.map +1 -1
  9. package/dist/builder/index.d.ts +1 -0
  10. package/dist/builder/index.d.ts.map +1 -1
  11. package/dist/builder/index.js +1 -0
  12. package/dist/builder/index.js.map +1 -1
  13. package/dist/builder/relation.d.ts +4 -8
  14. package/dist/builder/relation.d.ts.map +1 -1
  15. package/dist/builder/relation.js +7 -14
  16. package/dist/builder/relation.js.map +1 -1
  17. package/dist/builder/update-relation.d.ts +64 -0
  18. package/dist/builder/update-relation.d.ts.map +1 -0
  19. package/dist/builder/update-relation.js +107 -0
  20. package/dist/builder/update-relation.js.map +1 -0
  21. package/dist/builder/update.d.ts +4 -4
  22. package/dist/builder/update.d.ts.map +1 -1
  23. package/dist/builder/update.js +6 -6
  24. package/dist/builder/update.js.map +1 -1
  25. package/dist/codec/compression.d.ts +132 -0
  26. package/dist/codec/compression.d.ts.map +1 -0
  27. package/dist/codec/compression.js +244 -0
  28. package/dist/codec/compression.js.map +1 -0
  29. package/dist/codec/index.d.ts +1 -0
  30. package/dist/codec/index.d.ts.map +1 -1
  31. package/dist/codec/index.js +9 -0
  32. package/dist/codec/index.js.map +1 -1
  33. package/dist/codec/op.d.ts.map +1 -1
  34. package/dist/codec/op.js +100 -37
  35. package/dist/codec/op.js.map +1 -1
  36. package/dist/codec/value.d.ts.map +1 -1
  37. package/dist/codec/value.js +35 -16
  38. package/dist/codec/value.js.map +1 -1
  39. package/dist/genesis/index.d.ts +14 -90
  40. package/dist/genesis/index.d.ts.map +1 -1
  41. package/dist/genesis/index.js +22 -149
  42. package/dist/genesis/index.js.map +1 -1
  43. package/dist/genesis/language.d.ts +33 -0
  44. package/dist/genesis/language.d.ts.map +1 -0
  45. package/dist/genesis/language.js +35 -0
  46. package/dist/genesis/language.js.map +1 -0
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +4 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/test/basic.test.js +175 -26
  52. package/dist/test/basic.test.js.map +1 -1
  53. package/dist/types/index.d.ts +1 -1
  54. package/dist/types/index.d.ts.map +1 -1
  55. package/dist/types/op.d.ts +17 -12
  56. package/dist/types/op.d.ts.map +1 -1
  57. package/dist/types/op.js.map +1 -1
  58. package/dist/types/value.d.ts +7 -6
  59. package/dist/types/value.d.ts.map +1 -1
  60. package/dist/types/value.js +11 -8
  61. package/dist/types/value.js.map +1 -1
  62. package/package.json +5 -1
  63. 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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"}
@@ -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"}
@@ -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
@@ -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"}
@@ -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,EAOH,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;AAiBD;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,GAAG,IAAI,CA8BjF;AAgID;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,EAAE,CAyBvE"}
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 UPDATE_REL_HAS_POSITION = 0x01;
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
- // Mode: 0 = unique, 1 = many
108
- if (op.idMode.type === "unique") {
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
- let flags = 0;
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
- flags |= UPDATE_REL_HAS_POSITION;
154
- writer.writeByte(flags);
155
- if (op.position !== undefined) {
156
- writer.writeString(op.position);
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
- const mode = reader.readByte();
264
- let idMode;
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
- idMode,
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
- const flags = reader.readByte();
309
- // Check reserved bits
310
- if ((flags & 0xfe) !== 0) {
311
- throw new DecodeError("E005", "reserved bits are non-zero in UpdateRelation flags");
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
- const position = flags & UPDATE_REL_HAS_POSITION ? reader.readString() : undefined;
314
- return { type: "updateRelation", id, position };
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());