@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,439 @@
1
+ /**
2
+ * Core storage class with automatic strategy selection and ultra-simple API
3
+ * @module @bloomneo/appkit/storage
4
+ * @file src/storage/storage.ts
5
+ *
6
+ * @llm-rule WHEN: Building apps that need file storage with automatic Local/S3/R2 selection
7
+ * @llm-rule AVOID: Using directly - always get instance via storageClass.get()
8
+ * @llm-rule NOTE: Auto-detects Local vs S3 vs R2 based on environment variables
9
+ */
10
+ import { LocalStrategy } from './strategies/local.js';
11
+ import { S3Strategy } from './strategies/s3.js';
12
+ import { R2Strategy } from './strategies/r2.js';
13
+ /**
14
+ * Storage class with automatic strategy selection and ultra-simple API
15
+ */
16
+ export class StorageClass {
17
+ config;
18
+ strategy;
19
+ connected = false;
20
+ constructor(config) {
21
+ this.config = config;
22
+ this.strategy = this.createStrategy();
23
+ }
24
+ /**
25
+ * Creates appropriate strategy based on configuration
26
+ * @llm-rule WHEN: Storage initialization - selects Local, S3, or R2 based on environment
27
+ * @llm-rule AVOID: Manual strategy creation - configuration handles strategy selection
28
+ */
29
+ createStrategy() {
30
+ switch (this.config.strategy) {
31
+ case 'local':
32
+ return new LocalStrategy(this.config);
33
+ case 's3':
34
+ return new S3Strategy(this.config);
35
+ case 'r2':
36
+ return new R2Strategy(this.config);
37
+ default:
38
+ throw new Error(`Unknown storage strategy: ${this.config.strategy}`);
39
+ }
40
+ }
41
+ /**
42
+ * Connects to storage backend with automatic setup
43
+ * @llm-rule WHEN: Storage initialization or reconnection after failure
44
+ * @llm-rule AVOID: Manual connection management - this handles connection state
45
+ */
46
+ async connect() {
47
+ if (this.connected)
48
+ return;
49
+ try {
50
+ // Strategy-specific connection (S3/R2 connect, Local creates dirs)
51
+ if ('connect' in this.strategy) {
52
+ await this.strategy.connect();
53
+ }
54
+ this.connected = true;
55
+ if (this.config.environment.isDevelopment) {
56
+ console.log(`✅ [AppKit] Storage system connected using ${this.config.strategy} strategy`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.error(`❌ [AppKit] Storage connection failed:`, error.message);
61
+ throw error;
62
+ }
63
+ }
64
+ /**
65
+ * Disconnects from storage backend gracefully
66
+ * @llm-rule WHEN: App shutdown or storage cleanup
67
+ * @llm-rule AVOID: Abrupt disconnection - graceful shutdown prevents data loss
68
+ */
69
+ async disconnect() {
70
+ if (!this.connected)
71
+ return;
72
+ try {
73
+ await this.strategy.disconnect();
74
+ this.connected = false;
75
+ if (this.config.environment.isDevelopment) {
76
+ console.log(`👋 [AppKit] Storage system disconnected`);
77
+ }
78
+ }
79
+ catch (error) {
80
+ console.error(`⚠️ [AppKit] Storage disconnect error:`, error.message);
81
+ }
82
+ }
83
+ /**
84
+ * Stores file with automatic validation and type detection
85
+ * @llm-rule WHEN: Uploading files to storage backend
86
+ * @llm-rule AVOID: Manual file validation - this handles size, type, and path validation
87
+ * @llm-rule NOTE: Returns the key/path where file was stored
88
+ */
89
+ async put(key, data, options) {
90
+ this.validateKey(key);
91
+ await this.ensureConnected();
92
+ try {
93
+ // Convert data to Buffer for consistency
94
+ const buffer = this.normalizeData(data);
95
+ // Validate file size
96
+ this.validateFileSize(buffer);
97
+ // Auto-detect content type if not provided
98
+ const contentType = options?.contentType || this.detectContentType(key, buffer);
99
+ // Validate file type
100
+ this.validateFileType(contentType);
101
+ // Store via strategy with enhanced options
102
+ const enhancedOptions = {
103
+ ...options,
104
+ contentType,
105
+ };
106
+ const result = await this.strategy.put(key, buffer, enhancedOptions);
107
+ // Log in development
108
+ if (this.config.environment.isDevelopment) {
109
+ console.log(`📤 [AppKit] File stored: ${key} (${buffer.length} bytes, ${contentType})`);
110
+ }
111
+ return result;
112
+ }
113
+ catch (error) {
114
+ console.error(`[AppKit] Storage put error for "${key}":`, error.message);
115
+ throw error;
116
+ }
117
+ }
118
+ /**
119
+ * Retrieves file with automatic error handling
120
+ * @llm-rule WHEN: Downloading files from storage backend
121
+ * @llm-rule AVOID: Manual error handling - this provides consistent error messages
122
+ */
123
+ async get(key) {
124
+ this.validateKey(key);
125
+ await this.ensureConnected();
126
+ try {
127
+ const result = await this.strategy.get(key);
128
+ // Log in development
129
+ if (this.config.environment.isDevelopment) {
130
+ console.log(`📥 [AppKit] File retrieved: ${key} (${result.length} bytes)`);
131
+ }
132
+ return result;
133
+ }
134
+ catch (error) {
135
+ console.error(`[AppKit] Storage get error for "${key}":`, error.message);
136
+ throw new Error(`File not found: ${key}`);
137
+ }
138
+ }
139
+ /**
140
+ * Deletes file with confirmation
141
+ * @llm-rule WHEN: Removing files from storage backend
142
+ * @llm-rule AVOID: Silent failures - this confirms deletion success
143
+ */
144
+ async delete(key) {
145
+ this.validateKey(key);
146
+ await this.ensureConnected();
147
+ try {
148
+ const result = await this.strategy.delete(key);
149
+ // Log in development
150
+ if (this.config.environment.isDevelopment) {
151
+ console.log(`🗑️ [AppKit] File deleted: ${key} (success: ${result})`);
152
+ }
153
+ return result;
154
+ }
155
+ catch (error) {
156
+ console.error(`[AppKit] Storage delete error for "${key}":`, error.message);
157
+ return false;
158
+ }
159
+ }
160
+ /**
161
+ * Lists files with prefix filtering and metadata
162
+ * @llm-rule WHEN: Browsing files or implementing file managers
163
+ * @llm-rule AVOID: Loading all files - use prefix filtering for performance
164
+ */
165
+ async list(prefix = '', limit) {
166
+ await this.ensureConnected();
167
+ try {
168
+ const files = await this.strategy.list(prefix);
169
+ // Apply limit if specified
170
+ const result = limit ? files.slice(0, limit) : files;
171
+ // Log in development
172
+ if (this.config.environment.isDevelopment) {
173
+ console.log(`📋 [AppKit] Files listed: ${prefix}* (${result.length} files)`);
174
+ }
175
+ return result;
176
+ }
177
+ catch (error) {
178
+ console.error(`[AppKit] Storage list error for prefix "${prefix}":`, error.message);
179
+ return [];
180
+ }
181
+ }
182
+ /**
183
+ * Gets public URL for file access
184
+ * @llm-rule WHEN: Generating URLs for file access in web applications
185
+ * @llm-rule AVOID: Hardcoding URLs - this handles CDN and strategy-specific URLs
186
+ */
187
+ url(key) {
188
+ this.validateKey(key);
189
+ try {
190
+ const url = this.strategy.url(key);
191
+ // Log in development
192
+ if (this.config.environment.isDevelopment) {
193
+ console.log(`🔗 [AppKit] URL generated: ${key} → ${url}`);
194
+ }
195
+ return url;
196
+ }
197
+ catch (error) {
198
+ console.error(`[AppKit] URL generation error for "${key}":`, error.message);
199
+ throw error;
200
+ }
201
+ }
202
+ /**
203
+ * Generates signed URL for temporary access
204
+ * @llm-rule WHEN: Creating temporary download links or private file access
205
+ * @llm-rule AVOID: Permanent URLs for private files - use signed URLs with expiration
206
+ */
207
+ async signedUrl(key, expiresIn = 3600) {
208
+ this.validateKey(key);
209
+ await this.ensureConnected();
210
+ try {
211
+ if (!this.strategy.signedUrl) {
212
+ throw new Error(`Signed URLs not supported with ${this.config.strategy} strategy`);
213
+ }
214
+ const url = await this.strategy.signedUrl(key, expiresIn);
215
+ // Log in development
216
+ if (this.config.environment.isDevelopment) {
217
+ console.log(`🔐 [AppKit] Signed URL generated: ${key} (expires in ${expiresIn}s)`);
218
+ }
219
+ return url;
220
+ }
221
+ catch (error) {
222
+ console.error(`[AppKit] Signed URL error for "${key}":`, error.message);
223
+ throw error;
224
+ }
225
+ }
226
+ /**
227
+ * Checks if file exists without downloading
228
+ * @llm-rule WHEN: Validating file existence before operations
229
+ * @llm-rule AVOID: Downloading files just to check existence - this is more efficient
230
+ */
231
+ async exists(key) {
232
+ this.validateKey(key);
233
+ await this.ensureConnected();
234
+ try {
235
+ const result = await this.strategy.exists(key);
236
+ // Log in development
237
+ if (this.config.environment.isDevelopment) {
238
+ console.log(`🔍 [AppKit] File exists check: ${key} → ${result}`);
239
+ }
240
+ return result;
241
+ }
242
+ catch (error) {
243
+ console.error(`[AppKit] Exists check error for "${key}":`, error.message);
244
+ return false;
245
+ }
246
+ }
247
+ /**
248
+ * Copies file from one location to another
249
+ * @llm-rule WHEN: Duplicating files or moving between folders
250
+ * @llm-rule AVOID: Download and upload - this uses efficient copy operations when possible
251
+ */
252
+ async copy(sourceKey, destKey) {
253
+ this.validateKey(sourceKey);
254
+ this.validateKey(destKey);
255
+ await this.ensureConnected();
256
+ try {
257
+ // Strategy-specific copy if available, otherwise download/upload
258
+ if ('copy' in this.strategy) {
259
+ return await this.strategy.copy(sourceKey, destKey);
260
+ }
261
+ // Fallback: download and upload
262
+ const data = await this.get(sourceKey);
263
+ return await this.put(destKey, data);
264
+ }
265
+ catch (error) {
266
+ console.error(`[AppKit] Copy error "${sourceKey}" → "${destKey}":`, error.message);
267
+ throw error;
268
+ }
269
+ }
270
+ /**
271
+ * Gets current storage strategy name for debugging
272
+ * @llm-rule WHEN: Debugging or health checks to see which strategy is active
273
+ * @llm-rule AVOID: Using for application logic - storage should be transparent
274
+ */
275
+ getStrategy() {
276
+ return this.config.strategy;
277
+ }
278
+ /**
279
+ * Gets storage configuration summary for debugging
280
+ * @llm-rule WHEN: Health checks or debugging storage configuration
281
+ * @llm-rule AVOID: Exposing sensitive details - this only shows safe info
282
+ */
283
+ getConfig() {
284
+ // Get config values based on strategy
285
+ let maxFileSize = 52428800; // 50MB default
286
+ let allowedTypes = [];
287
+ if (this.config.strategy === 'local' && this.config.local) {
288
+ maxFileSize = this.config.local.maxFileSize;
289
+ allowedTypes = this.config.local.allowedTypes;
290
+ }
291
+ else {
292
+ // S3 and R2 use global config or defaults
293
+ maxFileSize = 52428800; // 50MB default for cloud
294
+ allowedTypes = ['*']; // Allow all for cloud storage
295
+ }
296
+ return {
297
+ strategy: this.config.strategy,
298
+ connected: this.connected,
299
+ maxFileSize,
300
+ allowedTypes,
301
+ };
302
+ }
303
+ // Private helper methods
304
+ /**
305
+ * Ensures storage system is connected before operations
306
+ */
307
+ async ensureConnected() {
308
+ if (!this.connected) {
309
+ await this.connect();
310
+ }
311
+ }
312
+ /**
313
+ * Validates storage key format and security
314
+ */
315
+ validateKey(key) {
316
+ if (!key || typeof key !== 'string') {
317
+ throw new Error('Storage key must be a non-empty string');
318
+ }
319
+ if (key.length > 1024) {
320
+ throw new Error('Storage key too long (max 1024 characters)');
321
+ }
322
+ // Security: prevent path traversal
323
+ if (key.includes('..') || key.includes('//')) {
324
+ throw new Error('Storage key contains invalid path components');
325
+ }
326
+ // Normalize separators
327
+ if (key.includes('\\')) {
328
+ throw new Error('Storage key must use forward slashes (/) as separators');
329
+ }
330
+ // Remove leading slash for consistency
331
+ if (key.startsWith('/')) {
332
+ throw new Error('Storage key should not start with forward slash');
333
+ }
334
+ }
335
+ /**
336
+ * Normalizes input data to Buffer
337
+ */
338
+ normalizeData(data) {
339
+ if (Buffer.isBuffer(data)) {
340
+ return data;
341
+ }
342
+ if (data instanceof Uint8Array) {
343
+ return Buffer.from(data);
344
+ }
345
+ if (typeof data === 'string') {
346
+ return Buffer.from(data, 'utf8');
347
+ }
348
+ throw new Error('Data must be Buffer, Uint8Array, or string');
349
+ }
350
+ /**
351
+ * Validates file size against configured limits
352
+ */
353
+ validateFileSize(buffer) {
354
+ let maxSize = 52428800; // 50MB default
355
+ if (this.config.strategy === 'local' && this.config.local) {
356
+ maxSize = this.config.local.maxFileSize;
357
+ }
358
+ // S3 and R2 use default limit for now
359
+ if (buffer.length > maxSize) {
360
+ const maxMB = Math.round(maxSize / 1048576);
361
+ const fileMB = Math.round(buffer.length / 1048576);
362
+ throw new Error(`File too large: ${fileMB}MB (max: ${maxMB}MB)`);
363
+ }
364
+ }
365
+ /**
366
+ * Detects content type from file extension and buffer
367
+ */
368
+ detectContentType(key, buffer) {
369
+ // Get extension from key
370
+ const ext = key.split('.').pop()?.toLowerCase();
371
+ // Common MIME types
372
+ const mimeTypes = {
373
+ 'jpg': 'image/jpeg',
374
+ 'jpeg': 'image/jpeg',
375
+ 'png': 'image/png',
376
+ 'gif': 'image/gif',
377
+ 'webp': 'image/webp',
378
+ 'svg': 'image/svg+xml',
379
+ 'pdf': 'application/pdf',
380
+ 'txt': 'text/plain',
381
+ 'json': 'application/json',
382
+ 'csv': 'text/csv',
383
+ 'zip': 'application/zip',
384
+ 'mp4': 'video/mp4',
385
+ 'webm': 'video/webm',
386
+ 'mp3': 'audio/mpeg',
387
+ 'wav': 'audio/wav',
388
+ };
389
+ if (ext && mimeTypes[ext]) {
390
+ return mimeTypes[ext];
391
+ }
392
+ // Simple buffer-based detection
393
+ const magic = buffer.subarray(0, 4);
394
+ if (magic[0] === 0xFF && magic[1] === 0xD8 && magic[2] === 0xFF) {
395
+ return 'image/jpeg';
396
+ }
397
+ if (magic[0] === 0x89 && magic[1] === 0x50 && magic[2] === 0x4E && magic[3] === 0x47) {
398
+ return 'image/png';
399
+ }
400
+ if (magic[0] === 0x47 && magic[1] === 0x49 && magic[2] === 0x46) {
401
+ return 'image/gif';
402
+ }
403
+ return 'application/octet-stream'; // Default binary
404
+ }
405
+ /**
406
+ * Validates file type against allowed types
407
+ */
408
+ validateFileType(contentType) {
409
+ let allowedTypes = [];
410
+ if (this.config.strategy === 'local' && this.config.local) {
411
+ allowedTypes = this.config.local.allowedTypes;
412
+ }
413
+ else {
414
+ // S3 and R2 allow all types by default (filtering done at app level)
415
+ allowedTypes = ['*'];
416
+ }
417
+ // Allow all types if wildcard is present
418
+ if (allowedTypes.includes('*')) {
419
+ return;
420
+ }
421
+ // Check exact match or wildcard patterns
422
+ const isAllowed = allowedTypes.some(allowedType => {
423
+ if (allowedType === contentType) {
424
+ return true;
425
+ }
426
+ // Support wildcard patterns like "image/*"
427
+ if (allowedType.endsWith('/*')) {
428
+ const prefix = allowedType.slice(0, -2);
429
+ return contentType.startsWith(prefix + '/');
430
+ }
431
+ return false;
432
+ });
433
+ if (!isAllowed) {
434
+ throw new Error(`File type not allowed: ${contentType}. ` +
435
+ `Allowed types: ${allowedTypes.join(', ')}`);
436
+ }
437
+ }
438
+ }
439
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/storage/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Local filesystem storage strategy with automatic directory management
3
+ * @module @bloomneo/appkit/storage
4
+ * @file src/storage/strategies/local.ts
5
+ *
6
+ * @llm-rule WHEN: No cloud storage env vars - perfect for development and single-server apps
7
+ * @llm-rule AVOID: Production use across multiple servers - files don't sync across instances
8
+ * @llm-rule NOTE: Fast local storage, automatic directory creation, file serving support
9
+ */
10
+ import type { StorageStrategy, StorageFile, PutOptions } from '../storage.js';
11
+ import type { StorageConfig } from '../defaults.js';
12
+ /**
13
+ * Local filesystem storage strategy with intelligent file management
14
+ */
15
+ export declare class LocalStrategy implements StorageStrategy {
16
+ private config;
17
+ private baseDir;
18
+ private baseUrl;
19
+ private maxFileSize;
20
+ private allowedTypes;
21
+ /**
22
+ * Creates local strategy with direct environment access (like auth pattern)
23
+ * @llm-rule WHEN: Storage initialization without cloud env vars - automatic fallback
24
+ * @llm-rule AVOID: Manual local configuration - environment detection handles this
25
+ */
26
+ constructor(config: StorageConfig);
27
+ /**
28
+ * Stores file to local filesystem with automatic directory creation
29
+ * @llm-rule WHEN: Saving files to local storage for development or single-server apps
30
+ * @llm-rule AVOID: Manual directory management - this handles nested paths automatically
31
+ */
32
+ put(key: string, data: Buffer, options?: PutOptions): Promise<string>;
33
+ /**
34
+ * Retrieves file from local filesystem with error handling
35
+ * @llm-rule WHEN: Loading files from local storage
36
+ * @llm-rule AVOID: Direct fs operations - this handles errors and validation
37
+ */
38
+ get(key: string): Promise<Buffer>;
39
+ /**
40
+ * Deletes file from local filesystem with confirmation
41
+ * @llm-rule WHEN: Removing files from local storage
42
+ * @llm-rule AVOID: Silent failures - this confirms deletion or reports issues
43
+ */
44
+ delete(key: string): Promise<boolean>;
45
+ /**
46
+ * Lists files with prefix filtering and metadata
47
+ * @llm-rule WHEN: Browsing local files or implementing file managers
48
+ * @llm-rule AVOID: Loading all files - this efficiently scans directories
49
+ */
50
+ list(prefix?: string): Promise<StorageFile[]>;
51
+ /**
52
+ * Gets public URL for local file access
53
+ * @llm-rule WHEN: Generating URLs for local file serving
54
+ * @llm-rule AVOID: Hardcoded paths - this handles base URL configuration
55
+ */
56
+ url(key: string): string;
57
+ /**
58
+ * Checks if file exists without reading content
59
+ * @llm-rule WHEN: Validating file existence efficiently
60
+ * @llm-rule AVOID: Reading entire file just to check existence
61
+ */
62
+ exists(key: string): Promise<boolean>;
63
+ /**
64
+ * Generates signed URL for temporary local file access (not applicable for local storage)
65
+ * @llm-rule WHEN: API compatibility - local storage doesn't support signed URLs
66
+ * @llm-rule AVOID: Using signed URLs with local storage - use regular URLs instead
67
+ */
68
+ signedUrl(key: string, expiresIn?: number): Promise<string>;
69
+ /**
70
+ * Copies file within local filesystem efficiently
71
+ * @llm-rule WHEN: Duplicating files within local storage
72
+ * @llm-rule AVOID: Read/write operations - this uses efficient copy operations
73
+ */
74
+ copy(sourceKey: string, destKey: string): Promise<string>;
75
+ /**
76
+ * Disconnects local strategy gracefully
77
+ * @llm-rule WHEN: App shutdown or storage cleanup
78
+ * @llm-rule AVOID: Leaving temp files - this cleans up if configured
79
+ */
80
+ disconnect(): Promise<void>;
81
+ /**
82
+ * Gets absolute file path from storage key
83
+ */
84
+ private getFilePath;
85
+ /**
86
+ * Ensures directory exists, creating it if necessary
87
+ */
88
+ private ensureDirectoryExists;
89
+ /**
90
+ * Recursively scans directory for files matching pattern
91
+ */
92
+ private scanDirectory;
93
+ /**
94
+ * Cleans up empty directories after file deletion
95
+ */
96
+ private cleanupEmptyDirectories;
97
+ /**
98
+ * Sets file metadata using extended attributes (where supported)
99
+ */
100
+ private setFileMetadata;
101
+ /**
102
+ * Gets content type from file extension
103
+ */
104
+ private getContentTypeFromExtension;
105
+ /**
106
+ * Gets detailed local storage statistics
107
+ */
108
+ getDetailedStats(): {
109
+ strategy: string;
110
+ baseDir: string;
111
+ totalFiles: number;
112
+ totalSize: number;
113
+ maxFileSize: number;
114
+ allowedTypes: string[];
115
+ };
116
+ }
117
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/storage/strategies/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;GAEG;AACH,qBAAa,aAAc,YAAW,eAAe;IACnD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAW;IAE/B;;;;OAIG;gBACS,MAAM,EAAE,aAAa;IAoBjC;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAiC3E;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBvC;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0B3C;;;;OAIG;IACG,IAAI,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BvD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAWxB;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS3C;;;;OAIG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvE;;;;OAIG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B/D;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;YACW,qBAAqB;IAUnC;;OAEG;YACW,aAAa;IAyC3B;;OAEG;YACW,uBAAuB;IA2BrC;;OAEG;YACW,eAAe;IAiB7B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAwBnC;;OAEG;IACH,gBAAgB,IAAI;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB;CAUF"}