@bloomneo/appkit 1.2.9

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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +902 -0
  3. package/bin/appkit.js +71 -0
  4. package/bin/commands/generate.js +1050 -0
  5. package/bin/templates/backend/README.md.template +39 -0
  6. package/bin/templates/backend/api.http.template +0 -0
  7. package/bin/templates/backend/docs/APPKIT_CLI.md +507 -0
  8. package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +61 -0
  9. package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +2539 -0
  10. package/bin/templates/backend/package.json.template +34 -0
  11. package/bin/templates/backend/src/api/features/welcome/welcome.http.template +29 -0
  12. package/bin/templates/backend/src/api/features/welcome/welcome.route.ts.template +36 -0
  13. package/bin/templates/backend/src/api/features/welcome/welcome.service.ts.template +88 -0
  14. package/bin/templates/backend/src/api/features/welcome/welcome.types.ts.template +18 -0
  15. package/bin/templates/backend/src/api/lib/api-router.ts.template +84 -0
  16. package/bin/templates/backend/src/api/server.ts.template +188 -0
  17. package/bin/templates/backend/tsconfig.api.json.template +24 -0
  18. package/bin/templates/backend/tsconfig.json.template +40 -0
  19. package/bin/templates/feature/feature.http.template +63 -0
  20. package/bin/templates/feature/feature.route.ts.template +36 -0
  21. package/bin/templates/feature/feature.service.ts.template +81 -0
  22. package/bin/templates/feature/feature.types.ts.template +23 -0
  23. package/bin/templates/feature-db/feature.http.template +63 -0
  24. package/bin/templates/feature-db/feature.model.ts.template +74 -0
  25. package/bin/templates/feature-db/feature.route.ts.template +58 -0
  26. package/bin/templates/feature-db/feature.service.ts.template +231 -0
  27. package/bin/templates/feature-db/feature.types.ts.template +25 -0
  28. package/bin/templates/feature-db/schema-addition.prisma.template +9 -0
  29. package/bin/templates/feature-db/seeding/README.md.template +57 -0
  30. package/bin/templates/feature-db/seeding/feature.seed.js.template +67 -0
  31. package/bin/templates/feature-user/schema-addition.prisma.template +19 -0
  32. package/bin/templates/feature-user/user.http.template +157 -0
  33. package/bin/templates/feature-user/user.model.ts.template +244 -0
  34. package/bin/templates/feature-user/user.route.ts.template +379 -0
  35. package/bin/templates/feature-user/user.seed.js.template +182 -0
  36. package/bin/templates/feature-user/user.service.ts.template +426 -0
  37. package/bin/templates/feature-user/user.types.ts.template +127 -0
  38. package/dist/auth/auth.d.ts +182 -0
  39. package/dist/auth/auth.d.ts.map +1 -0
  40. package/dist/auth/auth.js +477 -0
  41. package/dist/auth/auth.js.map +1 -0
  42. package/dist/auth/defaults.d.ts +104 -0
  43. package/dist/auth/defaults.d.ts.map +1 -0
  44. package/dist/auth/defaults.js +374 -0
  45. package/dist/auth/defaults.js.map +1 -0
  46. package/dist/auth/index.d.ts +70 -0
  47. package/dist/auth/index.d.ts.map +1 -0
  48. package/dist/auth/index.js +94 -0
  49. package/dist/auth/index.js.map +1 -0
  50. package/dist/cache/cache.d.ts +118 -0
  51. package/dist/cache/cache.d.ts.map +1 -0
  52. package/dist/cache/cache.js +249 -0
  53. package/dist/cache/cache.js.map +1 -0
  54. package/dist/cache/defaults.d.ts +63 -0
  55. package/dist/cache/defaults.d.ts.map +1 -0
  56. package/dist/cache/defaults.js +193 -0
  57. package/dist/cache/defaults.js.map +1 -0
  58. package/dist/cache/index.d.ts +101 -0
  59. package/dist/cache/index.d.ts.map +1 -0
  60. package/dist/cache/index.js +203 -0
  61. package/dist/cache/index.js.map +1 -0
  62. package/dist/cache/strategies/memory.d.ts +138 -0
  63. package/dist/cache/strategies/memory.d.ts.map +1 -0
  64. package/dist/cache/strategies/memory.js +348 -0
  65. package/dist/cache/strategies/memory.js.map +1 -0
  66. package/dist/cache/strategies/redis.d.ts +105 -0
  67. package/dist/cache/strategies/redis.d.ts.map +1 -0
  68. package/dist/cache/strategies/redis.js +318 -0
  69. package/dist/cache/strategies/redis.js.map +1 -0
  70. package/dist/config/config.d.ts +62 -0
  71. package/dist/config/config.d.ts.map +1 -0
  72. package/dist/config/config.js +107 -0
  73. package/dist/config/config.js.map +1 -0
  74. package/dist/config/defaults.d.ts +44 -0
  75. package/dist/config/defaults.d.ts.map +1 -0
  76. package/dist/config/defaults.js +217 -0
  77. package/dist/config/defaults.js.map +1 -0
  78. package/dist/config/index.d.ts +105 -0
  79. package/dist/config/index.d.ts.map +1 -0
  80. package/dist/config/index.js +163 -0
  81. package/dist/config/index.js.map +1 -0
  82. package/dist/database/adapters/mongoose.d.ts +106 -0
  83. package/dist/database/adapters/mongoose.d.ts.map +1 -0
  84. package/dist/database/adapters/mongoose.js +480 -0
  85. package/dist/database/adapters/mongoose.js.map +1 -0
  86. package/dist/database/adapters/prisma.d.ts +106 -0
  87. package/dist/database/adapters/prisma.d.ts.map +1 -0
  88. package/dist/database/adapters/prisma.js +494 -0
  89. package/dist/database/adapters/prisma.js.map +1 -0
  90. package/dist/database/defaults.d.ts +87 -0
  91. package/dist/database/defaults.d.ts.map +1 -0
  92. package/dist/database/defaults.js +271 -0
  93. package/dist/database/defaults.js.map +1 -0
  94. package/dist/database/index.d.ts +137 -0
  95. package/dist/database/index.d.ts.map +1 -0
  96. package/dist/database/index.js +490 -0
  97. package/dist/database/index.js.map +1 -0
  98. package/dist/email/defaults.d.ts +100 -0
  99. package/dist/email/defaults.d.ts.map +1 -0
  100. package/dist/email/defaults.js +400 -0
  101. package/dist/email/defaults.js.map +1 -0
  102. package/dist/email/email.d.ts +139 -0
  103. package/dist/email/email.d.ts.map +1 -0
  104. package/dist/email/email.js +316 -0
  105. package/dist/email/email.js.map +1 -0
  106. package/dist/email/index.d.ts +176 -0
  107. package/dist/email/index.d.ts.map +1 -0
  108. package/dist/email/index.js +251 -0
  109. package/dist/email/index.js.map +1 -0
  110. package/dist/email/strategies/console.d.ts +90 -0
  111. package/dist/email/strategies/console.d.ts.map +1 -0
  112. package/dist/email/strategies/console.js +268 -0
  113. package/dist/email/strategies/console.js.map +1 -0
  114. package/dist/email/strategies/resend.d.ts +84 -0
  115. package/dist/email/strategies/resend.d.ts.map +1 -0
  116. package/dist/email/strategies/resend.js +266 -0
  117. package/dist/email/strategies/resend.js.map +1 -0
  118. package/dist/email/strategies/smtp.d.ts +77 -0
  119. package/dist/email/strategies/smtp.d.ts.map +1 -0
  120. package/dist/email/strategies/smtp.js +286 -0
  121. package/dist/email/strategies/smtp.js.map +1 -0
  122. package/dist/error/defaults.d.ts +40 -0
  123. package/dist/error/defaults.d.ts.map +1 -0
  124. package/dist/error/defaults.js +75 -0
  125. package/dist/error/defaults.js.map +1 -0
  126. package/dist/error/error.d.ts +140 -0
  127. package/dist/error/error.d.ts.map +1 -0
  128. package/dist/error/error.js +200 -0
  129. package/dist/error/error.js.map +1 -0
  130. package/dist/error/index.d.ts +145 -0
  131. package/dist/error/index.d.ts.map +1 -0
  132. package/dist/error/index.js +145 -0
  133. package/dist/error/index.js.map +1 -0
  134. package/dist/event/defaults.d.ts +111 -0
  135. package/dist/event/defaults.d.ts.map +1 -0
  136. package/dist/event/defaults.js +378 -0
  137. package/dist/event/defaults.js.map +1 -0
  138. package/dist/event/event.d.ts +171 -0
  139. package/dist/event/event.d.ts.map +1 -0
  140. package/dist/event/event.js +391 -0
  141. package/dist/event/event.js.map +1 -0
  142. package/dist/event/index.d.ts +173 -0
  143. package/dist/event/index.d.ts.map +1 -0
  144. package/dist/event/index.js +302 -0
  145. package/dist/event/index.js.map +1 -0
  146. package/dist/event/strategies/memory.d.ts +122 -0
  147. package/dist/event/strategies/memory.d.ts.map +1 -0
  148. package/dist/event/strategies/memory.js +331 -0
  149. package/dist/event/strategies/memory.js.map +1 -0
  150. package/dist/event/strategies/redis.d.ts +115 -0
  151. package/dist/event/strategies/redis.d.ts.map +1 -0
  152. package/dist/event/strategies/redis.js +434 -0
  153. package/dist/event/strategies/redis.js.map +1 -0
  154. package/dist/index.d.ts +58 -0
  155. package/dist/index.d.ts.map +1 -0
  156. package/dist/index.js +72 -0
  157. package/dist/index.js.map +1 -0
  158. package/dist/logger/defaults.d.ts +67 -0
  159. package/dist/logger/defaults.d.ts.map +1 -0
  160. package/dist/logger/defaults.js +213 -0
  161. package/dist/logger/defaults.js.map +1 -0
  162. package/dist/logger/index.d.ts +84 -0
  163. package/dist/logger/index.d.ts.map +1 -0
  164. package/dist/logger/index.js +101 -0
  165. package/dist/logger/index.js.map +1 -0
  166. package/dist/logger/logger.d.ts +165 -0
  167. package/dist/logger/logger.d.ts.map +1 -0
  168. package/dist/logger/logger.js +843 -0
  169. package/dist/logger/logger.js.map +1 -0
  170. package/dist/logger/transports/console.d.ts +102 -0
  171. package/dist/logger/transports/console.d.ts.map +1 -0
  172. package/dist/logger/transports/console.js +276 -0
  173. package/dist/logger/transports/console.js.map +1 -0
  174. package/dist/logger/transports/database.d.ts +153 -0
  175. package/dist/logger/transports/database.d.ts.map +1 -0
  176. package/dist/logger/transports/database.js +539 -0
  177. package/dist/logger/transports/database.js.map +1 -0
  178. package/dist/logger/transports/file.d.ts +146 -0
  179. package/dist/logger/transports/file.d.ts.map +1 -0
  180. package/dist/logger/transports/file.js +464 -0
  181. package/dist/logger/transports/file.js.map +1 -0
  182. package/dist/logger/transports/http.d.ts +128 -0
  183. package/dist/logger/transports/http.d.ts.map +1 -0
  184. package/dist/logger/transports/http.js +401 -0
  185. package/dist/logger/transports/http.js.map +1 -0
  186. package/dist/logger/transports/webhook.d.ts +152 -0
  187. package/dist/logger/transports/webhook.d.ts.map +1 -0
  188. package/dist/logger/transports/webhook.js +485 -0
  189. package/dist/logger/transports/webhook.js.map +1 -0
  190. package/dist/queue/defaults.d.ts +66 -0
  191. package/dist/queue/defaults.d.ts.map +1 -0
  192. package/dist/queue/defaults.js +205 -0
  193. package/dist/queue/defaults.js.map +1 -0
  194. package/dist/queue/index.d.ts +124 -0
  195. package/dist/queue/index.d.ts.map +1 -0
  196. package/dist/queue/index.js +116 -0
  197. package/dist/queue/index.js.map +1 -0
  198. package/dist/queue/queue.d.ts +156 -0
  199. package/dist/queue/queue.d.ts.map +1 -0
  200. package/dist/queue/queue.js +387 -0
  201. package/dist/queue/queue.js.map +1 -0
  202. package/dist/queue/transports/database.d.ts +165 -0
  203. package/dist/queue/transports/database.d.ts.map +1 -0
  204. package/dist/queue/transports/database.js +595 -0
  205. package/dist/queue/transports/database.js.map +1 -0
  206. package/dist/queue/transports/memory.d.ts +143 -0
  207. package/dist/queue/transports/memory.d.ts.map +1 -0
  208. package/dist/queue/transports/memory.js +415 -0
  209. package/dist/queue/transports/memory.js.map +1 -0
  210. package/dist/queue/transports/redis.d.ts +203 -0
  211. package/dist/queue/transports/redis.d.ts.map +1 -0
  212. package/dist/queue/transports/redis.js +744 -0
  213. package/dist/queue/transports/redis.js.map +1 -0
  214. package/dist/security/defaults.d.ts +64 -0
  215. package/dist/security/defaults.d.ts.map +1 -0
  216. package/dist/security/defaults.js +159 -0
  217. package/dist/security/defaults.js.map +1 -0
  218. package/dist/security/index.d.ts +110 -0
  219. package/dist/security/index.d.ts.map +1 -0
  220. package/dist/security/index.js +160 -0
  221. package/dist/security/index.js.map +1 -0
  222. package/dist/security/security.d.ts +138 -0
  223. package/dist/security/security.d.ts.map +1 -0
  224. package/dist/security/security.js +419 -0
  225. package/dist/security/security.js.map +1 -0
  226. package/dist/storage/defaults.d.ts +79 -0
  227. package/dist/storage/defaults.d.ts.map +1 -0
  228. package/dist/storage/defaults.js +358 -0
  229. package/dist/storage/defaults.js.map +1 -0
  230. package/dist/storage/index.d.ts +153 -0
  231. package/dist/storage/index.d.ts.map +1 -0
  232. package/dist/storage/index.js +242 -0
  233. package/dist/storage/index.js.map +1 -0
  234. package/dist/storage/storage.d.ts +151 -0
  235. package/dist/storage/storage.d.ts.map +1 -0
  236. package/dist/storage/storage.js +439 -0
  237. package/dist/storage/storage.js.map +1 -0
  238. package/dist/storage/strategies/local.d.ts +117 -0
  239. package/dist/storage/strategies/local.d.ts.map +1 -0
  240. package/dist/storage/strategies/local.js +368 -0
  241. package/dist/storage/strategies/local.js.map +1 -0
  242. package/dist/storage/strategies/r2.d.ts +130 -0
  243. package/dist/storage/strategies/r2.d.ts.map +1 -0
  244. package/dist/storage/strategies/r2.js +470 -0
  245. package/dist/storage/strategies/r2.js.map +1 -0
  246. package/dist/storage/strategies/s3.d.ts +121 -0
  247. package/dist/storage/strategies/s3.d.ts.map +1 -0
  248. package/dist/storage/strategies/s3.js +461 -0
  249. package/dist/storage/strategies/s3.js.map +1 -0
  250. package/dist/util/defaults.d.ts +77 -0
  251. package/dist/util/defaults.d.ts.map +1 -0
  252. package/dist/util/defaults.js +193 -0
  253. package/dist/util/defaults.js.map +1 -0
  254. package/dist/util/index.d.ts +97 -0
  255. package/dist/util/index.d.ts.map +1 -0
  256. package/dist/util/index.js +165 -0
  257. package/dist/util/index.js.map +1 -0
  258. package/dist/util/util.d.ts +145 -0
  259. package/dist/util/util.d.ts.map +1 -0
  260. package/dist/util/util.js +481 -0
  261. package/dist/util/util.js.map +1 -0
  262. package/package.json +234 -0
