@arcraz/common 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.
Files changed (174) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +373 -0
  3. package/dist/aws/bedrock/client-factory.d.ts +45 -0
  4. package/dist/aws/bedrock/client-factory.d.ts.map +1 -0
  5. package/dist/aws/bedrock/client-factory.js +113 -0
  6. package/dist/aws/bedrock/index.d.ts +3 -0
  7. package/dist/aws/bedrock/index.d.ts.map +1 -0
  8. package/dist/aws/bedrock/index.js +1 -0
  9. package/dist/aws/bedrock/types.d.ts +95 -0
  10. package/dist/aws/bedrock/types.d.ts.map +1 -0
  11. package/dist/aws/bedrock/types.js +1 -0
  12. package/dist/aws/cloudfront/index.d.ts +3 -0
  13. package/dist/aws/cloudfront/index.d.ts.map +1 -0
  14. package/dist/aws/cloudfront/index.js +1 -0
  15. package/dist/aws/cloudfront/signer-factory.d.ts +36 -0
  16. package/dist/aws/cloudfront/signer-factory.d.ts.map +1 -0
  17. package/dist/aws/cloudfront/signer-factory.js +75 -0
  18. package/dist/aws/cloudfront/types.d.ts +52 -0
  19. package/dist/aws/cloudfront/types.d.ts.map +1 -0
  20. package/dist/aws/cloudfront/types.js +1 -0
  21. package/dist/aws/s3/client-factory.d.ts +13 -0
  22. package/dist/aws/s3/client-factory.d.ts.map +1 -0
  23. package/dist/aws/s3/client-factory.js +25 -0
  24. package/dist/aws/s3/index.d.ts +4 -0
  25. package/dist/aws/s3/index.d.ts.map +1 -0
  26. package/dist/aws/s3/index.js +2 -0
  27. package/dist/aws/s3/operations.d.ts +106 -0
  28. package/dist/aws/s3/operations.d.ts.map +1 -0
  29. package/dist/aws/s3/operations.js +234 -0
  30. package/dist/aws/s3/types.d.ts +88 -0
  31. package/dist/aws/s3/types.d.ts.map +1 -0
  32. package/dist/aws/s3/types.js +1 -0
  33. package/dist/caches/api-cache.d.ts +40 -0
  34. package/dist/caches/api-cache.d.ts.map +1 -0
  35. package/dist/caches/api-cache.js +65 -0
  36. package/dist/caches/database-cache.d.ts +40 -0
  37. package/dist/caches/database-cache.d.ts.map +1 -0
  38. package/dist/caches/database-cache.js +65 -0
  39. package/dist/caches/index.d.ts +3 -0
  40. package/dist/caches/index.d.ts.map +1 -0
  41. package/dist/caches/index.js +2 -0
  42. package/dist/config/env-loader.d.ts +28 -0
  43. package/dist/config/env-loader.d.ts.map +1 -0
  44. package/dist/config/env-loader.js +39 -0
  45. package/dist/config/index.d.ts +5 -0
  46. package/dist/config/index.d.ts.map +1 -0
  47. package/dist/config/index.js +2 -0
  48. package/dist/config/schemas.d.ts +193 -0
  49. package/dist/config/schemas.d.ts.map +1 -0
  50. package/dist/config/schemas.js +92 -0
  51. package/dist/config/types.d.ts +23 -0
  52. package/dist/config/types.d.ts.map +1 -0
  53. package/dist/config/types.js +2 -0
  54. package/dist/constants/cache-durations.d.ts +29 -0
  55. package/dist/constants/cache-durations.d.ts.map +1 -0
  56. package/dist/constants/cache-durations.js +27 -0
  57. package/dist/constants/defaults.d.ts +50 -0
  58. package/dist/constants/defaults.d.ts.map +1 -0
  59. package/dist/constants/defaults.js +49 -0
  60. package/dist/constants/index.d.ts +4 -0
  61. package/dist/constants/index.d.ts.map +1 -0
  62. package/dist/constants/index.js +2 -0
  63. package/dist/database/base-repository.d.ts +45 -0
  64. package/dist/database/base-repository.d.ts.map +1 -0
  65. package/dist/database/base-repository.js +57 -0
  66. package/dist/database/helpers/converter-helper.d.ts +9 -0
  67. package/dist/database/helpers/converter-helper.d.ts.map +1 -0
  68. package/dist/database/helpers/converter-helper.js +20 -0
  69. package/dist/database/helpers/index.d.ts +3 -0
  70. package/dist/database/helpers/index.d.ts.map +1 -0
  71. package/dist/database/helpers/index.js +2 -0
  72. package/dist/database/helpers/paged-response-helper.d.ts +33 -0
  73. package/dist/database/helpers/paged-response-helper.d.ts.map +1 -0
  74. package/dist/database/helpers/paged-response-helper.js +64 -0
  75. package/dist/database/index.d.ts +6 -0
  76. package/dist/database/index.d.ts.map +1 -0
  77. package/dist/database/index.js +4 -0
  78. package/dist/database/pool-factory.d.ts +24 -0
  79. package/dist/database/pool-factory.d.ts.map +1 -0
  80. package/dist/database/pool-factory.js +91 -0
  81. package/dist/database/query-helpers.d.ts +36 -0
  82. package/dist/database/query-helpers.d.ts.map +1 -0
  83. package/dist/database/query-helpers.js +68 -0
  84. package/dist/database/types.d.ts +55 -0
  85. package/dist/database/types.d.ts.map +1 -0
  86. package/dist/database/types.js +1 -0
  87. package/dist/helpers/data-obscurer.d.ts +18 -0
  88. package/dist/helpers/data-obscurer.d.ts.map +1 -0
  89. package/dist/helpers/data-obscurer.js +29 -0
  90. package/dist/helpers/enum-converters.d.ts +27 -0
  91. package/dist/helpers/enum-converters.d.ts.map +1 -0
  92. package/dist/helpers/enum-converters.js +37 -0
  93. package/dist/helpers/index.d.ts +5 -0
  94. package/dist/helpers/index.d.ts.map +1 -0
  95. package/dist/helpers/index.js +3 -0
  96. package/dist/helpers/remove-sensitive-values.d.ts +20 -0
  97. package/dist/helpers/remove-sensitive-values.d.ts.map +1 -0
  98. package/dist/helpers/remove-sensitive-values.js +72 -0
  99. package/dist/index.d.ts +11 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +20 -0
  102. package/dist/logging/formatters.d.ts +19 -0
  103. package/dist/logging/formatters.d.ts.map +1 -0
  104. package/dist/logging/formatters.js +94 -0
  105. package/dist/logging/index.d.ts +4 -0
  106. package/dist/logging/index.d.ts.map +1 -0
  107. package/dist/logging/index.js +2 -0
  108. package/dist/logging/logger-factory.d.ts +8 -0
  109. package/dist/logging/logger-factory.d.ts.map +1 -0
  110. package/dist/logging/logger-factory.js +86 -0
  111. package/dist/logging/types.d.ts +52 -0
  112. package/dist/logging/types.d.ts.map +1 -0
  113. package/dist/logging/types.js +1 -0
  114. package/dist/rabbitmq/connection-factory.d.ts +8 -0
  115. package/dist/rabbitmq/connection-factory.d.ts.map +1 -0
  116. package/dist/rabbitmq/connection-factory.js +117 -0
  117. package/dist/rabbitmq/consumer.d.ts +44 -0
  118. package/dist/rabbitmq/consumer.d.ts.map +1 -0
  119. package/dist/rabbitmq/consumer.js +107 -0
  120. package/dist/rabbitmq/index.d.ts +6 -0
  121. package/dist/rabbitmq/index.d.ts.map +1 -0
  122. package/dist/rabbitmq/index.js +4 -0
  123. package/dist/rabbitmq/namespace-helpers.d.ts +33 -0
  124. package/dist/rabbitmq/namespace-helpers.d.ts.map +1 -0
  125. package/dist/rabbitmq/namespace-helpers.js +44 -0
  126. package/dist/rabbitmq/publisher.d.ts +27 -0
  127. package/dist/rabbitmq/publisher.d.ts.map +1 -0
  128. package/dist/rabbitmq/publisher.js +94 -0
  129. package/dist/rabbitmq/types.d.ts +94 -0
  130. package/dist/rabbitmq/types.d.ts.map +1 -0
  131. package/dist/rabbitmq/types.js +1 -0
  132. package/dist/redis/client-factory.d.ts +14 -0
  133. package/dist/redis/client-factory.d.ts.map +1 -0
  134. package/dist/redis/client-factory.js +98 -0
  135. package/dist/redis/index.d.ts +6 -0
  136. package/dist/redis/index.d.ts.map +1 -0
  137. package/dist/redis/index.js +4 -0
  138. package/dist/redis/namespace-helpers.d.ts +33 -0
  139. package/dist/redis/namespace-helpers.d.ts.map +1 -0
  140. package/dist/redis/namespace-helpers.js +43 -0
  141. package/dist/redis/operations/index.d.ts +3 -0
  142. package/dist/redis/operations/index.d.ts.map +1 -0
  143. package/dist/redis/operations/index.js +2 -0
  144. package/dist/redis/operations/list.d.ts +102 -0
  145. package/dist/redis/operations/list.d.ts.map +1 -0
  146. package/dist/redis/operations/list.js +136 -0
  147. package/dist/redis/operations/standard.d.ts +85 -0
  148. package/dist/redis/operations/standard.d.ts.map +1 -0
  149. package/dist/redis/operations/standard.js +136 -0
  150. package/dist/redis/types.d.ts +81 -0
  151. package/dist/redis/types.d.ts.map +1 -0
  152. package/dist/redis/types.js +8 -0
  153. package/dist/security/cors-factory.d.ts +28 -0
  154. package/dist/security/cors-factory.d.ts.map +1 -0
  155. package/dist/security/cors-factory.js +73 -0
  156. package/dist/security/helmet-factory.d.ts +14 -0
  157. package/dist/security/helmet-factory.d.ts.map +1 -0
  158. package/dist/security/helmet-factory.js +80 -0
  159. package/dist/security/index.d.ts +4 -0
  160. package/dist/security/index.d.ts.map +1 -0
  161. package/dist/security/index.js +2 -0
  162. package/dist/security/types.d.ts +103 -0
  163. package/dist/security/types.d.ts.map +1 -0
  164. package/dist/security/types.js +1 -0
  165. package/dist/types/custom-types.d.ts +102 -0
  166. package/dist/types/custom-types.d.ts.map +1 -0
  167. package/dist/types/custom-types.js +45 -0
  168. package/dist/types/enums.d.ts +26 -0
  169. package/dist/types/enums.d.ts.map +1 -0
  170. package/dist/types/enums.js +30 -0
  171. package/dist/types/index.d.ts +4 -0
  172. package/dist/types/index.d.ts.map +1 -0
  173. package/dist/types/index.js +2 -0
  174. package/package.json +154 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * CRITICAL: RabbitMQ namespace pattern - NODE_ENV-queue
