redis-graph-cache 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,58 @@
1
+ /**
2
+ * Optional value compression for entity payloads.
3
+ *
4
+ * Why this exists:
5
+ * - Entity payloads (post + nested relationships) can be 5-50 KB.
6
+ * - At 50k concurrent users this is meaningful network bandwidth and
7
+ * Redis memory pressure.
8
+ * - Compression cuts typical JSON to ~30% of original size; even with
9
+ * base64 envelope overhead the net saving is 50-60%.
10
+ *
11
+ * Why ONLY entity values are compressed (not list values):
12
+ * - List values are JSON arrays of ids that the atomic Lua scripts
13
+ * parse server-side via `cjson.decode`. Compressed payloads would
14
+ * not parse and would break list-add / list-remove atomic ops.
15
+ * - Entity values are always parsed in Node, never inside Redis, so
16
+ * they're safe to ship in a compressed envelope.
17
+ *
18
+ * Backward compatibility:
19
+ * - Plain JSON (starts with `{` or `[`) is returned untouched on
20
+ * decode, so existing keys keep working when compression is enabled.
21
+ * - Compressed values carry a 4-character magic prefix `\x00z1:` that
22
+ * cannot occur at the start of valid JSON.
23
+ * - Writers can disable compression at any time and readers will
24
+ * transparently handle a mix of compressed and uncompressed values.
25
+ */
26
+ /**
27
+ * Wraps the (de)serialisation of an entity JSON string. A no-op codec
28
+ * (`enabled = false`) returns inputs unchanged on both encode and decode,
29
+ * with a fast-path so the engine pays virtually zero cost when the
30
+ * feature is off.
31
+ */
32
+ export declare class CompressionCodec {
33
+ readonly enabled: boolean;
34
+ readonly threshold: number;
35
+ constructor(enabled: boolean, threshold: number);
36
+ /**
37
+ * Encode a value for storage. When compression is disabled or the
38
+ * payload is below the threshold, returns the input unchanged so we
39
+ * don't add overhead to small entities.
40
+ */
41
+ encode(value: string): string;
42
+ /**
43
+ * Decode a value read from Redis. Detects the magic prefix to decide
44
+ * whether to inflate. Untagged values pass through, which is what
45
+ * makes this safe to deploy on top of an existing cache: any data
46
+ * written before compression was enabled keeps reading correctly.
47
+ *
48
+ * Throws if a tagged value is malformed; that's a hard error worth
49
+ * surfacing because it indicates corruption rather than a stale
50
+ * format.
51
+ */
52
+ decode(value: string): string;
53
+ }
54
+ /**
55
+ * Fast-path codec used when compression is disabled. Defined separately
56
+ * so the hot path doesn't even branch on `enabled` per call.
57
+ */
58
+ export declare const NOOP_CODEC: CompressionCodec;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /**
3
+ * Optional value compression for entity payloads.
4
+ *
5
+ * Why this exists:
6
+ * - Entity payloads (post + nested relationships) can be 5-50 KB.
7
+ * - At 50k concurrent users this is meaningful network bandwidth and
8
+ * Redis memory pressure.
9
+ * - Compression cuts typical JSON to ~30% of original size; even with
10
+ * base64 envelope overhead the net saving is 50-60%.
11
+ *
12
+ * Why ONLY entity values are compressed (not list values):
13
+ * - List values are JSON arrays of ids that the atomic Lua scripts
14
+ * parse server-side via `cjson.decode`. Compressed payloads would
15
+ * not parse and would break list-add / list-remove atomic ops.
16
+ * - Entity values are always parsed in Node, never inside Redis, so
17
+ * they're safe to ship in a compressed envelope.
18
+ *
19
+ * Backward compatibility:
20
+ * - Plain JSON (starts with `{` or `[`) is returned untouched on
21
+ * decode, so existing keys keep working when compression is enabled.
22
+ * - Compressed values carry a 4-character magic prefix `\x00z1:` that
23
+ * cannot occur at the start of valid JSON.
24
+ * - Writers can disable compression at any time and readers will
25
+ * transparently handle a mix of compressed and uncompressed values.
26
+ */
27
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ var desc = Object.getOwnPropertyDescriptor(m, k);
30
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
31
+ desc = { enumerable: true, get: function() { return m[k]; } };
32
+ }
33
+ Object.defineProperty(o, k2, desc);
34
+ }) : (function(o, m, k, k2) {
35
+ if (k2 === undefined) k2 = k;
36
+ o[k2] = m[k];
37
+ }));
38
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
39
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
40
+ }) : function(o, v) {
41
+ o["default"] = v;
42
+ });
43
+ var __importStar = (this && this.__importStar) || (function () {
44
+ var ownKeys = function(o) {
45
+ ownKeys = Object.getOwnPropertyNames || function (o) {
46
+ var ar = [];
47
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
48
+ return ar;
49
+ };
50
+ return ownKeys(o);
51
+ };
52
+ return function (mod) {
53
+ if (mod && mod.__esModule) return mod;
54
+ var result = {};
55
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
56
+ __setModuleDefault(result, mod);
57
+ return result;
58
+ };
59
+ })();
60
+ Object.defineProperty(exports, "__esModule", { value: true });
61
+ exports.NOOP_CODEC = exports.CompressionCodec = void 0;
62
+ const zlib = __importStar(require("zlib"));
63
+ const MAGIC = '\x00z1:';
64
+ const MAGIC_LENGTH = MAGIC.length;
65
+ /**
66
+ * Wraps the (de)serialisation of an entity JSON string. A no-op codec
67
+ * (`enabled = false`) returns inputs unchanged on both encode and decode,
68
+ * with a fast-path so the engine pays virtually zero cost when the
69
+ * feature is off.
70
+ */
71
+ class CompressionCodec {
72
+ constructor(enabled, threshold) {
73
+ this.enabled = enabled;
74
+ // Threshold is in bytes; clamp to a sensible minimum to avoid
75
+ // compressing tiny values where the envelope overhead outweighs the
76
+ // saving.
77
+ this.threshold = Math.max(64, threshold || 1024);
78
+ }
79
+ /**
80
+ * Encode a value for storage. When compression is disabled or the
81
+ * payload is below the threshold, returns the input unchanged so we
82
+ * don't add overhead to small entities.
83
+ */
84
+ encode(value) {
85
+ if (!this.enabled)
86
+ return value;
87
+ if (Buffer.byteLength(value, 'utf8') < this.threshold)
88
+ return value;
89
+ const compressed = zlib.deflateRawSync(Buffer.from(value, 'utf8'));
90
+ return MAGIC + compressed.toString('base64');
91
+ }
92
+ /**
93
+ * Decode a value read from Redis. Detects the magic prefix to decide
94
+ * whether to inflate. Untagged values pass through, which is what
95
+ * makes this safe to deploy on top of an existing cache: any data
96
+ * written before compression was enabled keeps reading correctly.
97
+ *
98
+ * Throws if a tagged value is malformed; that's a hard error worth
99
+ * surfacing because it indicates corruption rather than a stale
100
+ * format.
101
+ */
102
+ decode(value) {
103
+ if (!value.startsWith(MAGIC))
104
+ return value;
105
+ const b64 = value.slice(MAGIC_LENGTH);
106
+ const buf = Buffer.from(b64, 'base64');
107
+ return zlib.inflateRawSync(buf).toString('utf8');
108
+ }
109
+ }
110
+ exports.CompressionCodec = CompressionCodec;
111
+ /**
112
+ * Fast-path codec used when compression is disabled. Defined separately
113
+ * so the hot path doesn't even branch on `enabled` per call.
114
+ */
115
+ exports.NOOP_CODEC = new CompressionCodec(false, 0);
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Hydration Engine - Reconstructs full objects from normalized storage
3
+ */
4
+ import { SchemaManager } from './schema-manager';
5
+ import { RedisConnectionManager } from './redis-connection-manager';
6
+ import { CompressionCodec } from './compression';
7
+ import { Serializer } from './serializer';
8
+ import { HydrationOptions } from '../types';
9
+ export declare class HydrationEngine {
10
+ private schemaManager;
11
+ private connectionManager;
12
+ private defaultMaxDepth;
13
+ private defaultMaxMemory;
14
+ private codec;
15
+ private serializer;
16
+ constructor(schemaManager: SchemaManager, connectionManager: RedisConnectionManager, defaultMaxDepth?: number, defaultMaxMemory?: number, // 100MB
17
+ codec?: CompressionCodec, serializer?: Serializer);
18
+ /**
19
+ * Hydrate a single entity with all its relationships
20
+ */
21
+ hydrateEntity(entityType: string, id: string | number, options?: HydrationOptions): Promise<any>;
22
+ /**
23
+ * Hydrate multiple entities in batch
24
+ */
25
+ hydrateEntities(entityType: string, ids: (string | number)[], options?: HydrationOptions): Promise<any[]>;
26
+ /**
27
+ * Create hydration context with limits and tracking
28
+ */
29
+ private createHydrationContext;
30
+ /**
31
+ * Recursively hydrate entity and its relationships
32
+ */
33
+ private hydrateRecursive;
34
+ /**
35
+ * Hydrate all relationships for an entity
36
+ */
37
+ private hydrateRelationships;
38
+ /**
39
+ * Hydrate a single relationship
40
+ */
41
+ private hydrateRelation;
42
+ /**
43
+ * Batch hydrate multiple entities efficiently
44
+ */
45
+ private batchHydrateEntities;
46
+ /**
47
+ * Get a single entity from Redis. Hits/misses are tracked by the
48
+ * connection-manager wrapper so we don't double-count here. The codec
49
+ * decodes the storage envelope (decompressing if needed) before JSON
50
+ * parsing; untagged values pass through, preserving compatibility
51
+ * with caches that pre-date compression.
52
+ */
53
+ private getEntityFromRedis;
54
+ /**
55
+ * Batch fetch multiple entities via MGET. Each value is independently
56
+ * decoded (codec) and JSON-parsed. Per-element parse failures surface
57
+ * as null so the rest of the batch is still usable.
58
+ */
59
+ private batchGetEntitiesFromRedis;
60
+ /**
61
+ * Check if relations should be skipped based on context
62
+ */
63
+ private shouldSkipRelations;
64
+ /**
65
+ * Generate unique request ID for tracking
66
+ */
67
+ private generateRequestId;
68
+ }
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ /**
3
+ * Hydration Engine - Reconstructs full objects from normalized storage
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HydrationEngine = void 0;
7
+ const compression_1 = require("./compression");
8
+ const serializer_1 = require("./serializer");
9
+ const types_1 = require("../types");
10
+ const types_2 = require("../types");
11
+ class HydrationEngine {
12
+ constructor(schemaManager, connectionManager, defaultMaxDepth = 5, defaultMaxMemory = 100 * 1024 * 1024, // 100MB
13
+ codec = compression_1.NOOP_CODEC,
14
+ // Pluggable (de)serializer. Defaults to the engine's lossless
15
+ // tagged JSON serializer so reads recover `Date`/`BigInt`/`Map`/
16
+ // `Set`/`RegExp`/`Buffer`/`NaN`/`±Infinity` as their original JS
17
+ // types instead of degrading them to strings, nulls, or `{}`.
18
+ serializer = serializer_1.TAGGED_SERIALIZER) {
19
+ this.schemaManager = schemaManager;
20
+ this.connectionManager = connectionManager;
21
+ this.defaultMaxDepth = defaultMaxDepth;
22
+ this.defaultMaxMemory = defaultMaxMemory;
23
+ this.codec = codec;
24
+ this.serializer = serializer;
25
+ }
26
+ /**
27
+ * Hydrate a single entity with all its relationships
28
+ */
29
+ async hydrateEntity(entityType, id, options = {}) {
30
+ const context = this.createHydrationContext(options);
31
+ try {
32
+ const result = await this.hydrateRecursive(entityType, id, context);
33
+ return result ? (0, types_1.stripInternalFields)(result) : null;
34
+ }
35
+ catch (error) {
36
+ if (error instanceof types_2.HydrationDepthExceededError ||
37
+ error instanceof types_2.MemoryLimitError) {
38
+ // Return partial result with warning for limit exceeded errors
39
+ console.warn(`Hydration limit exceeded for ${entityType}:${id}`, error.message);
40
+ return null;
41
+ }
42
+ throw error;
43
+ }
44
+ }
45
+ /**
46
+ * Hydrate multiple entities in batch
47
+ */
48
+ async hydrateEntities(entityType, ids, options = {}) {
49
+ if (ids.length === 0) {
50
+ return [];
51
+ }
52
+ // Create separate context for each entity to prevent cross-contamination
53
+ const results = await Promise.all(ids.map((id) => this.hydrateEntity(entityType, id, options)));
54
+ // Filter out null results (deleted entities)
55
+ return results.filter((result) => result !== null);
56
+ }
57
+ /**
58
+ * Create hydration context with limits and tracking
59
+ */
60
+ createHydrationContext(options) {
61
+ return {
62
+ visitedEntities: new Set(),
63
+ currentDepth: 0,
64
+ maxDepth: options.maxDepth || this.defaultMaxDepth,
65
+ memoryUsage: 0,
66
+ maxMemory: options.memoryLimit || this.defaultMaxMemory,
67
+ requestId: this.generateRequestId(),
68
+ selectiveFields: options.selectiveFields,
69
+ excludeRelations: options.excludeRelations,
70
+ };
71
+ }
72
+ /**
73
+ * Recursively hydrate entity and its relationships
74
+ */
75
+ async hydrateRecursive(entityType, id, context) {
76
+ // Check depth limit
77
+ if (context.currentDepth >= context.maxDepth) {
78
+ throw new types_2.HydrationDepthExceededError(context.currentDepth, context.maxDepth, context.requestId);
79
+ }
80
+ // Check memory limit (rough estimation)
81
+ if (context.memoryUsage > context.maxMemory) {
82
+ throw new types_2.MemoryLimitError(Math.round(context.memoryUsage / (1024 * 1024)), Math.round(context.maxMemory / (1024 * 1024)), context.requestId);
83
+ }
84
+ const schema = this.schemaManager.getEntitySchema(entityType);
85
+ const entityKey = this.schemaManager.generateEntityKey(entityType, id);
86
+ // Prevent circular references. Instead of silently dropping the related
87
+ // entity (which corrupts the shape consumers expect) we emit a stub
88
+ // that contains the id and a `$ref` marker so consumers can detect a
89
+ // cycle and break recursion themselves. `$ref` is intentionally
90
+ // un-prefixed so it survives `stripInternalFields`.
91
+ const visitKey = `${entityType}:${id}`;
92
+ if (context.visitedEntities.has(visitKey)) {
93
+ return { [schema.id]: id, $ref: `${entityType}:${id}` };
94
+ }
95
+ context.visitedEntities.add(visitKey);
96
+ try {
97
+ // Get entity from Redis
98
+ const normalizedEntity = await this.getEntityFromRedis(entityKey);
99
+ if (!normalizedEntity) {
100
+ return null; // Entity not found
101
+ }
102
+ // Update memory usage estimation. We use the configured
103
+ // serializer here too because plain `JSON.stringify` would throw
104
+ // on values that the serializer specifically handles (BigInt) or
105
+ // silently understate the size (Buffer, Map). Wrapped in
106
+ // try/catch so a serialization quirk on a single entity can
107
+ // never abort hydration of the whole graph — the size estimate
108
+ // is best-effort.
109
+ try {
110
+ context.memoryUsage +=
111
+ this.serializer.stringify(normalizedEntity).length;
112
+ }
113
+ catch {
114
+ // Fall back to a conservative constant if even the serializer
115
+ // can't stringify the value. This is intentionally generous so
116
+ // we still apply some memory pressure rather than treating the
117
+ // entity as zero bytes.
118
+ context.memoryUsage += 4096;
119
+ }
120
+ // Build the hydrated entity. When `selectiveFields` is supplied the
121
+ // output is restricted to only those keys plus the ID field; we still
122
+ // keep the internal `__rse_*` markers in scope so relationship
123
+ // hydration can resolve referenced ids, then `stripInternalFields`
124
+ // removes them at the public boundary.
125
+ let hydratedEntity;
126
+ if (context.selectiveFields && context.selectiveFields.length > 0) {
127
+ const allowed = new Set(context.selectiveFields);
128
+ allowed.add(schema.id);
129
+ const filtered = {};
130
+ for (const [k, v] of Object.entries(normalizedEntity)) {
131
+ if (allowed.has(k) || k.startsWith('__rse_')) {
132
+ filtered[k] = v;
133
+ }
134
+ }
135
+ hydratedEntity = filtered;
136
+ }
137
+ else {
138
+ hydratedEntity = { ...normalizedEntity };
139
+ }
140
+ // Hydrate relationships
141
+ if (schema.relations && !this.shouldSkipRelations(context)) {
142
+ context.currentDepth++;
143
+ await this.hydrateRelationships(schema, normalizedEntity, hydratedEntity, context);
144
+ context.currentDepth--;
145
+ }
146
+ return hydratedEntity;
147
+ }
148
+ finally {
149
+ // Remove from visited set to allow re-visiting in different branches
150
+ context.visitedEntities.delete(visitKey);
151
+ }
152
+ }
153
+ /**
154
+ * Hydrate all relationships for an entity
155
+ */
156
+ async hydrateRelationships(schema, normalizedEntity, hydratedEntity, context) {
157
+ if (!schema.relations)
158
+ return;
159
+ const relationPromises = [];
160
+ for (const [relationName, relationDef] of Object.entries(schema.relations)) {
161
+ // Skip excluded relations
162
+ if (context.excludeRelations?.includes(relationName)) {
163
+ continue;
164
+ }
165
+ const promise = this.hydrateRelation(relationName, relationDef, normalizedEntity, hydratedEntity, context);
166
+ relationPromises.push(promise);
167
+ }
168
+ // Execute all relationship hydrations in parallel
169
+ await Promise.all(relationPromises);
170
+ }
171
+ /**
172
+ * Hydrate a single relationship
173
+ */
174
+ async hydrateRelation(relationName, relationDef, normalizedEntity, hydratedEntity, context) {
175
+ const relationIdField = (0, types_1.generateRelationIdField)(relationName, relationDef.kind);
176
+ const relationIds = normalizedEntity[relationIdField];
177
+ if (!relationIds) {
178
+ // No relation data, set appropriate default
179
+ hydratedEntity[relationName] = relationDef.kind === 'one' ? null : [];
180
+ return;
181
+ }
182
+ try {
183
+ if (relationDef.kind === 'one') {
184
+ // One-to-one relationship
185
+ const relatedEntity = await this.hydrateRecursive(relationDef.type, relationIds, { ...context });
186
+ hydratedEntity[relationName] = relatedEntity;
187
+ }
188
+ else {
189
+ // One-to-many relationship
190
+ if (Array.isArray(relationIds)) {
191
+ const relatedEntities = await this.batchHydrateEntities(relationDef.type, relationIds, context);
192
+ hydratedEntity[relationName] = relatedEntities;
193
+ }
194
+ else {
195
+ hydratedEntity[relationName] = [];
196
+ }
197
+ }
198
+ }
199
+ catch (error) {
200
+ // Handle relation hydration errors gracefully
201
+ console.warn(`Failed to hydrate relation '${relationName}':`, error);
202
+ hydratedEntity[relationName] = relationDef.kind === 'one' ? null : [];
203
+ }
204
+ }
205
+ /**
206
+ * Batch hydrate multiple entities efficiently
207
+ */
208
+ async batchHydrateEntities(entityType, ids, context) {
209
+ if (ids.length === 0) {
210
+ return [];
211
+ }
212
+ // First, batch fetch all entities from Redis
213
+ const entityKeys = ids.map((id) => this.schemaManager.generateEntityKey(entityType, id));
214
+ const normalizedEntities = await this.batchGetEntitiesFromRedis(entityKeys);
215
+ // Then hydrate each entity
216
+ const hydrationPromises = ids.map(async (id, index) => {
217
+ const normalizedEntity = normalizedEntities[index];
218
+ if (!normalizedEntity) {
219
+ return null; // Entity not found
220
+ }
221
+ // Create a copy of context for each entity
222
+ const entityContext = {
223
+ ...context,
224
+ visitedEntities: new Set(context.visitedEntities),
225
+ };
226
+ return this.hydrateRecursive(entityType, id, entityContext);
227
+ });
228
+ const results = await Promise.all(hydrationPromises);
229
+ // Filter out null results (deleted entities)
230
+ return results.filter((result) => result !== null);
231
+ }
232
+ /**
233
+ * Get a single entity from Redis. Hits/misses are tracked by the
234
+ * connection-manager wrapper so we don't double-count here. The codec
235
+ * decodes the storage envelope (decompressing if needed) before JSON
236
+ * parsing; untagged values pass through, preserving compatibility
237
+ * with caches that pre-date compression.
238
+ */
239
+ async getEntityFromRedis(key) {
240
+ try {
241
+ const value = await this.connectionManager.get(key);
242
+ if (!value)
243
+ return null;
244
+ return this.serializer.parse(this.codec.decode(value));
245
+ }
246
+ catch (error) {
247
+ throw new types_2.RedisConnectionError(`Failed to get entity from Redis: ${key}`, error);
248
+ }
249
+ }
250
+ /**
251
+ * Batch fetch multiple entities via MGET. Each value is independently
252
+ * decoded (codec) and JSON-parsed. Per-element parse failures surface
253
+ * as null so the rest of the batch is still usable.
254
+ */
255
+ async batchGetEntitiesFromRedis(keys) {
256
+ if (keys.length === 0)
257
+ return [];
258
+ try {
259
+ const values = await this.connectionManager.mget(keys);
260
+ return values.map((value) => {
261
+ if (!value)
262
+ return null;
263
+ try {
264
+ return this.serializer.parse(this.codec.decode(value));
265
+ }
266
+ catch {
267
+ return null;
268
+ }
269
+ });
270
+ }
271
+ catch (error) {
272
+ throw new types_2.RedisConnectionError('Failed to batch get entities from Redis', error);
273
+ }
274
+ }
275
+ /**
276
+ * Check if relations should be skipped based on context
277
+ */
278
+ shouldSkipRelations(context) {
279
+ return context.excludeRelations?.includes('*') || false;
280
+ }
281
+ /**
282
+ * Generate unique request ID for tracking
283
+ */
284
+ generateRequestId() {
285
+ return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
286
+ }
287
+ }
288
+ exports.HydrationEngine = HydrationEngine;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Barrel export for public core components.
3
+ *
4
+ * NOTE: `lua-scripts` is intentionally excluded — it contains raw Lua
5
+ * source strings that are implementation details of the connection
6
+ * manager and must not become part of the public API.
7
+ */
8
+ export * from './compression';
9
+ export * from './hydration-engine';
10
+ export * from './normalization-engine';
11
+ export * from './redis-connection-manager';
12
+ export * from './schema-manager';
13
+ export * from './serializer';
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Barrel export for public core components.
4
+ *
5
+ * NOTE: `lua-scripts` is intentionally excluded — it contains raw Lua
6
+ * source strings that are implementation details of the connection
7
+ * manager and must not become part of the public API.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ __exportStar(require("./compression"), exports);
25
+ __exportStar(require("./hydration-engine"), exports);
26
+ __exportStar(require("./normalization-engine"), exports);
27
+ __exportStar(require("./redis-connection-manager"), exports);
28
+ __exportStar(require("./schema-manager"), exports);
29
+ __exportStar(require("./serializer"), exports);