@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,490 @@
1
+ /**
2
+ * Ultra-simple database API with org/tenant support and smart connection management
3
+ * @module @bloomneo/appkit/database
4
+ * @file src/database/index.ts
5
+ *
6
+ * @llm-rule WHEN: ALWAYS add tenant_id text field to ALL tables (nullable for future compatibility)
7
+ * @llm-rule NOTE: tenant_id = null (single tenant) or "team-1" (multi-tenant)
8
+ * @llm-rule VARIABLE: const db = await databaseClass.get() - user's data (single or tenant-filtered)
9
+ * @llm-rule VARIABLE: const dbTenants = await databaseClass.getTenants() - all tenants (admin access)
10
+ * @llm-rule VARIABLE: const {orgName}Db = await databaseClass.org('{orgName}').get() - org-specific data
11
+ * @llm-rule VARIABLE: const {orgName}DbTenants = await databaseClass.org('{orgName}').getTenants() - all tenants in org
12
+ */
13
+ import fs from 'fs';
14
+ import { PrismaAdapter } from './adapters/prisma.js';
15
+ import { MongooseAdapter } from './adapters/mongoose.js';
16
+ // Global instances cache for performance
17
+ const connections = new Map();
18
+ let envWatcher = null;
19
+ /**
20
+ * Environment file watcher for hot reload
21
+ */
22
+ function setupEnvWatcher() {
23
+ if (envWatcher)
24
+ return;
25
+ try {
26
+ envWatcher = fs.watch('.env', (eventType) => {
27
+ if (eventType === 'change') {
28
+ // Clear require cache and reload
29
+ delete require.cache[require.resolve('dotenv')];
30
+ require('dotenv').config();
31
+ // Clear connection cache to use new URLs
32
+ connections.clear();
33
+ if (process.env.NODE_ENV === 'development') {
34
+ console.log('🔄 [AppKit] .env file reloaded, connections reset');
35
+ }
36
+ }
37
+ });
38
+ }
39
+ catch (error) {
40
+ // .env file doesn't exist or can't be watched - continue without watching
41
+ }
42
+ }
43
+ /**
44
+ * Detect organization from request context
45
+ */
46
+ function detectOrg(req) {
47
+ if (!req)
48
+ return null;
49
+ return (req.headers?.['x-org-id'] ||
50
+ req.user?.org_id ||
51
+ req.params?.orgId ||
52
+ req.query?.org ||
53
+ extractFromSubdomain(req, 'org') ||
54
+ null);
55
+ }
56
+ /**
57
+ * Detect tenant from request context
58
+ */
59
+ function detectTenant(req) {
60
+ if (!req)
61
+ return null;
62
+ if (!process.env.VOILA_DB_TENANT)
63
+ return null;
64
+ return (req.headers?.['x-tenant-id'] ||
65
+ req.user?.tenant_id ||
66
+ req.params?.tenantId ||
67
+ req.query?.tenant ||
68
+ extractFromSubdomain(req, 'tenant') ||
69
+ null);
70
+ }
71
+ /**
72
+ * Extract org/tenant from subdomain
73
+ */
74
+ function extractFromSubdomain(req, type) {
75
+ try {
76
+ const host = req.headers?.host || req.hostname;
77
+ if (!host)
78
+ return null;
79
+ const parts = host.split('.');
80
+ if (parts.length >= 3) {
81
+ const subdomain = parts[0];
82
+ // Skip common subdomains
83
+ if (!['www', 'api', 'admin', 'app'].includes(subdomain)) {
84
+ return subdomain;
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ /**
94
+ * Auto-detect database adapter from URL
95
+ */
96
+ function detectAdapter(url) {
97
+ if (url.includes('postgresql') || url.includes('postgres')) {
98
+ return 'prisma';
99
+ }
100
+ if (url.includes('mongodb')) {
101
+ return 'mongoose';
102
+ }
103
+ return 'prisma'; // Default fallback
104
+ }
105
+ /**
106
+ * Get database URL for organization
107
+ */
108
+ function getOrgUrl(orgId) {
109
+ if (!orgId)
110
+ return process.env.DATABASE_URL || '';
111
+ // Check for specific org URL
112
+ const orgUrl = process.env[`ORG_${orgId.toUpperCase()}`];
113
+ if (orgUrl)
114
+ return orgUrl;
115
+ // Check for pattern in base URL
116
+ const baseUrl = process.env.DATABASE_URL;
117
+ if (baseUrl?.includes('{org}')) {
118
+ return baseUrl.replace('{org}', orgId);
119
+ }
120
+ return baseUrl || '';
121
+ }
122
+ /**
123
+ * Create database client with caching
124
+ */
125
+ async function createClient(url, tenantId = null, orgId = null) {
126
+ const cacheKey = `${url}_${tenantId || 'null'}_${orgId || 'null'}`;
127
+ if (connections.has(cacheKey)) {
128
+ return connections.get(cacheKey);
129
+ }
130
+ try {
131
+ // Detect and create adapter
132
+ const adapterType = detectAdapter(url);
133
+ const adapter = adapterType === 'mongoose' ? new MongooseAdapter({ url }) : new PrismaAdapter({ url });
134
+ // Create client
135
+ let client = await adapter.createClient({ url });
136
+ // Apply tenant middleware if needed
137
+ if (tenantId && adapter.applyTenantMiddleware) {
138
+ client = await adapter.applyTenantMiddleware(client, tenantId, {
139
+ fieldName: 'tenant_id',
140
+ orgId
141
+ });
142
+ }
143
+ // Add metadata
144
+ client._appKit = true;
145
+ client._orgId = orgId || undefined;
146
+ client._tenantId = tenantId || undefined;
147
+ client._url = url;
148
+ // Cache connection
149
+ connections.set(cacheKey, client);
150
+ return client;
151
+ }
152
+ catch (error) {
153
+ throw new Error(`Failed to create database connection: ${error.message}`);
154
+ }
155
+ }
156
+ /**
157
+ * Organization database builder
158
+ */
159
+ class OrgDatabase {
160
+ orgId;
161
+ constructor(orgId) {
162
+ this.orgId = orgId;
163
+ }
164
+ /**
165
+ * Get organization database (tenant-filtered if tenant mode enabled)
166
+ */
167
+ async get(req = null) {
168
+ const tenantId = detectTenant(req);
169
+ const url = getOrgUrl(this.orgId);
170
+ if (!url) {
171
+ throw new Error(`No database URL found for organization '${this.orgId}'`);
172
+ }
173
+ return await createClient(url, tenantId, this.orgId);
174
+ }
175
+ /**
176
+ * Get all tenants in organization (admin access)
177
+ */
178
+ async getTenants(req = null) {
179
+ const url = getOrgUrl(this.orgId);
180
+ if (!url) {
181
+ throw new Error(`No database URL found for organization '${this.orgId}'`);
182
+ }
183
+ // No tenant filtering - admin sees all data
184
+ return await createClient(url, null, this.orgId);
185
+ }
186
+ }
187
+ /**
188
+ * Main database API - ultra-simple like auth module
189
+ */
190
+ export const databaseClass = {
191
+ /**
192
+ * Get database client - main function that handles all contexts
193
+ * @param {Object} [req] - Request object for context detection
194
+ * @returns {Promise<DatabaseClientUnion>} Database client
195
+ */
196
+ async get(req = null) {
197
+ // Setup env watching on first use
198
+ setupEnvWatcher();
199
+ // Detect context
200
+ const orgId = detectOrg(req);
201
+ const tenantId = detectTenant(req);
202
+ // Get appropriate URL
203
+ const url = getOrgUrl(orgId || undefined) || process.env.DATABASE_URL;
204
+ if (!url) {
205
+ throw new Error('Database URL required. Set DATABASE_URL environment variable');
206
+ }
207
+ return await createClient(url, tenantId, orgId);
208
+ },
209
+ /**
210
+ * Get all tenants data (admin access - no tenant filtering)
211
+ * @param {Object} [req] - Request object for org context
212
+ * @returns {Promise<DatabaseClientUnion>} Database client with no tenant filtering
213
+ */
214
+ async getTenants(req = null) {
215
+ setupEnvWatcher();
216
+ const orgId = detectOrg(req);
217
+ const url = getOrgUrl(orgId || undefined) || process.env.DATABASE_URL;
218
+ if (!url) {
219
+ throw new Error('Database URL required. Set DATABASE_URL environment variable');
220
+ }
221
+ // No tenant filtering - admin sees all data
222
+ return await createClient(url, null, orgId);
223
+ },
224
+ /**
225
+ * Get organization-specific database
226
+ * @param {string} orgId - Organization ID
227
+ * @returns {OrgDatabase} Organization database instance
228
+ */
229
+ org(orgId) {
230
+ if (!orgId || typeof orgId !== 'string') {
231
+ throw new Error('Organization ID is required and must be a string');
232
+ }
233
+ return new OrgDatabase(orgId);
234
+ },
235
+ /**
236
+ * Health check for database connections
237
+ * @returns {Promise<Object>} Health status
238
+ */
239
+ async health() {
240
+ try {
241
+ const db = await this.get();
242
+ // Simple connectivity test
243
+ if (db.$queryRaw) {
244
+ // Prisma client
245
+ await db.$queryRaw `SELECT 1`;
246
+ }
247
+ else if (db.db) {
248
+ // Mongoose connection
249
+ await db.db.admin().ping();
250
+ }
251
+ return {
252
+ healthy: true,
253
+ connections: connections.size,
254
+ timestamp: new Date().toISOString(),
255
+ };
256
+ }
257
+ catch (error) {
258
+ return {
259
+ healthy: false,
260
+ error: error.message,
261
+ connections: connections.size,
262
+ timestamp: new Date().toISOString(),
263
+ };
264
+ }
265
+ },
266
+ /**
267
+ * List tenants in current context
268
+ * @param {Object} [req] - Request object for org context
269
+ * @returns {Promise<string[]>} Array of tenant IDs
270
+ */
271
+ async list(req = null) {
272
+ try {
273
+ const db = await this.getTenants(req);
274
+ return await this._getDistinctTenantIds(db);
275
+ }
276
+ catch (error) {
277
+ throw new Error(`Failed to list tenants: ${error.message}`);
278
+ }
279
+ },
280
+ /**
281
+ * Check if tenant exists
282
+ * @param {string} tenantId - Tenant ID
283
+ * @param {Object} [req] - Request object for org context
284
+ * @returns {Promise<boolean>} Whether tenant exists
285
+ */
286
+ async exists(tenantId, req = null) {
287
+ if (!tenantId)
288
+ return false;
289
+ try {
290
+ const db = await this.getTenants(req);
291
+ return await this._tenantHasData(db, tenantId);
292
+ }
293
+ catch {
294
+ return false;
295
+ }
296
+ },
297
+ /**
298
+ * Create tenant (registers tenant for future use)
299
+ * @param {string} tenantId - Tenant ID
300
+ * @param {Object} [req] - Request object for org context
301
+ * @returns {Promise<void>}
302
+ */
303
+ async create(tenantId, req = null) {
304
+ if (!tenantId || typeof tenantId !== 'string') {
305
+ throw new Error('Tenant ID is required and must be a string');
306
+ }
307
+ if (!/^[a-zA-Z0-9_-]+$/.test(tenantId)) {
308
+ throw new Error('Invalid tenant ID format. Use alphanumeric characters, underscores, and hyphens only');
309
+ }
310
+ // For row-level strategy, tenant creation is implicit
311
+ // The tenant exists when first record with tenant_id is created
312
+ // This method can be used to validate the tenant ID format
313
+ },
314
+ /**
315
+ * Delete all tenant data (requires confirmation)
316
+ * @param {string} tenantId - Tenant ID
317
+ * @param {Object} options - Options object
318
+ * @param {boolean} options.confirm - Confirmation flag (required)
319
+ * @param {Object} [req] - Request object for org context
320
+ * @returns {Promise<void>}
321
+ */
322
+ async delete(tenantId, options, req = null) {
323
+ if (!tenantId) {
324
+ throw new Error('Tenant ID is required');
325
+ }
326
+ if (!options?.confirm) {
327
+ throw new Error('Tenant deletion requires explicit confirmation. Pass { confirm: true }');
328
+ }
329
+ const db = await this.getTenants(req);
330
+ await this._deleteAllTenantData(db, tenantId);
331
+ // Clear cached connections for this tenant
332
+ this._clearTenantCache(tenantId);
333
+ },
334
+ /**
335
+ * Disconnect all connections and cleanup
336
+ * @returns {Promise<void>}
337
+ */
338
+ async disconnect() {
339
+ const disconnectPromises = [];
340
+ for (const [key, connection] of connections) {
341
+ disconnectPromises.push(this._closeConnection(connection).catch((error) => console.warn(`Error disconnecting ${key}:`, error.message)));
342
+ }
343
+ await Promise.all(disconnectPromises);
344
+ connections.clear();
345
+ if (envWatcher) {
346
+ envWatcher.close();
347
+ envWatcher = null;
348
+ }
349
+ },
350
+ // Private helper methods
351
+ /**
352
+ * Get distinct tenant IDs from database
353
+ * @private
354
+ */
355
+ async _getDistinctTenantIds(client) {
356
+ const tenantIds = new Set();
357
+ try {
358
+ if (client.$queryRaw) {
359
+ // Prisma client - find models with tenant_id field
360
+ const models = Object.keys(client).filter((key) => !key.startsWith('$') &&
361
+ !key.startsWith('_') &&
362
+ typeof client[key] === 'object' &&
363
+ typeof client[key].findMany === 'function');
364
+ for (const modelName of models) {
365
+ try {
366
+ const records = await client[modelName].findMany({
367
+ select: { tenant_id: true },
368
+ distinct: ['tenant_id'],
369
+ where: { tenant_id: { not: null } },
370
+ });
371
+ records.forEach((record) => {
372
+ if (record.tenant_id)
373
+ tenantIds.add(record.tenant_id);
374
+ });
375
+ }
376
+ catch {
377
+ // Model might not have tenant_id field
378
+ continue;
379
+ }
380
+ }
381
+ }
382
+ return Array.from(tenantIds).sort();
383
+ }
384
+ catch (error) {
385
+ throw new Error(`Failed to get tenant IDs: ${error.message}`);
386
+ }
387
+ },
388
+ /**
389
+ * Check if tenant has data
390
+ * @private
391
+ */
392
+ async _tenantHasData(client, tenantId) {
393
+ try {
394
+ if (client.$queryRaw) {
395
+ // Prisma client
396
+ const models = Object.keys(client).filter((key) => !key.startsWith('$') &&
397
+ !key.startsWith('_') &&
398
+ typeof client[key] === 'object' &&
399
+ typeof client[key].findFirst === 'function');
400
+ for (const modelName of models) {
401
+ try {
402
+ const record = await client[modelName].findFirst({
403
+ where: { tenant_id: tenantId },
404
+ });
405
+ if (record)
406
+ return true;
407
+ }
408
+ catch {
409
+ continue;
410
+ }
411
+ }
412
+ }
413
+ return false;
414
+ }
415
+ catch {
416
+ return false;
417
+ }
418
+ },
419
+ /**
420
+ * Delete all tenant data
421
+ * @private
422
+ */
423
+ async _deleteAllTenantData(client, tenantId) {
424
+ try {
425
+ if (client.$transaction) {
426
+ // Prisma client - use transaction for safety
427
+ const models = Object.keys(client).filter((key) => !key.startsWith('$') &&
428
+ !key.startsWith('_') &&
429
+ typeof client[key] === 'object' &&
430
+ typeof client[key].deleteMany === 'function');
431
+ const deleteOperations = [];
432
+ for (const modelName of models) {
433
+ try {
434
+ deleteOperations.push(client[modelName].deleteMany({
435
+ where: { tenant_id: tenantId },
436
+ }));
437
+ }
438
+ catch {
439
+ continue;
440
+ }
441
+ }
442
+ if (deleteOperations.length > 0) {
443
+ await client.$transaction(deleteOperations);
444
+ }
445
+ }
446
+ }
447
+ catch (error) {
448
+ throw new Error(`Failed to delete tenant data: ${error.message}`);
449
+ }
450
+ },
451
+ /**
452
+ * Clear tenant-specific cached connections
453
+ * @private
454
+ */
455
+ _clearTenantCache(tenantId) {
456
+ const keysToDelete = [];
457
+ for (const [key] of connections) {
458
+ if (key.includes(`_${tenantId}_`)) {
459
+ keysToDelete.push(key);
460
+ }
461
+ }
462
+ keysToDelete.forEach((key) => {
463
+ const connection = connections.get(key);
464
+ if (connection) {
465
+ this._closeConnection(connection);
466
+ }
467
+ connections.delete(key);
468
+ });
469
+ },
470
+ /**
471
+ * Close database connection
472
+ * @private
473
+ */
474
+ async _closeConnection(connection) {
475
+ try {
476
+ if (connection.$disconnect) {
477
+ await connection.$disconnect();
478
+ }
479
+ else if (connection.close) {
480
+ await connection.close();
481
+ }
482
+ }
483
+ catch {
484
+ // Ignore disconnect errors
485
+ }
486
+ },
487
+ };
488
+ // Default export for convenience
489
+ export default databaseClass;
490
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/database/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Smart defaults and environment validation for email with auto-strategy detection
3
+ * @module @bloomneo/appkit/email
4
+ * @file src/email/defaults.ts
5
+ *
6
+ * @llm-rule WHEN: App startup - need to configure email strategy and connection settings
7
+ * @llm-rule AVOID: Calling multiple times - expensive environment parsing, use lazy loading in get()
8
+ * @llm-rule NOTE: Called once at startup, cached globally for performance
9
+ * @llm-rule NOTE: Auto-detects Resend → SMTP → Console based on environment variables
10
+ */
11
+ export interface ResendConfig {
12
+ apiKey: string;
13
+ baseURL: string;
14
+ timeout: number;
15
+ }
16
+ export interface SmtpConfig {
17
+ host: string;
18
+ port: number;
19
+ secure: boolean;
20
+ auth: {
21
+ user: string;
22
+ pass: string;
23
+ };
24
+ timeout: number;
25
+ pool: boolean;
26
+ }
27
+ export interface ConsoleConfig {
28
+ colorize: boolean;
29
+ showPreview: boolean;
30
+ format: 'simple' | 'detailed';
31
+ }
32
+ export interface EmailConfig {
33
+ strategy: 'resend' | 'smtp' | 'console';
34
+ from: {
35
+ name: string;
36
+ email: string;
37
+ };
38
+ resend?: ResendConfig;
39
+ smtp?: SmtpConfig;
40
+ console?: ConsoleConfig;
41
+ environment: {
42
+ isDevelopment: boolean;
43
+ isProduction: boolean;
44
+ isTest: boolean;
45
+ nodeEnv: string;
46
+ };
47
+ }
48
+ /**
49
+ * Gets smart defaults using environment variables with auto-strategy detection
50
+ * @llm-rule WHEN: App startup to get production-ready email configuration
51
+ * @llm-rule AVOID: Calling repeatedly - expensive validation, cache the result
52
+ * @llm-rule NOTE: Auto-detects strategy: RESEND_API_KEY → Resend, SMTP_HOST → SMTP, default → Console
53
+ */
54
+ export declare function getSmartDefaults(): EmailConfig;
55
+ /**
56
+ * Gets email configuration summary for debugging and health checks
57
+ * @llm-rule WHEN: Debugging email configuration or building health check endpoints
58
+ * @llm-rule AVOID: Exposing sensitive API keys or passwords - this only shows safe info
59
+ */
60
+ export declare function getConfigSummary(): {
61
+ strategy: string;
62
+ fromName: string;
63
+ fromEmail: string;
64
+ resendConfigured: boolean;
65
+ smtpConfigured: boolean;
66
+ environment: string;
67
+ };
68
+ /**
69
+ * Validates that required email configuration is present for production
70
+ * @llm-rule WHEN: App startup validation for production deployments
71
+ * @llm-rule AVOID: Skipping validation - missing email config causes runtime issues
72
+ */
73
+ export declare function validateProductionRequirements(): void;
74
+ /**
75
+ * Validates startup configuration and throws detailed errors
76
+ * @llm-rule WHEN: App startup to ensure email configuration is valid before starting
77
+ * @llm-rule AVOID: Skipping validation - catches config issues early
78
+ * @llm-rule NOTE: Comprehensive validation for production readiness
79
+ */
80
+ export declare function validateStartupConfiguration(): {
81
+ strategy: string;
82
+ warnings: string[];
83
+ errors: string[];
84
+ ready: boolean;
85
+ };
86
+ /**
87
+ * Performs comprehensive email system health check
88
+ * @llm-rule WHEN: Health check endpoints or monitoring systems
89
+ * @llm-rule AVOID: Running in critical path - this is for monitoring only
90
+ * @llm-rule NOTE: Returns detailed health status without exposing sensitive data
91
+ */
92
+ export declare function performHealthCheck(): {
93
+ status: 'healthy' | 'warning' | 'error';
94
+ strategy: string;
95
+ configured: boolean;
96
+ issues: string[];
97
+ ready: boolean;
98
+ timestamp: string;
99
+ };
100
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/email/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACxC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE;QACX,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAwD9C;AAuOD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB,CAWA;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CA0BrD;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB,CAwEA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAsCA"}