3
+ * This MUST be preserved for environment isolation in RabbitMQ
4
+ */
5
+ /**
6
+ * Gets the namespaced queue name with environment prefix
7
+ * Format: environment-queue
8
+ * @param queue The base queue name
9
+ * @param namespace Optional namespace override (defaults to NODE_ENV)
10
+ * @returns The namespaced queue name
11
+ */
12
+ export function getNamespacedQueue(queue, namespace) {
13
+ const env = namespace || process.env.NODE_ENV || 'local';
14
+ return `${env}-${queue}`;
15
+ }
16
+ /**
17
+ * Gets the namespaced exchange name with environment prefix
18
+ * Format: environment-exchange
19
+ * @param exchange The base exchange name
20
+ * @param namespace Optional namespace override (defaults to NODE_ENV)
21
+ * @returns The namespaced exchange name
22
+ */
23
+ export function getNamespacedExchange(exchange, namespace) {
24
+ const env = namespace || process.env.NODE_ENV || 'local';
25
+ return `${env}-${exchange}`;
26
+ }
27
+ /**
28
+ * Strips the namespace prefix from a queue name
29
+ * @param queue The namespaced queue name
30
+ * @returns The queue name without namespace prefix
31
+ */
32
+ export function stripQueueNamespace(queue) {
33
+ const match = queue.match(/^[^-]+-(.+)$/);
34
+ return match ? match[1] : queue;
35
+ }
36
+ /**
37
+ * Extracts the namespace from a namespaced queue name
38
+ * @param queue The namespaced queue name
39
+ * @returns The namespace or null if not namespaced
40
+ */
41
+ export function extractQueueNamespace(queue) {
42
+ const match = queue.match(/^([^-]+)-/);
43
+ return match ? match[1] : null;
44
+ }
@@ -0,0 +1,27 @@
1
+ import type { RabbitMQConnection, PublishOptions, DelaySettings } from './types.js';
2
+ /**
3
+ * Publishes a message to a queue
4
+ * @param conn RabbitMQ connection
5
+ * @param queue Queue name (will be namespaced)
6
+ * @param data Message data (will be JSON stringified)
7
+ * @param options Publish options
8
+ */
9
+ export declare function publish(conn: RabbitMQConnection, queue: string, data: unknown, options?: PublishOptions): Promise<boolean>;
10
+ /**
11
+ * Publishes a message with delay using delayed exchange
12
+ * @param conn RabbitMQ connection
13
+ * @param queue Queue name (will be namespaced)
14
+ * @param data Message data (will be JSON stringified)
15
+ * @param delay Delay settings
16
+ * @param options Additional publish options
17
+ */
18
+ export declare function publishWithDelay(conn: RabbitMQConnection, queue: string, data: unknown, delay: DelaySettings, options?: PublishOptions): Promise<boolean>;
19
+ /**
20
+ * Publishes to a fanout exchange (broadcasts to all bound queues)
21
+ * @param conn RabbitMQ connection
22
+ * @param exchange Exchange name (will be namespaced)
23
+ * @param data Message data
24
+ * @param options Publish options
25
+ */
26
+ export declare function publishToExchange(conn: RabbitMQConnection, exchange: string, data: unknown, routingKey?: string, options?: PublishOptions): boolean;
27
+ //# sourceMappingURL=publisher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.d.ts","sourceRoot":"","sources":["../../src/rabbitmq/publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIpF;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BpI;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA8CnK;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,GAAE,MAAW,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAQ3J"}
@@ -0,0 +1,94 @@
1
+ import { getNamespacedQueue, getNamespacedExchange } from './namespace-helpers.js';
2
+ import { RABBITMQ_DEFAULTS } from '../constants/defaults.js';
3
+ /**
4
+ * Publishes a message to a queue
5
+ * @param conn RabbitMQ connection
6
+ * @param queue Queue name (will be namespaced)
7
+ * @param data Message data (will be JSON stringified)
8
+ * @param options Publish options
9
+ */
10
+ export async function publish(conn, queue, data, options = {}) {
11
+ const finalQueue = getNamespacedQueue(queue, conn.namespace);
12
+ const content = Buffer.from(JSON.stringify(data));
13
+ // Ensure queue exists
14
+ await conn.channel.assertQueue(finalQueue, {
15
+ durable: true
16
+ });
17
+ const publishOptions = {
18
+ persistent: options.persistent ?? true,
19
+ priority: options.priority,
20
+ expiration: options.expiration,
21
+ correlationId: options.correlationId,
22
+ replyTo: options.replyTo,
23
+ headers: options.headers
24
+ };
25
+ // Remove undefined values
26
+ Object.keys(publishOptions).forEach((key) => {
27
+ if (publishOptions[key] === undefined) {
28
+ delete publishOptions[key];
29
+ }
30
+ });
31
+ return conn.channel.sendToQueue(finalQueue, content, publishOptions);
32
+ }
33
+ /**
34
+ * Publishes a message with delay using delayed exchange
35
+ * @param conn RabbitMQ connection
36
+ * @param queue Queue name (will be namespaced)
37
+ * @param data Message data (will be JSON stringified)
38
+ * @param delay Delay settings
39
+ * @param options Additional publish options
40
+ */
41
+ export async function publishWithDelay(conn, queue, data, delay, options = {}) {
42
+ const finalQueue = getNamespacedQueue(queue, conn.namespace);
43
+ const exchangeName = delay.delayExchange || RABBITMQ_DEFAULTS.DEFAULT_DELAY_EXCHANGE;
44
+ const finalExchange = getNamespacedExchange(exchangeName, conn.namespace);
45
+ // Track delay attempts if using max delays
46
+ let messageData = data;
47
+ if (typeof data === 'object' && data !== null) {
48
+ const delaySettings = {
49
+ ...delay,
50
+ delayAttempts: (delay.delayAttempts ?? 0) + 1
51
+ };
52
+ // Check if we've exceeded max delays
53
+ if (delay.maxDelays && delaySettings.delayAttempts > delay.maxDelays) {
54
+ console.log(`Max delay attempts (${delay.maxDelays}) exceeded for queue ${queue}`);
55
+ return false;
56
+ }
57
+ messageData = {
58
+ ...data,
59
+ delaySettings
60
+ };
61
+ }
62
+ const content = Buffer.from(JSON.stringify(messageData));
63
+ // Assert delayed exchange (requires delayed-message-exchange plugin)
64
+ await conn.channel.assertExchange(finalExchange, 'x-delayed-message', {
65
+ durable: true,
66
+ arguments: { 'x-delayed-type': 'direct' }
67
+ });
68
+ // Ensure queue exists and bind to exchange
69
+ await conn.channel.assertQueue(finalQueue, { durable: true });
70
+ await conn.channel.bindQueue(finalQueue, finalExchange, finalQueue);
71
+ const headers = {
72
+ ...options.headers,
73
+ 'x-delay': delay.delayTime
74
+ };
75
+ return conn.channel.publish(finalExchange, finalQueue, content, {
76
+ persistent: options.persistent ?? true,
77
+ headers
78
+ });
79
+ }
80
+ /**
81
+ * Publishes to a fanout exchange (broadcasts to all bound queues)
82
+ * @param conn RabbitMQ connection
83
+ * @param exchange Exchange name (will be namespaced)
84
+ * @param data Message data
85
+ * @param options Publish options
86
+ */
87
+ export function publishToExchange(conn, exchange, data, routingKey = '', options = {}) {
88
+ const finalExchange = getNamespacedExchange(exchange, conn.namespace);
89
+ const content = Buffer.from(JSON.stringify(data));
90
+ return conn.channel.publish(finalExchange, routingKey, content, {
91
+ persistent: options.persistent ?? true,
92
+ headers: options.headers
93
+ });
94
+ }
@@ -0,0 +1,94 @@
1
+ import type { Connection, Channel, ConsumeMessage } from 'amqplib';
2
+ /**
3
+ * RabbitMQ connection instance
4
+ */
5
+ export interface RabbitMQConnection {
6
+ /** The underlying amqplib connection */
7
+ connection: Connection;
8
+ /** The main channel for operations */
9
+ channel: Channel;
10
+ /** Default namespace for queues */
11
+ namespace: string;
12
+ /** Application name for connection identification */
13
+ appName: string;
14
+ /** Close the connection */
15
+ close(): Promise<void>;
16
+ /** Check if connected */
17
+ isConnected(): boolean;
18
+ /** Reconnect to RabbitMQ */
19
+ reconnect(): Promise<void>;
20
+ }
21
+ /**
22
+ * RabbitMQ connection configuration
23
+ */
24
+ export interface RabbitMQConnectionConfig {
25
+ host: string;
26
+ port?: number;
27
+ username: string;
28
+ password: string;
29
+ vhost?: string;
30
+ heartbeat?: number;
31
+ connectionTimeout?: number;
32
+ protocol?: 'amqp' | 'amqps';
33
+ appName?: string;
34
+ namespace?: string;
35
+ }
36
+ /**
37
+ * Delay settings for delayed message requeue
38
+ */
39
+ export interface DelaySettings {
40
+ /** Delay exchange name */
41
+ delayExchange?: string;
42
+ /** Delay time in milliseconds */
43
+ delayTime: number;
44
+ /** Current delay attempt count */
45
+ delayAttempts?: number;
46
+ /** Maximum number of delay attempts */
47
+ maxDelays?: number;
48
+ }
49
+ /**
50
+ * Options for publishing messages
51
+ */
52
+ export interface PublishOptions {
53
+ /** Whether message should persist to disk */
54
+ persistent?: boolean;
55
+ /** Message priority (0-9) */
56
+ priority?: number;
57
+ /** Message expiration in milliseconds */
58
+ expiration?: string;
59
+ /** Correlation ID for RPC patterns */
60
+ correlationId?: string;
61
+ /** Reply-to queue for RPC patterns */
62
+ replyTo?: string;
63
+ /** Custom headers */
64
+ headers?: Record<string, unknown>;
65
+ /** Delay settings for delayed messages */
66
+ delay?: DelaySettings;
67
+ }
68
+ /**
69
+ * Options for consuming messages
70
+ */
71
+ export interface ConsumeOptions {
72
+ /** Consumer tag for identification */
73
+ consumerTag?: string;
74
+ /** Whether to acknowledge automatically */
75
+ noAck?: boolean;
76
+ /** Prefetch count for this consumer */
77
+ prefetch?: number;
78
+ }
79
+ /**
80
+ * Message handler function type
81
+ */
82
+ export type MessageHandler = (message: ConsumeMessage, content: unknown) => Promise<void> | void;
83
+ /**
84
+ * Consumer instance interface
85
+ */
86
+ export interface RabbitMQConsumer {
87
+ /** Queue being consumed */
88
+ queue: string;
89
+ /** Consumer tag */
90
+ consumerTag: string;
91
+ /** Stop consuming */
92
+ cancel(): Promise<void>;
93
+ }
94
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rabbitmq/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,UAAU,EAAE,UAAU,CAAC;IACvB,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,yBAAyB;IACzB,WAAW,IAAI,OAAO,CAAC;IACvB,4BAA4B;IAC5B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,0CAA0C;IAC1C,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEjG;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { RedisInstance, RedisInstanceConfig, RedisClusterInstanceConfig } from './types.js';
2
+ /**
3
+ * Creates a single Redis instance
4
+ * @param config Redis configuration
5
+ * @returns RedisInstance wrapper
6
+ */
7
+ export declare function createRedisClient(config: RedisInstanceConfig): RedisInstance;
8
+ /**
9
+ * Creates a Redis cluster instance
10
+ * @param config Cluster configuration
11
+ * @returns RedisInstance wrapper
12
+ */
13
+ export declare function createRedisCluster(config: RedisClusterInstanceConfig): RedisInstance;
14
+ //# sourceMappingURL=client-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-factory.d.ts","sourceRoot":"","sources":["../../src/redis/client-factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAGjG;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,aAAa,CAgD5E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,0BAA0B,GAAG,aAAa,CA8CpF"}
@@ -0,0 +1,98 @@
1
+ import { Redis, Cluster } from 'ioredis';
2
+ import { REDIS_DEFAULTS } from '../constants/defaults.js';
3
+ /**
4
+ * Creates a single Redis instance
5
+ * @param config Redis configuration
6
+ * @returns RedisInstance wrapper
7
+ */
8
+ export function createRedisClient(config) {
9
+ const client = new Redis({
10
+ host: config.host,
11
+ port: config.port ?? REDIS_DEFAULTS.PORT,
12
+ password: config.password,
13
+ db: config.db ?? REDIS_DEFAULTS.DB,
14
+ keyPrefix: config.keyPrefix,
15
+ tls: config.tls ? {} : undefined,
16
+ connectTimeout: config.connectTimeout ?? REDIS_DEFAULTS.CONNECT_TIMEOUT_MS,
17
+ commandTimeout: config.commandTimeout ?? REDIS_DEFAULTS.COMMAND_TIMEOUT_MS,
18
+ retryStrategy: (times) => {
19
+ if (times > REDIS_DEFAULTS.MAX_RETRIES) {
20
+ return null; // Stop retrying
21
+ }
22
+ return Math.min(times * REDIS_DEFAULTS.RETRY_DELAY_MS, 2000);
23
+ },
24
+ lazyConnect: false
25
+ });
26
+ const namespace = config.namespace || process.env.NODE_ENV || 'local';
27
+ let connected = false;
28
+ client.on('connect', () => {
29
+ connected = true;
30
+ console.log('Redis Connection: Single Instance connected');
31
+ });
32
+ client.on('error', (err) => {
33
+ console.error('Redis error:', err);
34
+ connected = false;
35
+ });
36
+ client.on('close', () => {
37
+ connected = false;
38
+ });
39
+ return {
40
+ client,
41
+ isCluster: false,
42
+ namespace,
43
+ async close() {
44
+ await client.quit();
45
+ connected = false;
46
+ },
47
+ isConnected() {
48
+ return connected;
49
+ }
50
+ };
51
+ }
52
+ /**
53
+ * Creates a Redis cluster instance
54
+ * @param config Cluster configuration
55
+ * @returns RedisInstance wrapper
56
+ */
57
+ export function createRedisCluster(config) {
58
+ const client = new Cluster(config.nodes, {
59
+ redisOptions: {
60
+ password: config.password,
61
+ keyPrefix: config.keyPrefix,
62
+ tls: config.tls ? {} : undefined,
63
+ connectTimeout: config.connectTimeout ?? REDIS_DEFAULTS.CONNECT_TIMEOUT_MS,
64
+ commandTimeout: config.commandTimeout ?? REDIS_DEFAULTS.COMMAND_TIMEOUT_MS
65
+ },
66
+ clusterRetryStrategy: (times) => {
67
+ if (times > REDIS_DEFAULTS.MAX_RETRIES) {
68
+ return null;
69
+ }
70
+ return Math.min(times * REDIS_DEFAULTS.RETRY_DELAY_MS, 2000);
71
+ }
72
+ });
73
+ const namespace = config.namespace || process.env.NODE_ENV || 'local';
74
+ let connected = false;
75
+ client.on('connect', () => {
76
+ connected = true;
77
+ console.log('Redis Connection: Cluster connected');
78
+ });
79
+ client.on('error', (err) => {
80
+ console.error('Redis cluster error:', err);
81
+ connected = false;
82
+ });
83
+ client.on('close', () => {
84
+ connected = false;
85
+ });
86
+ return {
87
+ client,
88
+ isCluster: true,
89
+ namespace,
90
+ async close() {
91
+ await client.quit();
92
+ connected = false;
93
+ },
94
+ isConnected() {
95
+ return connected;
96
+ }
97
+ };
98
+ }
@@ -0,0 +1,6 @@
1
+ export { createRedisClient, createRedisCluster } from './client-factory.js';
2
+ export { getNamespacedKey, processKey, stripNamespace, extractNamespace } from './namespace-helpers.js';
3
+ export { set, get, del, exists, keys, expire, ttl, incr, incrBy, decr, listPush, lpush, rpush, lpop, rpop, lrange, lgetall, llen, lindex, lset, ltrim } from './operations/index.js';
4
+ export { ListPosition } from './types.js';
5
+ export type { RedisClient, RedisData, RedisInstance, RedisInstanceConfig, RedisClusterInstanceConfig, SetOptions, GetOptions } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAExG,OAAO,EACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,MAAM,EACN,IAAI,EACJ,MAAM,EACN,GAAG,EACH,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,KAAK,EACN,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { createRedisClient, createRedisCluster } from './client-factory.js';
2
+ export { getNamespacedKey, processKey, stripNamespace, extractNamespace } from './namespace-helpers.js';
3
+ export { set, get, del, exists, keys, expire, ttl, incr, incrBy, decr, listPush, lpush, rpush, lpop, rpop, lrange, lgetall, llen, lindex, lset, ltrim } from './operations/index.js';
4
+ export { ListPosition } from './types.js';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CRITICAL: Redis namespace pattern - {NODE_ENV}:key
3
+ * This MUST be preserved for environment isolation in Redis clusters
4
+ */
5
+ /**
6
+ * Gets the namespaced key with environment prefix
7
+ * Format: {environment}:key
8
+ * @param key The base key
9
+ * @param namespace Optional namespace override (defaults to NODE_ENV)
10
+ * @returns The namespaced key
11
+ */
12
+ export declare function getNamespacedKey(key: string, namespace?: string): string;
13
+ /**
14
+ * Processes a key, optionally adding namespace
15
+ * @param key The base key
16
+ * @param useNamespace Whether to add namespace prefix
17
+ * @param namespace Optional namespace override
18
+ * @returns The processed key
19
+ */
20
+ export declare function processKey(key: string, useNamespace?: boolean, namespace?: string): string;
21
+ /**
22
+ * Strips the namespace prefix from a key
23
+ * @param key The namespaced key
24
+ * @returns The key without namespace prefix
25
+ */
26
+ export declare function stripNamespace(key: string): string;
27
+ /**
28
+ * Extracts the namespace from a namespaced key
29
+ * @param key The namespaced key
30
+ * @returns The namespace or null if not namespaced
31
+ */
32
+ export declare function extractNamespace(key: string): string | null;
33
+ //# sourceMappingURL=namespace-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace-helpers.d.ts","sourceRoot":"","sources":["../../src/redis/namespace-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhG;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3D"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * CRITICAL: Redis namespace pattern - {NODE_ENV}:key
3
+ * This MUST be preserved for environment isolation in Redis clusters
4
+ */
5
+ /**
6
+ * Gets the namespaced key with environment prefix
7
+ * Format: {environment}:key
8
+ * @param key The base key
9
+ * @param namespace Optional namespace override (defaults to NODE_ENV)
10
+ * @returns The namespaced key
11
+ */
12
+ export function getNamespacedKey(key, namespace) {
13
+ const env = namespace || process.env.NODE_ENV || 'local';
14
+ return `{${env}}:${key}`;
15
+ }
16
+ /**
17
+ * Processes a key, optionally adding namespace
18
+ * @param key The base key
19
+ * @param useNamespace Whether to add namespace prefix
20
+ * @param namespace Optional namespace override
21
+ * @returns The processed key
22
+ */
23
+ export function processKey(key, useNamespace = true, namespace) {
24
+ return useNamespace ? getNamespacedKey(key, namespace) : key;
25
+ }
26
+ /**
27
+ * Strips the namespace prefix from a key
28
+ * @param key The namespaced key
29
+ * @returns The key without namespace prefix
30
+ */
31
+ export function stripNamespace(key) {
32
+ const match = key.match(/^\{[^}]+\}:(.+)$/);
33
+ return match ? match[1] : key;
34
+ }
35
+ /**
36
+ * Extracts the namespace from a namespaced key
37
+ * @param key The namespaced key
38
+ * @returns The namespace or null if not namespaced
39
+ */
40
+ export function extractNamespace(key) {
41
+ const match = key.match(/^\{([^}]+)\}:/);
42
+ return match ? match[1] : null;
43
+ }
@@ -0,0 +1,3 @@
1
+ export { set, get, del, exists, keys, expire, ttl, incr, incrBy, decr } from './standard.js';
2
+ export { listPush, lpush, rpush, lpop, rpop, lrange, lgetall, llen, lindex, lset, ltrim } from './list.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/redis/operations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE7F,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { set, get, del, exists, keys, expire, ttl, incr, incrBy, decr } from './standard.js';
2
+ export { listPush, lpush, rpush, lpop, rpop, lrange, lgetall, llen, lindex, lset, ltrim } from './list.js';
@@ -0,0 +1,102 @@
1
+ import type { RedisInstance, RedisData } from '../types.js';
2
+ import { ListPosition } from '../types.js';
3
+ /**
4
+ * Adds an element to a list
5
+ * @param redis Redis instance
6
+ * @param key The list key
7
+ * @param position Where to add (front or back)
8
+ * @param data The data to add
9
+ * @param useNamespace Whether to apply namespace
10
+ * @returns Length of list after operation
11
+ */
12
+ export declare function listPush(redis: RedisInstance, key: string, position: ListPosition, data: RedisData, useNamespace?: boolean): Promise<number>;
13
+ /**
14
+ * Adds an element to the front of a list
15
+ * @param redis Redis instance
16
+ * @param key The list key
17
+ * @param data The data to add
18
+ * @param useNamespace Whether to apply namespace
19
+ * @returns Length of list after operation
20
+ */
21
+ export declare function lpush(redis: RedisInstance, key: string, data: RedisData, useNamespace?: boolean): Promise<number>;
22
+ /**
23
+ * Adds an element to the back of a list
24
+ * @param redis Redis instance
25
+ * @param key The list key
26
+ * @param data The data to add
27
+ * @param useNamespace Whether to apply namespace
28
+ * @returns Length of list after operation
29
+ */
30
+ export declare function rpush(redis: RedisInstance, key: string, data: RedisData, useNamespace?: boolean): Promise<number>;
31
+ /**
32
+ * Removes and returns the first element of a list
33
+ * @param redis Redis instance
34
+ * @param key The list key
35
+ * @param useNamespace Whether to apply namespace
36
+ * @returns The element or null if list is empty
37
+ */
38
+ export declare function lpop(redis: RedisInstance, key: string, useNamespace?: boolean): Promise<string | null>;
39
+ /**
40
+ * Removes and returns the last element of a list
41
+ * @param redis Redis instance
42
+ * @param key The list key
43
+ * @param useNamespace Whether to apply namespace
44
+ * @returns The element or null if list is empty
45
+ */
46
+ export declare function rpop(redis: RedisInstance, key: string, useNamespace?: boolean): Promise<string | null>;
47
+ /**
48
+ * Gets a range of elements from a list
49
+ * @param redis Redis instance
50
+ * @param key The list key
51
+ * @param start Start index (0-based)
52
+ * @param stop Stop index (inclusive, -1 for end)
53
+ * @param useNamespace Whether to apply namespace
54
+ * @returns Array of elements
55
+ */
56
+ export declare function lrange(redis: RedisInstance, key: string, start: number, stop: number, useNamespace?: boolean): Promise<string[]>;
57
+ /**
58
+ * Gets all elements from a list
59
+ * @param redis Redis instance
60
+ * @param key The list key
61
+ * @param useNamespace Whether to apply namespace
62
+ * @returns Array of all elements
63
+ */
64
+ export declare function lgetall(redis: RedisInstance, key: string, useNamespace?: boolean): Promise<string[]>;
65
+ /**
66
+ * Gets the length of a list
67
+ * @param redis Redis instance
68
+ * @param key The list key
69
+ * @param useNamespace Whether to apply namespace
70
+ * @returns Length of list
71
+ */
72
+ export declare function llen(redis: RedisInstance, key: string, useNamespace?: boolean): Promise<number>;
73
+ /**
74
+ * Gets an element at a specific index
75
+ * @param redis Redis instance
76
+ * @param key The list key
77
+ * @param index The index
78
+ * @param useNamespace Whether to apply namespace
79
+ * @returns The element or null
80
+ */
81
+ export declare function lindex(redis: RedisInstance, key: string, index: number, useNamespace?: boolean): Promise<string | null>;
82
+ /**
83
+ * Sets an element at a specific index
84
+ * @param redis Redis instance
85
+ * @param key The list key
86
+ * @param index The index
87
+ * @param value The new value
88
+ * @param useNamespace Whether to apply namespace
89
+ * @returns 'OK' on success
90
+ */
91
+ export declare function lset(redis: RedisInstance, key: string, index: number, value: RedisData, useNamespace?: boolean): Promise<string>;
92
+ /**
93
+ * Trims a list to the specified range
94
+ * @param redis Redis instance
95
+ * @param key The list key
96
+ * @param start Start index
97
+ * @param stop Stop index
98
+ * @param useNamespace Whether to apply namespace
99
+ * @returns 'OK' on success
100
+ */
101
+ export declare function ltrim(redis: RedisInstance, key: string, start: number, stop: number, useNamespace?: boolean): Promise<string>;
102
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/redis/operations/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxJ;AAED;;;;;;;GAOG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7H;AAED;;;;;;;GAOG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7H;AAED;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGlH;AAED;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGlH;AAED;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAG5I;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEhH;AAED;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3G;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnI;AAED;;;;;;;;GAQG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5I;AAED;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzI"}