@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,461 @@
1
+ /**
2
+ * S3-compatible storage strategy with automatic connection management and multi-provider support
3
+ * @module @bloomneo/appkit/storage
4
+ * @file src/storage/strategies/s3.ts
5
+ *
6
+ * @llm-rule WHEN: App has AWS_S3_BUCKET or S3_ENDPOINT env vars for distributed cloud storage
7
+ * @llm-rule AVOID: Manual S3 setup - this handles AWS, Wasabi, MinIO, DigitalOcean Spaces automatically
8
+ * @llm-rule NOTE: Production-ready with retry logic, signed URLs, CDN support, automatic MIME detection
9
+ */
10
+ /**
11
+ * S3-compatible storage strategy with multi-provider support and reliability features
12
+ */
13
+ export class S3Strategy {
14
+ config;
15
+ s3Client = null;
16
+ connected = false;
17
+ bucket;
18
+ region;
19
+ endpoint;
20
+ cdnUrl;
21
+ /**
22
+ * Creates S3 strategy with direct environment access (like auth pattern)
23
+ * @llm-rule WHEN: Storage initialization with S3-compatible environment variables detected
24
+ * @llm-rule AVOID: Manual S3 configuration - environment detection handles AWS/Wasabi/MinIO
25
+ */
26
+ constructor(config) {
27
+ this.config = config;
28
+ if (!config.s3) {
29
+ throw new Error('S3 storage configuration missing');
30
+ }
31
+ this.bucket = config.s3.bucket;
32
+ this.region = config.s3.region;
33
+ this.endpoint = config.s3.endpoint;
34
+ this.cdnUrl = config.s3.cdnUrl;
35
+ }
36
+ /**
37
+ * Connects to S3-compatible service with automatic retry and provider detection
38
+ * @llm-rule WHEN: Storage initialization or reconnection after failure
39
+ * @llm-rule AVOID: Manual S3 client setup - this handles all provider configurations
40
+ */
41
+ async connect() {
42
+ if (this.connected)
43
+ return;
44
+ try {
45
+ // Dynamic import for S3 client
46
+ const { S3Client } = await import('@aws-sdk/client-s3');
47
+ const s3Config = this.config.s3;
48
+ // Build S3 client configuration
49
+ const clientConfig = {
50
+ region: this.region,
51
+ credentials: {
52
+ accessKeyId: s3Config.accessKeyId,
53
+ secretAccessKey: s3Config.secretAccessKey,
54
+ },
55
+ maxAttempts: 3, // Built-in retry logic
56
+ };
57
+ // Configure for S3-compatible services (Wasabi, MinIO, etc.)
58
+ if (this.endpoint) {
59
+ clientConfig.endpoint = this.endpoint;
60
+ clientConfig.forcePathStyle = s3Config.forcePathStyle;
61
+ }
62
+ // Create S3 client
63
+ this.s3Client = new S3Client(clientConfig);
64
+ // Test connection by checking if bucket exists
65
+ await this.testConnection();
66
+ this.connected = true;
67
+ if (this.config.environment.isDevelopment) {
68
+ const provider = this.detectProvider();
69
+ console.log(`✅ [AppKit] S3 storage connected (provider: ${provider}, bucket: ${this.bucket})`);
70
+ }
71
+ }
72
+ catch (error) {
73
+ this.connected = false;
74
+ this.s3Client = null;
75
+ throw new Error(`S3 storage connection failed: ${error.message}`);
76
+ }
77
+ }
78
+ /**
79
+ * Tests S3 connection by checking bucket access
80
+ */
81
+ async testConnection() {
82
+ const { HeadBucketCommand } = await import('@aws-sdk/client-s3');
83
+ try {
84
+ await this.s3Client.send(new HeadBucketCommand({ Bucket: this.bucket }));
85
+ }
86
+ catch (error) {
87
+ if (error.name === 'NotFound') {
88
+ throw new Error(`S3 bucket not found: ${this.bucket}`);
89
+ }
90
+ if (error.name === 'Forbidden') {
91
+ throw new Error(`S3 bucket access denied: ${this.bucket}`);
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+ /**
97
+ * Detects S3 provider from configuration
98
+ */
99
+ detectProvider() {
100
+ if (!this.endpoint)
101
+ return 'AWS S3';
102
+ const hostname = new URL(this.endpoint).hostname.toLowerCase();
103
+ if (hostname.includes('wasabi'))
104
+ return 'Wasabi';
105
+ if (hostname.includes('digitalocean'))
106
+ return 'DigitalOcean Spaces';
107
+ if (hostname.includes('minio') || hostname.includes('localhost'))
108
+ return 'MinIO';
109
+ if (hostname.includes('backblaze'))
110
+ return 'Backblaze B2';
111
+ return 'S3-Compatible';
112
+ }
113
+ /**
114
+ * Stores file to S3 with automatic content type detection and metadata
115
+ * @llm-rule WHEN: Uploading files to S3-compatible cloud storage
116
+ * @llm-rule AVOID: Manual S3 operations - this handles multipart uploads and metadata
117
+ */
118
+ async put(key, data, options) {
119
+ if (!this.connected || !this.s3Client) {
120
+ throw new Error('S3 storage not connected');
121
+ }
122
+ try {
123
+ const { PutObjectCommand } = await import('@aws-sdk/client-s3');
124
+ // Build S3 put parameters
125
+ const params = {
126
+ Bucket: this.bucket,
127
+ Key: key,
128
+ Body: data,
129
+ ContentType: options?.contentType || this.detectContentType(key, data),
130
+ };
131
+ // Add optional parameters
132
+ if (options?.cacheControl) {
133
+ params.CacheControl = options.cacheControl;
134
+ }
135
+ if (options?.expires) {
136
+ params.Expires = options.expires;
137
+ }
138
+ if (options?.metadata) {
139
+ params.Metadata = options.metadata;
140
+ }
141
+ // Execute upload
142
+ await this.s3Client.send(new PutObjectCommand(params));
143
+ if (this.config.environment.isDevelopment) {
144
+ console.log(`☁️ [AppKit] S3 file uploaded: ${key} (${data.length} bytes)`);
145
+ }
146
+ return key;
147
+ }
148
+ catch (error) {
149
+ throw new Error(`S3 upload failed: ${error.message}`);
150
+ }
151
+ }
152
+ /**
153
+ * Retrieves file from S3 with streaming support
154
+ * @llm-rule WHEN: Downloading files from S3-compatible storage
155
+ * @llm-rule AVOID: Manual S3 operations - this handles streaming and errors
156
+ */
157
+ async get(key) {
158
+ if (!this.connected || !this.s3Client) {
159
+ throw new Error('S3 storage not connected');
160
+ }
161
+ try {
162
+ const { GetObjectCommand } = await import('@aws-sdk/client-s3');
163
+ const params = {
164
+ Bucket: this.bucket,
165
+ Key: key,
166
+ };
167
+ const result = await this.s3Client.send(new GetObjectCommand(params));
168
+ if (!result.Body) {
169
+ throw new Error(`S3 object has no body: ${key}`);
170
+ }
171
+ // Convert stream to buffer
172
+ const buffer = await this.streamToBuffer(result.Body);
173
+ if (this.config.environment.isDevelopment) {
174
+ console.log(`☁️ [AppKit] S3 file downloaded: ${key} (${buffer.length} bytes)`);
175
+ }
176
+ return buffer;
177
+ }
178
+ catch (error) {
179
+ if (error.name === 'NoSuchKey') {
180
+ throw new Error(`File not found: ${key}`);
181
+ }
182
+ throw new Error(`S3 download failed: ${error.message}`);
183
+ }
184
+ }
185
+ /**
186
+ * Deletes file from S3 with confirmation
187
+ * @llm-rule WHEN: Removing files from S3-compatible storage
188
+ * @llm-rule AVOID: Silent failures - this confirms deletion success
189
+ */
190
+ async delete(key) {
191
+ if (!this.connected || !this.s3Client) {
192
+ console.error('S3 storage not connected');
193
+ return false;
194
+ }
195
+ try {
196
+ const { DeleteObjectCommand } = await import('@aws-sdk/client-s3');
197
+ const params = {
198
+ Bucket: this.bucket,
199
+ Key: key,
200
+ };
201
+ await this.s3Client.send(new DeleteObjectCommand(params));
202
+ if (this.config.environment.isDevelopment) {
203
+ console.log(`🗑️ [AppKit] S3 file deleted: ${key}`);
204
+ }
205
+ return true;
206
+ }
207
+ catch (error) {
208
+ console.error(`[AppKit] S3 delete error for "${key}":`, error.message);
209
+ return false;
210
+ }
211
+ }
212
+ /**
213
+ * Lists files with prefix filtering and pagination
214
+ * @llm-rule WHEN: Browsing S3 files or implementing file managers
215
+ * @llm-rule AVOID: Loading all objects - use prefix filtering and pagination
216
+ */
217
+ async list(prefix = '') {
218
+ if (!this.connected || !this.s3Client) {
219
+ throw new Error('S3 storage not connected');
220
+ }
221
+ try {
222
+ const { ListObjectsV2Command } = await import('@aws-sdk/client-s3');
223
+ const params = {
224
+ Bucket: this.bucket,
225
+ MaxKeys: 1000, // Limit results for performance
226
+ };
227
+ if (prefix) {
228
+ params.Prefix = prefix;
229
+ }
230
+ const result = await this.s3Client.send(new ListObjectsV2Command(params));
231
+ const files = [];
232
+ if (result.Contents) {
233
+ for (const object of result.Contents) {
234
+ if (object.Key) {
235
+ files.push({
236
+ key: object.Key,
237
+ size: object.Size || 0,
238
+ lastModified: object.LastModified || new Date(),
239
+ etag: object.ETag?.replace(/"/g, ''), // Remove quotes from ETag
240
+ contentType: await this.getObjectContentType(object.Key),
241
+ });
242
+ }
243
+ }
244
+ }
245
+ if (this.config.environment.isDevelopment) {
246
+ console.log(`☁️ [AppKit] S3 files listed: ${prefix}* (${files.length} files)`);
247
+ }
248
+ return files;
249
+ }
250
+ catch (error) {
251
+ console.error(`[AppKit] S3 list error for prefix "${prefix}":`, error.message);
252
+ return [];
253
+ }
254
+ }
255
+ /**
256
+ * Gets public or CDN URL for S3 object
257
+ * @llm-rule WHEN: Generating URLs for S3 file access with CDN support
258
+ * @llm-rule AVOID: Hardcoded URLs - this handles CDN and region-specific URLs
259
+ */
260
+ url(key) {
261
+ // Use CDN URL if configured
262
+ if (this.cdnUrl) {
263
+ const baseUrl = this.cdnUrl.endsWith('/') ? this.cdnUrl : this.cdnUrl + '/';
264
+ const cleanKey = key.startsWith('/') ? key.slice(1) : key;
265
+ return baseUrl + cleanKey;
266
+ }
267
+ // Generate S3 public URL
268
+ if (this.endpoint) {
269
+ // Custom endpoint (Wasabi, MinIO, etc.)
270
+ const baseUrl = this.endpoint.endsWith('/') ? this.endpoint : this.endpoint + '/';
271
+ return `${baseUrl}${this.bucket}/${key}`;
272
+ }
273
+ // AWS S3 URL
274
+ return `https://${this.bucket}.s3.${this.region}.amazonaws.com/${key}`;
275
+ }
276
+ /**
277
+ * Generates signed URL for temporary S3 object access
278
+ * @llm-rule WHEN: Creating temporary download/upload links for S3 objects
279
+ * @llm-rule AVOID: Permanent URLs for private files - use signed URLs with expiration
280
+ */
281
+ async signedUrl(key, expiresIn = 3600) {
282
+ if (!this.connected || !this.s3Client) {
283
+ throw new Error('S3 storage not connected');
284
+ }
285
+ try {
286
+ const { GetObjectCommand } = await import('@aws-sdk/client-s3');
287
+ const { getSignedUrl } = await import('@aws-sdk/s3-request-presigner');
288
+ const command = new GetObjectCommand({
289
+ Bucket: this.bucket,
290
+ Key: key,
291
+ });
292
+ const signedUrl = await getSignedUrl(this.s3Client, command, {
293
+ expiresIn,
294
+ });
295
+ if (this.config.environment.isDevelopment) {
296
+ console.log(`🔐 [AppKit] S3 signed URL generated: ${key} (expires in ${expiresIn}s)`);
297
+ }
298
+ return signedUrl;
299
+ }
300
+ catch (error) {
301
+ throw new Error(`S3 signed URL generation failed: ${error.message}`);
302
+ }
303
+ }
304
+ /**
305
+ * Checks if S3 object exists without downloading
306
+ * @llm-rule WHEN: Validating S3 object existence efficiently
307
+ * @llm-rule AVOID: Downloading objects just to check existence
308
+ */
309
+ async exists(key) {
310
+ if (!this.connected || !this.s3Client) {
311
+ return false;
312
+ }
313
+ try {
314
+ const { HeadObjectCommand } = await import('@aws-sdk/client-s3');
315
+ const params = {
316
+ Bucket: this.bucket,
317
+ Key: key,
318
+ };
319
+ await this.s3Client.send(new HeadObjectCommand(params));
320
+ return true;
321
+ }
322
+ catch (error) {
323
+ if (error.name === 'NotFound' || error.name === 'NoSuchKey') {
324
+ return false;
325
+ }
326
+ console.error(`[AppKit] S3 exists check error for "${key}":`, error.message);
327
+ return false;
328
+ }
329
+ }
330
+ /**
331
+ * Copies S3 object efficiently using server-side copy
332
+ * @llm-rule WHEN: Duplicating S3 objects without downloading/uploading
333
+ * @llm-rule AVOID: Download and upload - S3 server-side copy is much faster
334
+ */
335
+ async copy(sourceKey, destKey) {
336
+ if (!this.connected || !this.s3Client) {
337
+ throw new Error('S3 storage not connected');
338
+ }
339
+ try {
340
+ const { CopyObjectCommand } = await import('@aws-sdk/client-s3');
341
+ const params = {
342
+ Bucket: this.bucket,
343
+ Key: destKey,
344
+ CopySource: `${this.bucket}/${sourceKey}`,
345
+ };
346
+ await this.s3Client.send(new CopyObjectCommand(params));
347
+ if (this.config.environment.isDevelopment) {
348
+ console.log(`☁️ [AppKit] S3 file copied: ${sourceKey} → ${destKey}`);
349
+ }
350
+ return destKey;
351
+ }
352
+ catch (error) {
353
+ throw new Error(`S3 copy failed: ${error.message}`);
354
+ }
355
+ }
356
+ /**
357
+ * Disconnects S3 strategy gracefully
358
+ * @llm-rule WHEN: App shutdown or storage cleanup
359
+ * @llm-rule AVOID: Abrupt disconnection - graceful shutdown prevents connection issues
360
+ */
361
+ async disconnect() {
362
+ if (!this.connected)
363
+ return;
364
+ try {
365
+ // S3 client doesn't need explicit disconnection
366
+ // Could implement connection pooling cleanup here if needed
367
+ this.connected = false;
368
+ this.s3Client = null;
369
+ if (this.config.environment.isDevelopment) {
370
+ console.log(`👋 [AppKit] S3 storage strategy disconnected`);
371
+ }
372
+ }
373
+ catch (error) {
374
+ console.error(`[AppKit] S3 disconnect error:`, error.message);
375
+ }
376
+ }
377
+ // Private helper methods
378
+ /**
379
+ * Converts readable stream to buffer
380
+ */
381
+ async streamToBuffer(stream) {
382
+ const chunks = [];
383
+ return new Promise((resolve, reject) => {
384
+ stream.on('data', (chunk) => chunks.push(chunk));
385
+ stream.on('error', reject);
386
+ stream.on('end', () => resolve(Buffer.concat(chunks)));
387
+ });
388
+ }
389
+ /**
390
+ * Detects content type from file extension and buffer
391
+ */
392
+ detectContentType(key, buffer) {
393
+ // Get extension from key
394
+ const ext = key.split('.').pop()?.toLowerCase();
395
+ // Common MIME types
396
+ const mimeTypes = {
397
+ 'jpg': 'image/jpeg',
398
+ 'jpeg': 'image/jpeg',
399
+ 'png': 'image/png',
400
+ 'gif': 'image/gif',
401
+ 'webp': 'image/webp',
402
+ 'svg': 'image/svg+xml',
403
+ 'pdf': 'application/pdf',
404
+ 'txt': 'text/plain',
405
+ 'json': 'application/json',
406
+ 'csv': 'text/csv',
407
+ 'zip': 'application/zip',
408
+ 'mp4': 'video/mp4',
409
+ 'webm': 'video/webm',
410
+ 'mp3': 'audio/mpeg',
411
+ 'wav': 'audio/wav',
412
+ };
413
+ if (ext && mimeTypes[ext]) {
414
+ return mimeTypes[ext];
415
+ }
416
+ // Simple buffer-based detection for images
417
+ const magic = buffer.subarray(0, 4);
418
+ if (magic[0] === 0xFF && magic[1] === 0xD8 && magic[2] === 0xFF) {
419
+ return 'image/jpeg';
420
+ }
421
+ if (magic[0] === 0x89 && magic[1] === 0x50 && magic[2] === 0x4E && magic[3] === 0x47) {
422
+ return 'image/png';
423
+ }
424
+ if (magic[0] === 0x47 && magic[1] === 0x49 && magic[2] === 0x46) {
425
+ return 'image/gif';
426
+ }
427
+ return 'application/octet-stream';
428
+ }
429
+ /**
430
+ * Gets content type for existing S3 object
431
+ */
432
+ async getObjectContentType(key) {
433
+ try {
434
+ const { HeadObjectCommand } = await import('@aws-sdk/client-s3');
435
+ const params = {
436
+ Bucket: this.bucket,
437
+ Key: key,
438
+ };
439
+ const result = await this.s3Client.send(new HeadObjectCommand(params));
440
+ return result.ContentType;
441
+ }
442
+ catch (error) {
443
+ // If we can't get content type, return undefined
444
+ return undefined;
445
+ }
446
+ }
447
+ /**
448
+ * Gets S3 connection info for debugging
449
+ */
450
+ getConnectionInfo() {
451
+ return {
452
+ connected: this.connected,
453
+ bucket: this.bucket,
454
+ region: this.region,
455
+ endpoint: this.endpoint,
456
+ provider: this.detectProvider(),
457
+ cdnEnabled: !!this.cdnUrl,
458
+ };
459
+ }
460
+ }
461
+ //# sourceMappingURL=s3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/storage/strategies/s3.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Smart defaults and environment validation for utilities
3
+ * @module @bloomneo/appkit/util
4
+ * @file src/util/defaults.ts
5
+ *
6
+ * @llm-rule WHEN: App startup - need to configure utility behavior and performance 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 like other modules
9
+ */
10
+ export interface CacheConfig {
11
+ enabled: boolean;
12
+ maxSize: number;
13
+ ttl: number;
14
+ }
15
+ export interface PerformanceConfig {
16
+ enabled: boolean;
17
+ memoization: boolean;
18
+ largeArrayThreshold: number;
19
+ chunkSizeLimit: number;
20
+ }
21
+ export interface DebugConfig {
22
+ enabled: boolean;
23
+ logOperations: boolean;
24
+ trackPerformance: boolean;
25
+ }
26
+ export interface SlugifyConfig {
27
+ lowercase: boolean;
28
+ strict: boolean;
29
+ locale: string;
30
+ replacement: string;
31
+ }
32
+ export interface FormatConfig {
33
+ locale: string;
34
+ currency: string;
35
+ dateFormat: string;
36
+ numberPrecision: number;
37
+ }
38
+ export interface EnvironmentConfig {
39
+ isDevelopment: boolean;
40
+ isProduction: boolean;
41
+ isTest: boolean;
42
+ nodeEnv: string;
43
+ }
44
+ export interface UtilConfig {
45
+ version: string;
46
+ cache: CacheConfig;
47
+ performance: PerformanceConfig;
48
+ debug: DebugConfig;
49
+ slugify: SlugifyConfig;
50
+ format: FormatConfig;
51
+ environment: EnvironmentConfig;
52
+ }
53
+ /**
54
+ * Gets smart defaults using VOILA_UTIL_* environment variables
55
+ * @llm-rule WHEN: App startup to get production-ready utility configuration
56
+ * @llm-rule AVOID: Calling repeatedly - expensive validation, cache the result
57
+ * @llm-rule NOTE: Called once at startup, cached globally for performance
58
+ */
59
+ export declare function getSmartDefaults(): UtilConfig;
60
+ /**
61
+ * Creates utility error with helpful context
62
+ * @llm-rule WHEN: Creating errors in utility functions for better debugging
63
+ * @llm-rule AVOID: Using generic Error objects - utility errors need context
64
+ */
65
+ export declare function createUtilityError(message: string, operation?: string, input?: any): Error;
66
+ /**
67
+ * Default configuration constants for reference
68
+ */
69
+ export declare const DEFAULT_CACHE_SIZE = 1000;
70
+ export declare const DEFAULT_CACHE_TTL = 300000;
71
+ export declare const DEFAULT_ARRAY_THRESHOLD = 10000;
72
+ export declare const DEFAULT_CHUNK_LIMIT = 100000;
73
+ export declare const DEFAULT_NUMBER_PRECISION = 2;
74
+ export declare const DEFAULT_LOCALE = "en-US";
75
+ export declare const DEFAULT_CURRENCY = "USD";
76
+ export declare const DEFAULT_SLUGIFY_REPLACEMENT = "-";
77
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/util/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,iBAAiB,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAyD7C;AA6ID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,GAAG,GACV,KAAK,CAYP;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,uBAAuB,QAAQ,CAAC;AAC7C,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,cAAc,UAAU,CAAC;AACtC,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC"}