crous 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.
package/index.d.ts ADDED
@@ -0,0 +1,358 @@
1
+ /**
2
+ * Crous - High-performance binary serialization for Node.js
3
+ *
4
+ * TypeScript type definitions for the Crous serialization library.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ /**
10
+ * Custom error class for Crous-related errors
11
+ */
12
+ export class CrousError extends Error {
13
+ constructor(message: string);
14
+ }
15
+
16
+ /**
17
+ * Error thrown during encoding/serialization
18
+ */
19
+ export class CrousEncodeError extends CrousError {
20
+ constructor(message: string);
21
+ }
22
+
23
+ /**
24
+ * Error thrown during decoding/deserialization
25
+ */
26
+ export class CrousDecodeError extends CrousError {
27
+ constructor(message: string);
28
+ }
29
+
30
+ /**
31
+ * Function type for custom serializers
32
+ * @template T - The type being serialized
33
+ */
34
+ export type SerializerFunction<T = any> = (obj: T) => any;
35
+
36
+ /**
37
+ * Function type for custom decoders
38
+ * @template T - The type being deserialized
39
+ */
40
+ export type DecoderFunction<T = any> = (value: any) => T;
41
+
42
+ /**
43
+ * Function type for object hooks (post-processing dictionaries)
44
+ */
45
+ export type ObjectHook = (obj: Record<string, any>) => any;
46
+
47
+ /**
48
+ * Function type for default serializer fallback
49
+ */
50
+ export type DefaultFunction = (obj: any) => any;
51
+
52
+ /**
53
+ * Options for dumps() function
54
+ */
55
+ export interface DumpsOptions {
56
+ /**
57
+ * Optional function to handle custom types that aren't natively supported
58
+ */
59
+ default?: DefaultFunction;
60
+
61
+ /**
62
+ * Whether to allow custom serializers (default: true)
63
+ */
64
+ allowCustom?: boolean;
65
+ }
66
+
67
+ /**
68
+ * Options for loads() function
69
+ */
70
+ export interface LoadsOptions {
71
+ /**
72
+ * Optional function to post-process dictionary objects during deserialization
73
+ */
74
+ objectHook?: ObjectHook;
75
+ }
76
+
77
+ /**
78
+ * Options for dump() function
79
+ */
80
+ export interface DumpOptions extends DumpsOptions {
81
+ }
82
+
83
+ /**
84
+ * Options for load() function
85
+ */
86
+ export interface LoadOptions extends LoadsOptions {
87
+ }
88
+
89
+ /**
90
+ * Encoder class for custom serialization control
91
+ */
92
+ export class CrousEncoder {
93
+ /**
94
+ * Create a new encoder instance
95
+ * @param options - Encoder options
96
+ */
97
+ constructor(options?: {
98
+ default?: DefaultFunction;
99
+ allowCustom?: boolean;
100
+ });
101
+
102
+ /**
103
+ * Encode an object to binary format
104
+ * @param obj - The object to encode
105
+ * @returns Binary encoded data
106
+ */
107
+ encode(obj: any): Buffer;
108
+ }
109
+
110
+ /**
111
+ * Decoder class for custom deserialization control
112
+ */
113
+ export class CrousDecoder {
114
+ /**
115
+ * Create a new decoder instance
116
+ * @param options - Decoder options
117
+ */
118
+ constructor(options?: {
119
+ objectHook?: ObjectHook;
120
+ });
121
+
122
+ /**
123
+ * Decode binary data to an object
124
+ * @param data - The binary data to decode
125
+ * @returns Deserialized object
126
+ */
127
+ decode(data: Buffer): any;
128
+ }
129
+
130
+ /**
131
+ * Version information structure
132
+ */
133
+ export interface VersionInfo {
134
+ major: number;
135
+ minor: number;
136
+ patch: number;
137
+ string: string;
138
+ tuple: [number, number, number];
139
+ hex: number;
140
+ }
141
+
142
+ /**
143
+ * Serialize a JavaScript value to binary format
144
+ *
145
+ * @param obj - The object to serialize
146
+ * @param options - Serialization options
147
+ * @returns Binary encoded data as a Buffer
148
+ * @throws {CrousEncodeError} If encoding fails
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * import { dumps } from 'crous';
153
+ *
154
+ * const data = { name: 'Alice', age: 30 };
155
+ * const binary = dumps(data);
156
+ * console.log(binary); // <Buffer ...>
157
+ * ```
158
+ */
159
+ export function dumps(obj: any, options?: DumpsOptions): Buffer;
160
+
161
+ /**
162
+ * Deserialize binary data to a JavaScript value
163
+ *
164
+ * @param data - Binary data to deserialize
165
+ * @param options - Deserialization options
166
+ * @returns Deserialized JavaScript value
167
+ * @throws {CrousDecodeError} If decoding fails
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * import { loads, dumps } from 'crous';
172
+ *
173
+ * const binary = dumps({ name: 'Alice' });
174
+ * const data = loads(binary);
175
+ * console.log(data); // { name: 'Alice' }
176
+ * ```
177
+ */
178
+ export function loads(data: Buffer, options?: LoadsOptions): any;
179
+
180
+ /**
181
+ * Serialize a JavaScript value and write to a file
182
+ *
183
+ * @param obj - The object to serialize
184
+ * @param filepath - Path to the output file or writable stream
185
+ * @param options - Serialization options
186
+ * @throws {CrousEncodeError} If encoding fails
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * import { dump } from 'crous';
191
+ * import * as fs from 'fs';
192
+ *
193
+ * const data = { name: 'Alice', age: 30 };
194
+ *
195
+ * // Write to file path
196
+ * dump(data, 'output.crous');
197
+ *
198
+ * // Write to stream
199
+ * const stream = fs.createWriteStream('output.crous');
200
+ * dump(data, stream);
201
+ * ```
202
+ */
203
+ export function dump(obj: any, filepath: string | NodeJS.WritableStream, options?: DumpOptions): void;
204
+
205
+ /**
206
+ * Deserialize a JavaScript value from a file
207
+ *
208
+ * @param filepath - Path to the input file or readable stream
209
+ * @param options - Deserialization options
210
+ * @returns Deserialized JavaScript value
211
+ * @throws {CrousDecodeError} If decoding fails
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * import { load } from 'crous';
216
+ * import * as fs from 'fs';
217
+ *
218
+ * // Read from file path
219
+ * const data = load('input.crous');
220
+ *
221
+ * // Read from stream
222
+ * const stream = fs.createReadStream('input.crous');
223
+ * const data2 = load(stream);
224
+ * ```
225
+ */
226
+ export function load(filepath: string | NodeJS.ReadableStream, options?: LoadOptions): any;
227
+
228
+ /**
229
+ * Register a custom serializer for a specific type
230
+ *
231
+ * @param type - The constructor/class to register a serializer for
232
+ * @param serializer - Function to convert instances to serializable values
233
+ * @throws {TypeError} If serializer is not a function
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * import { registerSerializer, dumps } from 'crous';
238
+ *
239
+ * class Point {
240
+ * constructor(public x: number, public y: number) {}
241
+ * }
242
+ *
243
+ * registerSerializer(Point, (point) => {
244
+ * return { x: point.x, y: point.y };
245
+ * });
246
+ *
247
+ * const binary = dumps(new Point(10, 20));
248
+ * ```
249
+ */
250
+ export function registerSerializer<T = any>(
251
+ type: new (...args: any[]) => T,
252
+ serializer: SerializerFunction<T>
253
+ ): void;
254
+
255
+ /**
256
+ * Unregister a custom serializer for a specific type
257
+ *
258
+ * @param type - The constructor/class to unregister
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * import { unregisterSerializer } from 'crous';
263
+ *
264
+ * class Point {}
265
+ * unregisterSerializer(Point);
266
+ * ```
267
+ */
268
+ export function unregisterSerializer<T = any>(
269
+ type: new (...args: any[]) => T
270
+ ): void;
271
+
272
+ /**
273
+ * Register a custom decoder for a specific tag
274
+ *
275
+ * @param tag - The tag identifier (integer)
276
+ * @param decoder - Function to convert tagged values to objects
277
+ * @throws {TypeError} If decoder is not a function
278
+ *
279
+ * @example
280
+ * ```typescript
281
+ * import { registerDecoder, loads } from 'crous';
282
+ *
283
+ * class Point {
284
+ * constructor(public x: number, public y: number) {}
285
+ * }
286
+ *
287
+ * registerDecoder(100, (value) => {
288
+ * return new Point(value.x, value.y);
289
+ * });
290
+ *
291
+ * const data = loads(binary);
292
+ * ```
293
+ */
294
+ export function registerDecoder<T = any>(
295
+ tag: number,
296
+ decoder: DecoderFunction<T>
297
+ ): void;
298
+
299
+ /**
300
+ * Unregister a custom decoder for a specific tag
301
+ *
302
+ * @param tag - The tag identifier to unregister
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * import { unregisterDecoder } from 'crous';
307
+ *
308
+ * unregisterDecoder(100);
309
+ * ```
310
+ */
311
+ export function unregisterDecoder(tag: number): void;
312
+
313
+ /**
314
+ * Get version information about the Crous library
315
+ *
316
+ * @returns Version information object
317
+ *
318
+ * @example
319
+ * ```typescript
320
+ * import { versionInfo } from 'crous';
321
+ *
322
+ * const info = versionInfo();
323
+ * console.log(`Crous v${info.string}`);
324
+ * ```
325
+ */
326
+ export function versionInfo(): VersionInfo;
327
+
328
+ /**
329
+ * Module version string
330
+ */
331
+ export const version: string;
332
+
333
+ /**
334
+ * Module version tuple [major, minor, patch]
335
+ */
336
+ export const versionTuple: [number, number, number];
337
+
338
+ // Re-export as default for CommonJS compatibility
339
+ declare const crous: {
340
+ dumps: typeof dumps;
341
+ loads: typeof loads;
342
+ dump: typeof dump;
343
+ load: typeof load;
344
+ registerSerializer: typeof registerSerializer;
345
+ unregisterSerializer: typeof unregisterSerializer;
346
+ registerDecoder: typeof registerDecoder;
347
+ unregisterDecoder: typeof unregisterDecoder;
348
+ versionInfo: typeof versionInfo;
349
+ CrousEncoder: typeof CrousEncoder;
350
+ CrousDecoder: typeof CrousDecoder;
351
+ CrousError: typeof CrousError;
352
+ CrousEncodeError: typeof CrousEncodeError;
353
+ CrousDecodeError: typeof CrousDecodeError;
354
+ version: string;
355
+ versionTuple: [number, number, number];
356
+ };
357
+
358
+ export default crous;
package/index.js ADDED
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Crous - High-performance binary serialization for Node.js
3
+ *
4
+ * This module provides complete Crous serialization with full support
5
+ * for Node.js native types and custom serializers.
6
+ *
7
+ * @module crous
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ // Load native addon
16
+ let native;
17
+ try {
18
+ native = require('./build/Release/crous.node');
19
+ } catch (e) {
20
+ try {
21
+ native = require('./build/Debug/crous.node');
22
+ } catch (e2) {
23
+ throw new Error('Could not load Crous native addon. Please run: npm install');
24
+ }
25
+ }
26
+
27
+ // Version information
28
+ const VERSION = {
29
+ major: 1,
30
+ minor: 0,
31
+ patch: 0,
32
+ get string() {
33
+ return `${this.major}.${this.minor}.${this.patch}`;
34
+ },
35
+ get tuple() {
36
+ return [this.major, this.minor, this.patch];
37
+ },
38
+ get hex() {
39
+ return (this.major << 16) | (this.minor << 8) | this.patch;
40
+ }
41
+ };
42
+
43
+ /**
44
+ * Custom error classes
45
+ */
46
+ class CrousError extends Error {
47
+ constructor(message) {
48
+ super(message);
49
+ this.name = 'CrousError';
50
+ }
51
+ }
52
+
53
+ class CrousEncodeError extends CrousError {
54
+ constructor(message) {
55
+ super(message);
56
+ this.name = 'CrousEncodeError';
57
+ }
58
+ }
59
+
60
+ class CrousDecodeError extends CrousError {
61
+ constructor(message) {
62
+ super(message);
63
+ this.name = 'CrousDecodeError';
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Encoder class for custom serialization control
69
+ */
70
+ class CrousEncoder {
71
+ constructor(options = {}) {
72
+ this.default = options.default || null;
73
+ this.allowCustom = options.allowCustom !== false;
74
+ }
75
+
76
+ encode(obj) {
77
+ return native.dumps(obj, this.default);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Decoder class for custom deserialization control
83
+ */
84
+ class CrousDecoder {
85
+ constructor(options = {}) {
86
+ this.objectHook = options.objectHook || null;
87
+ }
88
+
89
+ decode(data) {
90
+ return native.loads(data, this.objectHook);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Serialize a JavaScript value to binary format
96
+ *
97
+ * @param {*} obj - The object to serialize
98
+ * @param {Object} options - Serialization options
99
+ * @param {Function} options.default - Optional function for custom types
100
+ * @param {boolean} options.allowCustom - Whether to allow custom serializers
101
+ * @returns {Buffer} Binary encoded data
102
+ * @throws {CrousEncodeError} If encoding fails
103
+ */
104
+ function dumps(obj, options = {}) {
105
+ try {
106
+ return native.dumps(obj, options.default || null);
107
+ } catch (error) {
108
+ throw new CrousEncodeError(error.message);
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Deserialize binary data to a JavaScript value
114
+ *
115
+ * @param {Buffer} data - Binary data to deserialize
116
+ * @param {Object} options - Deserialization options
117
+ * @param {Function} options.objectHook - Optional function for post-processing objects
118
+ * @returns {*} Deserialized JavaScript value
119
+ * @throws {CrousDecodeError} If decoding fails
120
+ */
121
+ function loads(data, options = {}) {
122
+ try {
123
+ if (!Buffer.isBuffer(data)) {
124
+ data = Buffer.from(data);
125
+ }
126
+ return native.loads(data, options.objectHook || null);
127
+ } catch (error) {
128
+ throw new CrousDecodeError(error.message);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Serialize a JavaScript value and write to a file
134
+ *
135
+ * @param {*} obj - The object to serialize
136
+ * @param {string|stream.Writable} filepath - Path to output file or writable stream
137
+ * @param {Object} options - Serialization options
138
+ * @throws {CrousEncodeError} If encoding fails
139
+ */
140
+ function dump(obj, filepath, options = {}) {
141
+ try {
142
+ const binary = native.dumps(obj, options.default || null);
143
+
144
+ if (typeof filepath === 'string') {
145
+ // Write to file path
146
+ fs.writeFileSync(filepath, binary);
147
+ } else if (filepath && typeof filepath.write === 'function') {
148
+ // Write to stream
149
+ filepath.write(binary);
150
+ } else {
151
+ throw new Error('filepath must be a string or writable stream');
152
+ }
153
+ } catch (error) {
154
+ if (error instanceof CrousEncodeError) {
155
+ throw error;
156
+ }
157
+ throw new CrousEncodeError(error.message);
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Deserialize a JavaScript value from a file
163
+ *
164
+ * @param {string|stream.Readable} filepath - Path to input file or readable stream
165
+ * @param {Object} options - Deserialization options
166
+ * @returns {*} Deserialized JavaScript value
167
+ * @throws {CrousDecodeError} If decoding fails
168
+ */
169
+ function load(filepath, options = {}) {
170
+ try {
171
+ let binary;
172
+
173
+ if (typeof filepath === 'string') {
174
+ // Read from file path
175
+ binary = fs.readFileSync(filepath);
176
+ } else if (filepath && typeof filepath.read === 'function') {
177
+ // Read from stream
178
+ const chunks = [];
179
+ let chunk;
180
+ while ((chunk = filepath.read()) !== null) {
181
+ chunks.push(chunk);
182
+ }
183
+ binary = Buffer.concat(chunks);
184
+ } else {
185
+ throw new Error('filepath must be a string or readable stream');
186
+ }
187
+
188
+ return native.loads(binary, options.objectHook || null);
189
+ } catch (error) {
190
+ if (error instanceof CrousDecodeError) {
191
+ throw error;
192
+ }
193
+ throw new CrousDecodeError(error.message);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Register a custom serializer for a specific type
199
+ *
200
+ * @param {Function} type - The constructor/class to register a serializer for
201
+ * @param {Function} serializer - Function to convert instances to serializable values
202
+ * @throws {TypeError} If serializer is not a function
203
+ */
204
+ function registerSerializer(type, serializer) {
205
+ if (typeof serializer !== 'function') {
206
+ throw new TypeError('Serializer must be a function');
207
+ }
208
+ native.registerSerializer(type, serializer);
209
+ }
210
+
211
+ /**
212
+ * Unregister a custom serializer for a specific type
213
+ *
214
+ * @param {Function} type - The constructor/class to unregister
215
+ */
216
+ function unregisterSerializer(type) {
217
+ native.unregisterSerializer(type);
218
+ }
219
+
220
+ /**
221
+ * Register a custom decoder for a specific tag
222
+ *
223
+ * @param {number} tag - The tag identifier (integer)
224
+ * @param {Function} decoder - Function to convert tagged values to objects
225
+ * @throws {TypeError} If decoder is not a function
226
+ */
227
+ function registerDecoder(tag, decoder) {
228
+ if (typeof decoder !== 'function') {
229
+ throw new TypeError('Decoder must be a function');
230
+ }
231
+ native.registerDecoder(tag, decoder);
232
+ }
233
+
234
+ /**
235
+ * Unregister a custom decoder for a specific tag
236
+ *
237
+ * @param {number} tag - The tag identifier to unregister
238
+ */
239
+ function unregisterDecoder(tag) {
240
+ native.unregisterDecoder(tag);
241
+ }
242
+
243
+ /**
244
+ * Get version information about the Crous library
245
+ *
246
+ * @returns {Object} Version information object
247
+ */
248
+ function versionInfo() {
249
+ return {
250
+ major: VERSION.major,
251
+ minor: VERSION.minor,
252
+ patch: VERSION.patch,
253
+ string: VERSION.string,
254
+ tuple: VERSION.tuple,
255
+ hex: VERSION.hex
256
+ };
257
+ }
258
+
259
+ // Export all functions and classes
260
+ module.exports = {
261
+ // Core functions
262
+ dumps,
263
+ loads,
264
+ dump,
265
+ load,
266
+
267
+ // Custom serializers/decoders
268
+ registerSerializer,
269
+ unregisterSerializer,
270
+ registerDecoder,
271
+ unregisterDecoder,
272
+
273
+ // Classes
274
+ CrousEncoder,
275
+ CrousDecoder,
276
+ CrousError,
277
+ CrousEncodeError,
278
+ CrousDecodeError,
279
+
280
+ // Version info
281
+ versionInfo,
282
+ version: VERSION.string,
283
+ versionTuple: VERSION.tuple,
284
+ };
285
+
286
+ // ES6 named exports for modern Node.js
287
+ if (typeof exports !== 'undefined') {
288
+ Object.defineProperty(exports, "__esModule", { value: true });
289
+ exports.default = module.exports;
290
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "crous",
3
+ "version": "1.0.0",
4
+ "description": "Crous: High-performance binary serialization format for Node.js",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "keywords": [
8
+ "serialization",
9
+ "binary",
10
+ "encoding",
11
+ "decoding",
12
+ "msgpack",
13
+ "protobuf",
14
+ "fast",
15
+ "native",
16
+ "performance"
17
+ ],
18
+ "author": "Pawan Kumar <aegis.invincible@gmail.com>",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/axiomchronicles/crous.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/axiomchronicles/crous/issues"
26
+ },
27
+ "homepage": "https://github.com/axiomchronicles/crous#readme",
28
+ "scripts": {
29
+ "install": "node-gyp rebuild",
30
+ "build": "node-gyp rebuild",
31
+ "test": "node test/test_basic.js && node test/test_advanced.js",
32
+ "test:basic": "node test/test_basic.js",
33
+ "test:advanced": "node test/test_advanced.js",
34
+ "test:performance": "node test/test_performance.js",
35
+ "test:compat": "node test/test_python_compat.js",
36
+ "test:all": "npm run test:basic && npm run test:advanced && npm run test:performance && npm run test:compat",
37
+ "clean": "node-gyp clean"
38
+ },
39
+ "gypfile": true,
40
+ "engines": {
41
+ "node": ">=14.0.0"
42
+ },
43
+ "dependencies": {
44
+ "node-addon-api": "^8.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "node-gyp": "^10.0.0"
48
+ },
49
+ "files": [
50
+ "binding.gyp",
51
+ "index.js",
52
+ "index.d.ts",
53
+ "src/",
54
+ "README.md",
55
+ "LICENSE"
56
+ ]
57
+ }