@@ -0,0 +1,434 @@
1
+ /**
2
+ * Redis event strategy with distributed pub/sub and automatic connection management
3
+ * @module @bloomneo/appkit/event
4
+ * @file src/event/strategies/redis.ts
5
+ *
6
+ * @llm-rule WHEN: App has REDIS_URL environment variable for distributed events across servers
7
+ * @llm-rule AVOID: Manual Redis setup - this handles connection, retry, and subscription management
8
+ * @llm-rule NOTE: Distributed events, automatic reconnection, pattern subscriptions, production-ready
9
+ */
10
+ /**
11
+ * Redis event strategy with distributed pub/sub and reliability features
12
+ */
13
+ export class RedisStrategy {
14
+ config;
15
+ namespace;
16
+ publisher = null;
17
+ subscriber = null;
18
+ connected = false;
19
+ listeners = new Map();
20
+ patternListeners = new Map();
21
+ /**
22
+ * Creates Redis strategy with direct environment access (like auth pattern)
23
+ * @llm-rule WHEN: Event initialization with REDIS_URL detected
24
+ * @llm-rule AVOID: Manual Redis configuration - environment detection handles this
25
+ */
26
+ constructor(config, namespace) {
27
+ this.config = config;
28
+ this.namespace = namespace;
29
+ }
30
+ /**
31
+ * Connects to Redis with automatic retry and pub/sub setup
32
+ * @llm-rule WHEN: Event initialization or reconnection after failure
33
+ * @llm-rule AVOID: Manual connection management - this handles all Redis complexity
34
+ */
35
+ async connect() {
36
+ if (this.connected)
37
+ return;
38
+ try {
39
+ // Dynamic import for Redis client
40
+ const { createClient } = await import('redis');
41
+ const redisConfig = this.config.redis;
42
+ // Create Redis clients (separate for pub/sub)
43
+ const clientConfig = {
44
+ url: redisConfig.url,
45
+ password: redisConfig.password,
46
+ socket: {
47
+ connectTimeout: redisConfig.connectTimeout,
48
+ reconnectStrategy: (retries) => {
49
+ if (retries >= redisConfig.maxRetries) {
50
+ console.error(`[AppKit] Redis max retries (${redisConfig.maxRetries}) exceeded`);
51
+ return new Error('Redis connection failed');
52
+ }
53
+ const delay = Math.min(redisConfig.retryDelay * Math.pow(2, retries), 10000);
54
+ console.warn(`[AppKit] Redis reconnecting in ${delay}ms (attempt ${retries + 1})`);
55
+ return delay;
56
+ },
57
+ },
58
+ };
59
+ // Create publisher and subscriber clients
60
+ this.publisher = createClient(clientConfig);
61
+ this.subscriber = createClient(clientConfig);
62
+ // Set up event handlers
63
+ this.setupEventHandlers();
64
+ // Connect both clients
65
+ await Promise.all([
66
+ this.publisher.connect(),
67
+ this.subscriber.connect()
68
+ ]);
69
+ this.connected = true;
70
+ if (this.config.environment.isDevelopment) {
71
+ console.log(`✅ [AppKit] Redis event strategy connected (namespace: ${this.namespace})`);
72
+ }
73
+ }
74
+ catch (error) {
75
+ this.connected = false;
76
+ this.publisher = null;
77
+ this.subscriber = null;
78
+ throw new Error(`Redis event connection failed: ${error.message}`);
79
+ }
80
+ }
81
+ /**
82
+ * Sets up Redis event handlers for connection management
83
+ */
84
+ setupEventHandlers() {
85
+ if (!this.publisher || !this.subscriber)
86
+ return;
87
+ // Publisher events
88
+ this.publisher.on('error', (error) => {
89
+ console.error('[AppKit] Redis publisher error:', error.message);
90
+ this.connected = false;
91
+ });
92
+ this.publisher.on('ready', () => {
93
+ if (this.config.environment.isDevelopment) {
94
+ console.log('✅ [AppKit] Redis publisher ready');
95
+ }
96
+ });
97
+ // Subscriber events
98
+ this.subscriber.on('error', (error) => {
99
+ console.error('[AppKit] Redis subscriber error:', error.message);
100
+ this.connected = false;
101
+ });
102
+ this.subscriber.on('ready', () => {
103
+ if (this.config.environment.isDevelopment) {
104
+ console.log('✅ [AppKit] Redis subscriber ready');
105
+ }
106
+ });
107
+ // Handle reconnection
108
+ this.subscriber.on('reconnecting', () => {
109
+ this.connected = false;
110
+ if (this.config.environment.isDevelopment) {
111
+ console.log('🔄 [AppKit] Redis subscriber reconnecting...');
112
+ }
113
+ });
114
+ this.subscriber.on('end', () => {
115
+ this.connected = false;
116
+ if (this.config.environment.isDevelopment) {
117
+ console.log('👋 [AppKit] Redis subscriber connection ended');
118
+ }
119
+ });
120
+ }
121
+ /**
122
+ * Emits event via Redis pub/sub with automatic serialization
123
+ * @llm-rule WHEN: Sending events across multiple servers/processes
124
+ * @llm-rule AVOID: Manual Redis pub/sub - this handles serialization and namespacing
125
+ * @llm-rule NOTE: Events are distributed to all connected servers automatically
126
+ */
127
+ async emit(event, data) {
128
+ if (!this.connected || !this.publisher) {
129
+ console.error(`[AppKit] Redis not connected, cannot emit event: ${event}`);
130
+ return false;
131
+ }
132
+ try {
133
+ // Build Redis channel name with prefix
134
+ const channel = this.buildChannelName(event);
135
+ // Serialize event data
136
+ const message = this.serializeMessage(data);
137
+ // Publish to Redis
138
+ const result = await this.publisher.publish(channel, message);
139
+ // Log in development
140
+ if (this.config.environment.isDevelopment) {
141
+ console.log(`📤 [AppKit] Redis event published: ${event} (subscribers: ${result})`);
142
+ }
143
+ return result >= 0; // Redis returns number of subscribers
144
+ }
145
+ catch (error) {
146
+ console.error(`[AppKit] Redis emit error for event "${event}":`, error.message);
147
+ return false;
148
+ }
149
+ }
150
+ /**
151
+ * Adds event listener with Redis subscription management
152
+ * @llm-rule WHEN: Listening to distributed events across servers
153
+ * @llm-rule AVOID: Manual Redis subscribe - this handles pattern matching and message routing
154
+ */
155
+ on(event, handler) {
156
+ try {
157
+ // Add to local listeners map
158
+ if (!this.listeners.has(event)) {
159
+ this.listeners.set(event, new Set());
160
+ }
161
+ this.listeners.get(event).add(handler);
162
+ // Subscribe to Redis channel if this is the first listener
163
+ if (this.listeners.get(event).size === 1) {
164
+ this.subscribeToEvent(event);
165
+ }
166
+ if (this.config.environment.isDevelopment) {
167
+ console.log(`📥 [AppKit] Redis listener added for: ${event} (total: ${this.listeners.get(event).size})`);
168
+ }
169
+ }
170
+ catch (error) {
171
+ console.error(`[AppKit] Redis on error for event "${event}":`, error.message);
172
+ }
173
+ }
174
+ /**
175
+ * Adds one-time event listener with automatic cleanup
176
+ * @llm-rule WHEN: Listening to distributed events that should only fire once
177
+ * @llm-rule AVOID: Manual cleanup - this handles removal after first trigger
178
+ */
179
+ once(event, handler) {
180
+ try {
181
+ // Create wrapper that removes itself after first call
182
+ const onceWrapper = (data) => {
183
+ this.off(event, onceWrapper);
184
+ handler(data);
185
+ };
186
+ // Add the wrapper as a regular listener
187
+ this.on(event, onceWrapper);
188
+ if (this.config.environment.isDevelopment) {
189
+ console.log(`📥 [AppKit] Redis once listener added for: ${event}`);
190
+ }
191
+ }
192
+ catch (error) {
193
+ console.error(`[AppKit] Redis once error for event "${event}":`, error.message);
194
+ }
195
+ }
196
+ /**
197
+ * Removes event listener(s) with Redis unsubscribe management
198
+ * @llm-rule WHEN: Cleaning up distributed event listeners
199
+ * @llm-rule AVOID: Manual Redis unsubscribe - this handles cleanup automatically
200
+ */
201
+ off(event, handler) {
202
+ try {
203
+ const eventListeners = this.listeners.get(event);
204
+ if (!eventListeners)
205
+ return;
206
+ if (handler) {
207
+ // Remove specific handler
208
+ eventListeners.delete(handler);
209
+ // Unsubscribe from Redis if no more listeners
210
+ if (eventListeners.size === 0) {
211
+ this.listeners.delete(event);
212
+ this.unsubscribeFromEvent(event);
213
+ }
214
+ }
215
+ else {
216
+ // Remove all handlers for event
217
+ const count = eventListeners.size;
218
+ this.listeners.delete(event);
219
+ this.unsubscribeFromEvent(event);
220
+ if (this.config.environment.isDevelopment && count > 0) {
221
+ console.log(`📤 [AppKit] Redis removed ${count} listeners for: ${event}`);
222
+ }
223
+ }
224
+ }
225
+ catch (error) {
226
+ console.error(`[AppKit] Redis off error for event "${event}":`, error.message);
227
+ }
228
+ }
229
+ /**
230
+ * Gets current event listeners for debugging
231
+ * @llm-rule WHEN: Debugging distributed event listeners
232
+ * @llm-rule AVOID: Using for business logic - this is for debugging only
233
+ */
234
+ getListeners(event) {
235
+ if (event) {
236
+ const listeners = this.listeners.get(event);
237
+ return {
238
+ count: listeners ? listeners.size : 0,
239
+ subscribed: this.listeners.has(event),
240
+ channel: this.buildChannelName(event),
241
+ };
242
+ }
243
+ // Get all events with listeners
244
+ const events = Array.from(this.listeners.entries()).map(([eventName, handlers]) => ({
245
+ event: eventName,
246
+ count: handlers.size,
247
+ channel: this.buildChannelName(eventName),
248
+ }));
249
+ return {
250
+ totalEvents: events.length,
251
+ totalListeners: events.reduce((sum, event) => sum + event.count, 0),
252
+ connected: this.connected,
253
+ events,
254
+ };
255
+ }
256
+ /**
257
+ * Disconnects Redis strategy gracefully
258
+ * @llm-rule WHEN: App shutdown or event cleanup
259
+ * @llm-rule AVOID: Abrupt disconnection - graceful shutdown prevents connection issues
260
+ */
261
+ async disconnect() {
262
+ if (!this.connected)
263
+ return;
264
+ try {
265
+ // Clear all listeners
266
+ this.listeners.clear();
267
+ this.patternListeners.clear();
268
+ // Disconnect Redis clients
269
+ const disconnectPromises = [];
270
+ if (this.publisher) {
271
+ disconnectPromises.push(this.publisher.quit());
272
+ }
273
+ if (this.subscriber) {
274
+ disconnectPromises.push(this.subscriber.quit());
275
+ }
276
+ await Promise.all(disconnectPromises);
277
+ this.connected = false;
278
+ this.publisher = null;
279
+ this.subscriber = null;
280
+ if (this.config.environment.isDevelopment) {
281
+ console.log(`👋 [AppKit] Redis event strategy disconnected (namespace: ${this.namespace})`);
282
+ }
283
+ }
284
+ catch (error) {
285
+ console.error(`[AppKit] Redis disconnect error:`, error.message);
286
+ // Force close if graceful quit fails
287
+ if (this.publisher)
288
+ this.publisher.disconnect();
289
+ if (this.subscriber)
290
+ this.subscriber.disconnect();
291
+ this.publisher = null;
292
+ this.subscriber = null;
293
+ }
294
+ }
295
+ // Private helper methods
296
+ /**
297
+ * Builds Redis channel name with prefix and namespace
298
+ */
299
+ buildChannelName(event) {
300
+ const prefix = this.config.redis?.keyPrefix || 'events';
301
+ return `${prefix}:${this.namespace}:${event}`;
302
+ }
303
+ /**
304
+ * Serializes message data for Redis transmission
305
+ */
306
+ serializeMessage(data) {
307
+ try {
308
+ return JSON.stringify({
309
+ data,
310
+ timestamp: new Date().toISOString(),
311
+ namespace: this.namespace,
312
+ });
313
+ }
314
+ catch (error) {
315
+ throw new Error(`Failed to serialize event data: ${error.message}`);
316
+ }
317
+ }
318
+ /**
319
+ * Deserializes message data from Redis
320
+ */
321
+ deserializeMessage(message) {
322
+ try {
323
+ const parsed = JSON.parse(message);
324
+ return parsed.data;
325
+ }
326
+ catch (error) {
327
+ console.error('Failed to deserialize Redis message:', error);
328
+ return message; // Return raw message as fallback
329
+ }
330
+ }
331
+ /**
332
+ * Subscribes to Redis channel for specific event
333
+ */
334
+ async subscribeToEvent(event) {
335
+ if (!this.connected || !this.subscriber)
336
+ return;
337
+ try {
338
+ const channel = this.buildChannelName(event);
339
+ // Subscribe to Redis channel
340
+ await this.subscriber.subscribe(channel, (message) => {
341
+ this.handleRedisMessage(event, message);
342
+ });
343
+ if (this.config.environment.isDevelopment) {
344
+ console.log(`🔗 [AppKit] Redis subscribed to: ${channel}`);
345
+ }
346
+ }
347
+ catch (error) {
348
+ console.error(`[AppKit] Redis subscribe error for event "${event}":`, error.message);
349
+ }
350
+ }
351
+ /**
352
+ * Unsubscribes from Redis channel for specific event
353
+ */
354
+ async unsubscribeFromEvent(event) {
355
+ if (!this.connected || !this.subscriber)
356
+ return;
357
+ try {
358
+ const channel = this.buildChannelName(event);
359
+ // Unsubscribe from Redis channel
360
+ await this.subscriber.unsubscribe(channel);
361
+ if (this.config.environment.isDevelopment) {
362
+ console.log(`🔓 [AppKit] Redis unsubscribed from: ${channel}`);
363
+ }
364
+ }
365
+ catch (error) {
366
+ console.error(`[AppKit] Redis unsubscribe error for event "${event}":`, error.message);
367
+ }
368
+ }
369
+ /**
370
+ * Handles incoming Redis messages and routes to listeners
371
+ */
372
+ handleRedisMessage(event, message) {
373
+ try {
374
+ // Deserialize message
375
+ const data = this.deserializeMessage(message);
376
+ // Get listeners for this event
377
+ const eventListeners = this.listeners.get(event);
378
+ if (!eventListeners || eventListeners.size === 0)
379
+ return;
380
+ // Call all listeners
381
+ for (const handler of eventListeners) {
382
+ try {
383
+ const result = handler(data);
384
+ if (result && typeof result.then === 'function') {
385
+ result.catch((error) => {
386
+ console.error(`Redis event handler error for "${event}":`, error.message);
387
+ });
388
+ }
389
+ }
390
+ catch (error) {
391
+ console.error(`Redis event handler error for "${event}":`, error.message);
392
+ }
393
+ }
394
+ if (this.config.environment.isDevelopment) {
395
+ console.log(`📨 [AppKit] Redis message received: ${event} (${eventListeners.size} handlers)`);
396
+ }
397
+ }
398
+ catch (error) {
399
+ console.error(`[AppKit] Redis message handling error:`, error.message);
400
+ }
401
+ }
402
+ /**
403
+ * Gets Redis connection statistics
404
+ */
405
+ getConnectionInfo() {
406
+ const redisConfig = this.config.redis;
407
+ const subscriptions = Array.from(this.listeners.keys());
408
+ const totalListeners = Array.from(this.listeners.values())
409
+ .reduce((sum, listeners) => sum + listeners.size, 0);
410
+ return {
411
+ connected: this.connected,
412
+ url: this.maskUrl(redisConfig.url),
413
+ namespace: this.namespace,
414
+ totalSubscriptions: subscriptions.length,
415
+ totalListeners,
416
+ };
417
+ }
418
+ /**
419
+ * Masks sensitive parts of Redis URL for logging
420
+ */
421
+ maskUrl(url) {
422
+ try {
423
+ const parsed = new URL(url);
424
+ if (parsed.password) {
425
+ parsed.password = '***';
426
+ }
427
+ return parsed.toString();
428
+ }
429
+ catch {
430
+ return 'redis://***';
431
+ }
432
+ }
433
+ }
434
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/event/strategies/redis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @bloomneo/appkit - Ultra-minimal, tree-shakable Node.js application toolkit
3
+ *
4
+ * This file provides direct access to individual module entry points for optimal tree-shaking.
5
+ * Import only what you need - unused code will be automatically eliminated by modern bundlers.
6
+ *
7
+ * @module @bloomneo/appkit
8
+ * @file src/index.ts
9
+ *
10
+ * @example
11
+ * // ✅ Perfect tree-shaking - only specific modules bundled
12
+ * import { authClass } from '@bloomneo/appkit/auth';
13
+ * import { databaseClass } from '@bloomneo/appkit/database';
14
+ *
15
+ * // ✅ Also tree-shakable - but imports main index
16
+ * import { authClass, databaseClass } from '@bloomneo/appkit';
17
+ *
18
+ * // ❌ Avoid - imports everything
19
+ * import * as appkit from '@bloomneo/appkit';
20
+ */
21
+ /**
22
+ * Library name
23
+ * @type {string}
24
+ */
25
+ export declare const NAME = "@bloomneo/appkit";
26
+ /**
27
+ * Supported Node.js version
28
+ * @type {string}
29
+ */
30
+ export declare const NODE_VERSION = ">=18.0.0";
31
+ /**
32
+ * Re-export main entry functions for convenience (tree-shakable)
33
+ * Each import only loads the specific module needed
34
+ *
35
+ * Pattern: {folderName}Class.get() → creates {folderName} instance
36
+ */
37
+ export { authClass } from './auth/index.js';
38
+ export { configClass } from './config/index.js';
39
+ export { securityClass } from './security/index.js';
40
+ export { databaseClass } from './database/index.js';
41
+ export { cacheClass } from './cache/index.js';
42
+ export { emailClass } from './email/index.js';
43
+ export { eventClass } from './event/index.js';
44
+ export { errorClass } from './error/index.js';
45
+ export { loggerClass } from './logger/index.js';
46
+ export { queueClass } from './queue/index.js';
47
+ export { storageClass } from './storage/index.js';
48
+ export { utilClass } from './util/index.js';
49
+ /**
50
+ * Quick health check for the library
51
+ * @returns {Object} Basic library information
52
+ */
53
+ export declare function getLibraryInfo(): {
54
+ name: string;
55
+ nodeVersion: string;
56
+ timestamp: string;
57
+ };
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;;GAGG;AACH,eAAO,MAAM,IAAI,qBAAqB,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,cAAc;;;;EAM7B"}
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @bloomneo/appkit - Ultra-minimal, tree-shakable Node.js application toolkit
3
+ *
4
+ * This file provides direct access to individual module entry points for optimal tree-shaking.
5
+ * Import only what you need - unused code will be automatically eliminated by modern bundlers.
6
+ *
7
+ * @module @bloomneo/appkit
8
+ * @file src/index.ts
9
+ *
10
+ * @example
11
+ * // ✅ Perfect tree-shaking - only specific modules bundled
12
+ * import { authClass } from '@bloomneo/appkit/auth';
13
+ * import { databaseClass } from '@bloomneo/appkit/database';
14
+ *
15
+ * // ✅ Also tree-shakable - but imports main index
16
+ * import { authClass, databaseClass } from '@bloomneo/appkit';
17
+ *
18
+ * // ❌ Avoid - imports everything
19
+ * import * as appkit from '@bloomneo/appkit';
20
+ */
21
+ /**
22
+ * Library name
23
+ * @type {string}
24
+ */
25
+ export const NAME = '@bloomneo/appkit';
26
+ /**
27
+ * Supported Node.js version
28
+ * @type {string}
29
+ */
30
+ export const NODE_VERSION = '>=18.0.0';
31
+ /**
32
+ * Re-export main entry functions for convenience (tree-shakable)
33
+ * Each import only loads the specific module needed
34
+ *
35
+ * Pattern: {folderName}Class.get() → creates {folderName} instance
36
+ */
37
+ // Authentication
38
+ export { authClass } from './auth/index.js';
39
+ // Configuration
40
+ export { configClass } from './config/index.js';
41
+ // Security
42
+ export { securityClass } from './security/index.js';
43
+ // Database
44
+ export { databaseClass } from './database/index.js';
45
+ // Caching
46
+ export { cacheClass } from './cache/index.js';
47
+ // Email
48
+ export { emailClass } from './email/index.js';
49
+ // Events
50
+ export { eventClass } from './event/index.js';
51
+ // Error handling
52
+ export { errorClass } from './error/index.js';
53
+ // Logging
54
+ export { loggerClass } from './logger/index.js';
55
+ // Queuing
56
+ export { queueClass } from './queue/index.js';
57
+ // Storage
58
+ export { storageClass } from './storage/index.js';
59
+ // Utilities
60
+ export { utilClass } from './util/index.js';
61
+ /**
62
+ * Quick health check for the library
63
+ * @returns {Object} Basic library information
64
+ */
65
+ export function getLibraryInfo() {
66
+ return {
67
+ name: NAME,
68
+ nodeVersion: NODE_VERSION,
69
+ timestamp: new Date().toISOString(),
70
+ };
71
+ }
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEvC;;;;;GAKG;AAEH,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,gBAAgB;AAChB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,iBAAiB;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,YAAY;AACZ,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,YAAY;QACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Smart defaults with direct environment access and auto transport detection
3
+ * @module @bloomneo/appkit/logger
4
+ * @file src/logger/defaults.ts
5
+ *
6
+ * @llm-rule WHEN: App startup - need production-ready logging configuration
7
+ * @llm-rule AVOID: Calling multiple times - expensive environment parsing, cache results
8
+ * @llm-rule NOTE: Called once at startup, cached globally for performance like auth module
9
+ * @llm-rule NOTE: Now includes visual error configuration for enhanced developer experience
10
+ */
11
+ export interface LoggingConfig {
12
+ level: 'debug' | 'info' | 'warn' | 'error';
13
+ scope: 'minimal' | 'full';
14
+ minimal: boolean;
15
+ transports: {
16
+ console: boolean;
17
+ file: boolean;
18
+ database: boolean;
19
+ http: boolean;
20
+ webhook: boolean;
21
+ };
22
+ console: {
23
+ colorize: boolean;
24
+ timestamps: boolean;
25
+ prettyPrint: boolean;
26
+ };
27
+ file: {
28
+ dir: string;
29
+ filename: string;
30
+ maxSize: number;
31
+ retentionDays: number;
32
+ };
33
+ database: {
34
+ url: string | null;
35
+ table: string;
36
+ batchSize: number;
37
+ };
38
+ http: {
39
+ url: string | null;
40
+ batchSize: number;
41
+ timeout: number;
42
+ };
43
+ webhook: {
44
+ url: string | null;
45
+ level: 'debug' | 'info' | 'warn' | 'error';
46
+ rateLimit: number;
47
+ };
48
+ service: {
49
+ name: string;
50
+ version: string;
51
+ environment: string;
52
+ };
53
+ }
54
+ /**
55
+ * Get smart defaults using direct VOILA_LOGGER_* environment access
56
+ * @llm-rule WHEN: App startup to get production-ready logging configuration
57
+ * @llm-rule AVOID: Calling repeatedly - validates environment each time, expensive operation
58
+ * @llm-rule NOTE: Called once at startup, cached globally for performance
59
+ */
60
+ export declare function getSmartDefaults(): LoggingConfig;
61
+ /**
62
+ * Validate environment variables (like auth module validation)
63
+ * @llm-rule WHEN: App startup to catch configuration errors early
64
+ * @llm-rule AVOID: Skipping validation - invalid config causes silent failures
65
+ */
66
+ export declare function validateEnvironment(): void;
67
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/logger/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IAGjB,UAAU,EAAE;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,OAAO,CAAC;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,IAAI,EAAE,OAAO,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IAGF,OAAO,EAAE;QACP,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,EAAE,OAAO,CAAC;QACpB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;IAEF,IAAI,EAAE;QACJ,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF,IAAI,EAAE;QACJ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;QAC3C,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAGF,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAkEhD;AAiED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CA4C1C"}