@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,368 @@
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 fs from 'fs/promises';
11
+ import path from 'path';
12
+ import { existsSync } from 'fs';
13
+ /**
14
+ * Local filesystem storage strategy with intelligent file management
15
+ */
16
+ export class LocalStrategy {
17
+ config;
18
+ baseDir;
19
+ baseUrl;
20
+ maxFileSize;
21
+ allowedTypes;
22
+ /**
23
+ * Creates local strategy with direct environment access (like auth pattern)
24
+ * @llm-rule WHEN: Storage initialization without cloud env vars - automatic fallback
25
+ * @llm-rule AVOID: Manual local configuration - environment detection handles this
26
+ */
27
+ constructor(config) {
28
+ this.config = config;
29
+ if (!config.local) {
30
+ throw new Error('Local storage configuration missing');
31
+ }
32
+ this.baseDir = path.resolve(config.local.dir);
33
+ this.baseUrl = config.local.baseUrl;
34
+ this.maxFileSize = config.local.maxFileSize;
35
+ this.allowedTypes = config.local.allowedTypes;
36
+ // Ensure base directory exists on initialization
37
+ this.ensureDirectoryExists(this.baseDir);
38
+ if (this.config.environment.isDevelopment) {
39
+ console.log(`✅ [AppKit] Local storage initialized (dir: ${this.baseDir}, maxSize: ${Math.round(this.maxFileSize / 1048576)}MB)`);
40
+ }
41
+ }
42
+ /**
43
+ * Stores file to local filesystem with automatic directory creation
44
+ * @llm-rule WHEN: Saving files to local storage for development or single-server apps
45
+ * @llm-rule AVOID: Manual directory management - this handles nested paths automatically
46
+ */
47
+ async put(key, data, options) {
48
+ try {
49
+ const filePath = this.getFilePath(key);
50
+ // Ensure parent directory exists
51
+ const parentDir = path.dirname(filePath);
52
+ await this.ensureDirectoryExists(parentDir);
53
+ // Write file to disk
54
+ await fs.writeFile(filePath, data);
55
+ // Set file metadata if supported (extended attributes not available on all systems)
56
+ if (options?.metadata) {
57
+ try {
58
+ await this.setFileMetadata(filePath, options.metadata);
59
+ }
60
+ catch (error) {
61
+ // Metadata setting is optional, don't fail the operation
62
+ if (this.config.environment.isDevelopment) {
63
+ console.warn(`[AppKit] Could not set metadata for ${key}:`, error.message);
64
+ }
65
+ }
66
+ }
67
+ if (this.config.environment.isDevelopment) {
68
+ console.log(`📁 [AppKit] Local file stored: ${key} (${data.length} bytes)`);
69
+ }
70
+ return key;
71
+ }
72
+ catch (error) {
73
+ throw new Error(`Failed to store file locally: ${error.message}`);
74
+ }
75
+ }
76
+ /**
77
+ * Retrieves file from local filesystem with error handling
78
+ * @llm-rule WHEN: Loading files from local storage
79
+ * @llm-rule AVOID: Direct fs operations - this handles errors and validation
80
+ */
81
+ async get(key) {
82
+ try {
83
+ const filePath = this.getFilePath(key);
84
+ // Check if file exists before reading
85
+ if (!existsSync(filePath)) {
86
+ throw new Error(`File not found: ${key}`);
87
+ }
88
+ // Read file from disk
89
+ const data = await fs.readFile(filePath);
90
+ if (this.config.environment.isDevelopment) {
91
+ console.log(`📁 [AppKit] Local file retrieved: ${key} (${data.length} bytes)`);
92
+ }
93
+ return data;
94
+ }
95
+ catch (error) {
96
+ throw new Error(`Failed to retrieve file locally: ${error.message}`);
97
+ }
98
+ }
99
+ /**
100
+ * Deletes file from local filesystem with confirmation
101
+ * @llm-rule WHEN: Removing files from local storage
102
+ * @llm-rule AVOID: Silent failures - this confirms deletion or reports issues
103
+ */
104
+ async delete(key) {
105
+ try {
106
+ const filePath = this.getFilePath(key);
107
+ // Check if file exists
108
+ if (!existsSync(filePath)) {
109
+ return false; // File doesn't exist, consider it "deleted"
110
+ }
111
+ // Delete file
112
+ await fs.unlink(filePath);
113
+ // Clean up empty directories
114
+ await this.cleanupEmptyDirectories(path.dirname(filePath));
115
+ if (this.config.environment.isDevelopment) {
116
+ console.log(`🗑️ [AppKit] Local file deleted: ${key}`);
117
+ }
118
+ return true;
119
+ }
120
+ catch (error) {
121
+ console.error(`[AppKit] Local delete error for "${key}":`, error.message);
122
+ return false;
123
+ }
124
+ }
125
+ /**
126
+ * Lists files with prefix filtering and metadata
127
+ * @llm-rule WHEN: Browsing local files or implementing file managers
128
+ * @llm-rule AVOID: Loading all files - this efficiently scans directories
129
+ */
130
+ async list(prefix = '') {
131
+ try {
132
+ const searchDir = prefix ? path.join(this.baseDir, path.dirname(prefix)) : this.baseDir;
133
+ const searchPattern = prefix ? path.basename(prefix) : '';
134
+ if (!existsSync(searchDir)) {
135
+ return []; // Directory doesn't exist, return empty list
136
+ }
137
+ const files = [];
138
+ await this.scanDirectory(searchDir, files, searchPattern, prefix);
139
+ // Sort by key for consistent ordering
140
+ files.sort((a, b) => a.key.localeCompare(b.key));
141
+ if (this.config.environment.isDevelopment) {
142
+ console.log(`📋 [AppKit] Local files listed: ${prefix}* (${files.length} files)`);
143
+ }
144
+ return files;
145
+ }
146
+ catch (error) {
147
+ console.error(`[AppKit] Local list error for prefix "${prefix}":`, error.message);
148
+ return [];
149
+ }
150
+ }
151
+ /**
152
+ * Gets public URL for local file access
153
+ * @llm-rule WHEN: Generating URLs for local file serving
154
+ * @llm-rule AVOID: Hardcoded paths - this handles base URL configuration
155
+ */
156
+ url(key) {
157
+ // Normalize key to use forward slashes for URLs
158
+ const normalizedKey = key.replace(/\\/g, '/');
159
+ // Ensure base URL ends with / and key doesn't start with /
160
+ const baseUrl = this.baseUrl.endsWith('/') ? this.baseUrl : this.baseUrl + '/';
161
+ const cleanKey = normalizedKey.startsWith('/') ? normalizedKey.slice(1) : normalizedKey;
162
+ return baseUrl + cleanKey;
163
+ }
164
+ /**
165
+ * Checks if file exists without reading content
166
+ * @llm-rule WHEN: Validating file existence efficiently
167
+ * @llm-rule AVOID: Reading entire file just to check existence
168
+ */
169
+ async exists(key) {
170
+ try {
171
+ const filePath = this.getFilePath(key);
172
+ return existsSync(filePath);
173
+ }
174
+ catch (error) {
175
+ return false;
176
+ }
177
+ }
178
+ /**
179
+ * Generates signed URL for temporary local file access (not applicable for local storage)
180
+ * @llm-rule WHEN: API compatibility - local storage doesn't support signed URLs
181
+ * @llm-rule AVOID: Using signed URLs with local storage - use regular URLs instead
182
+ */
183
+ async signedUrl(key, expiresIn = 3600) {
184
+ // Local storage doesn't support signed URLs, return regular URL
185
+ console.warn('[AppKit] Signed URLs not supported with local storage, returning public URL');
186
+ return this.url(key);
187
+ }
188
+ /**
189
+ * Copies file within local filesystem efficiently
190
+ * @llm-rule WHEN: Duplicating files within local storage
191
+ * @llm-rule AVOID: Read/write operations - this uses efficient copy operations
192
+ */
193
+ async copy(sourceKey, destKey) {
194
+ try {
195
+ const sourcePath = this.getFilePath(sourceKey);
196
+ const destPath = this.getFilePath(destKey);
197
+ // Check source exists
198
+ if (!existsSync(sourcePath)) {
199
+ throw new Error(`Source file not found: ${sourceKey}`);
200
+ }
201
+ // Ensure destination directory exists
202
+ const destDir = path.dirname(destPath);
203
+ await this.ensureDirectoryExists(destDir);
204
+ // Copy file
205
+ await fs.copyFile(sourcePath, destPath);
206
+ if (this.config.environment.isDevelopment) {
207
+ console.log(`📁 [AppKit] Local file copied: ${sourceKey} → ${destKey}`);
208
+ }
209
+ return destKey;
210
+ }
211
+ catch (error) {
212
+ throw new Error(`Failed to copy file locally: ${error.message}`);
213
+ }
214
+ }
215
+ /**
216
+ * Disconnects local strategy gracefully
217
+ * @llm-rule WHEN: App shutdown or storage cleanup
218
+ * @llm-rule AVOID: Leaving temp files - this cleans up if configured
219
+ */
220
+ async disconnect() {
221
+ // Local storage doesn't need explicit disconnection
222
+ // Could implement cleanup of temp files here if needed
223
+ if (this.config.environment.isDevelopment) {
224
+ console.log(`👋 [AppKit] Local storage strategy disconnected`);
225
+ }
226
+ }
227
+ // Private helper methods
228
+ /**
229
+ * Gets absolute file path from storage key
230
+ */
231
+ getFilePath(key) {
232
+ // Normalize path separators and prevent directory traversal
233
+ const normalizedKey = key.replace(/\\/g, '/').replace(/\.\.+/g, '');
234
+ return path.join(this.baseDir, normalizedKey);
235
+ }
236
+ /**
237
+ * Ensures directory exists, creating it if necessary
238
+ */
239
+ async ensureDirectoryExists(dirPath) {
240
+ try {
241
+ if (!existsSync(dirPath)) {
242
+ await fs.mkdir(dirPath, { recursive: true });
243
+ }
244
+ }
245
+ catch (error) {
246
+ throw new Error(`Failed to create directory: ${error.message}`);
247
+ }
248
+ }
249
+ /**
250
+ * Recursively scans directory for files matching pattern
251
+ */
252
+ async scanDirectory(dirPath, files, pattern = '', prefix = '') {
253
+ try {
254
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
255
+ for (const entry of entries) {
256
+ const fullPath = path.join(dirPath, entry.name);
257
+ if (entry.isDirectory()) {
258
+ // Recursively scan subdirectories
259
+ await this.scanDirectory(fullPath, files, pattern, prefix);
260
+ }
261
+ else if (entry.isFile()) {
262
+ // Check if file matches pattern
263
+ if (!pattern || entry.name.startsWith(pattern)) {
264
+ const relativePath = path.relative(this.baseDir, fullPath);
265
+ const key = relativePath.replace(/\\/g, '/'); // Normalize to forward slashes
266
+ // Get file stats
267
+ const stats = await fs.stat(fullPath);
268
+ files.push({
269
+ key,
270
+ size: stats.size,
271
+ lastModified: stats.mtime,
272
+ contentType: this.getContentTypeFromExtension(key),
273
+ });
274
+ }
275
+ }
276
+ }
277
+ }
278
+ catch (error) {
279
+ // Directory access error, skip silently
280
+ if (this.config.environment.isDevelopment) {
281
+ console.warn(`[AppKit] Error scanning directory ${dirPath}:`, error.message);
282
+ }
283
+ }
284
+ }
285
+ /**
286
+ * Cleans up empty directories after file deletion
287
+ */
288
+ async cleanupEmptyDirectories(dirPath) {
289
+ try {
290
+ // Don't clean up the base directory
291
+ if (dirPath === this.baseDir) {
292
+ return;
293
+ }
294
+ const entries = await fs.readdir(dirPath);
295
+ // If directory is empty, remove it and check parent
296
+ if (entries.length === 0) {
297
+ await fs.rmdir(dirPath);
298
+ // Recursively check parent directory
299
+ const parentDir = path.dirname(dirPath);
300
+ if (parentDir !== dirPath && parentDir !== this.baseDir) {
301
+ await this.cleanupEmptyDirectories(parentDir);
302
+ }
303
+ }
304
+ }
305
+ catch (error) {
306
+ // Cleanup is optional, don't fail if it doesn't work
307
+ if (this.config.environment.isDevelopment) {
308
+ console.warn(`[AppKit] Could not cleanup directory ${dirPath}:`, error.message);
309
+ }
310
+ }
311
+ }
312
+ /**
313
+ * Sets file metadata using extended attributes (where supported)
314
+ */
315
+ async setFileMetadata(filePath, metadata) {
316
+ // Extended attributes are not universally supported
317
+ // This is a placeholder for future metadata support
318
+ // Could implement using file naming conventions or sidecar files
319
+ // For now, we'll store metadata in a separate .meta file
320
+ const metaPath = filePath + '.meta';
321
+ const metaContent = JSON.stringify(metadata, null, 2);
322
+ try {
323
+ await fs.writeFile(metaPath, metaContent);
324
+ }
325
+ catch (error) {
326
+ // Metadata is optional
327
+ throw new Error(`Failed to write metadata: ${error.message}`);
328
+ }
329
+ }
330
+ /**
331
+ * Gets content type from file extension
332
+ */
333
+ getContentTypeFromExtension(key) {
334
+ const ext = path.extname(key).toLowerCase();
335
+ const mimeTypes = {
336
+ '.jpg': 'image/jpeg',
337
+ '.jpeg': 'image/jpeg',
338
+ '.png': 'image/png',
339
+ '.gif': 'image/gif',
340
+ '.webp': 'image/webp',
341
+ '.svg': 'image/svg+xml',
342
+ '.pdf': 'application/pdf',
343
+ '.txt': 'text/plain',
344
+ '.json': 'application/json',
345
+ '.csv': 'text/csv',
346
+ '.zip': 'application/zip',
347
+ '.mp4': 'video/mp4',
348
+ '.webm': 'video/webm',
349
+ '.mp3': 'audio/mpeg',
350
+ '.wav': 'audio/wav',
351
+ };
352
+ return mimeTypes[ext] || 'application/octet-stream';
353
+ }
354
+ /**
355
+ * Gets detailed local storage statistics
356
+ */
357
+ getDetailedStats() {
358
+ return {
359
+ strategy: 'local',
360
+ baseDir: this.baseDir,
361
+ totalFiles: 0, // Would need to scan to get accurate count
362
+ totalSize: 0, // Would need to scan to get accurate size
363
+ maxFileSize: this.maxFileSize,
364
+ allowedTypes: this.allowedTypes,
365
+ };
366
+ }
367
+ }
368
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/storage/strategies/local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Cloudflare R2 storage strategy with zero egress fees and automatic CDN integration
3
+ * @module @bloomneo/appkit/storage
4
+ * @file src/storage/strategies/r2.ts
5
+ *
6
+ * @llm-rule WHEN: App has CLOUDFLARE_R2_BUCKET env var for cost-effective distributed storage
7
+ * @llm-rule AVOID: Manual R2 setup - this handles connection, CDN integration, and S3-compatible API
8
+ * @llm-rule NOTE: Production-ready with zero egress fees, automatic CDN, S3-compatible operations
9
+ */
10
+ import type { StorageStrategy, StorageFile, PutOptions } from '../storage.js';
11
+ import type { StorageConfig } from '../defaults.js';
12
+ /**
13
+ * Cloudflare R2 storage strategy with cost optimization and CDN integration
14
+ */
15
+ export declare class R2Strategy implements StorageStrategy {
16
+ private config;
17
+ private r2Client;
18
+ private connected;
19
+ private bucket;
20
+ private accountId;
21
+ private cdnUrl?;
22
+ private endpoint;
23
+ /**
24
+ * Creates R2 strategy with direct environment access (like auth pattern)
25
+ * @llm-rule WHEN: Storage initialization with Cloudflare R2 environment variables detected
26
+ * @llm-rule AVOID: Manual R2 configuration - environment detection handles Cloudflare specifics
27
+ */
28
+ constructor(config: StorageConfig);
29
+ /**
30
+ * Connects to Cloudflare R2 with automatic account validation
31
+ * @llm-rule WHEN: Storage initialization or reconnection after failure
32
+ * @llm-rule AVOID: Manual R2 client setup - this handles Cloudflare-specific configuration
33
+ */
34
+ connect(): Promise<void>;
35
+ /**
36
+ * Tests R2 connection by checking bucket access
37
+ */
38
+ private testConnection;
39
+ /**
40
+ * Stores file to R2 with automatic content type detection and zero egress cost
41
+ * @llm-rule WHEN: Uploading files to Cloudflare R2 for cost-effective storage
42
+ * @llm-rule AVOID: Manual R2 operations - this handles R2-specific optimizations
43
+ */
44
+ put(key: string, data: Buffer, options?: PutOptions): Promise<string>;
45
+ /**
46
+ * Retrieves file from R2 with streaming support and zero egress cost
47
+ * @llm-rule WHEN: Downloading files from Cloudflare R2
48
+ * @llm-rule AVOID: Manual R2 operations - this handles streaming and cost optimization
49
+ */
50
+ get(key: string): Promise<Buffer>;
51
+ /**
52
+ * Deletes file from R2 with confirmation
53
+ * @llm-rule WHEN: Removing files from Cloudflare R2 storage
54
+ * @llm-rule AVOID: Silent failures - this confirms deletion success
55
+ */
56
+ delete(key: string): Promise<boolean>;
57
+ /**
58
+ * Lists files with prefix filtering and R2-optimized pagination
59
+ * @llm-rule WHEN: Browsing R2 files or implementing file managers
60
+ * @llm-rule AVOID: Loading all objects - R2 has same limits as S3
61
+ */
62
+ list(prefix?: string): Promise<StorageFile[]>;
63
+ /**
64
+ * Gets CDN or public URL for R2 object with automatic CDN detection
65
+ * @llm-rule WHEN: Generating URLs for R2 file access with CDN optimization
66
+ * @llm-rule AVOID: Hardcoded URLs - this handles CDN and R2-specific URLs
67
+ */
68
+ url(key: string): string;
69
+ /**
70
+ * Generates R2 public URL hash (simplified for demo)
71
+ */
72
+ private generatePublicHash;
73
+ /**
74
+ * Generates signed URL for temporary R2 object access
75
+ * @llm-rule WHEN: Creating temporary download/upload links for R2 objects
76
+ * @llm-rule AVOID: Public URLs for private files - use signed URLs with expiration
77
+ */
78
+ signedUrl(key: string, expiresIn?: number): Promise<string>;
79
+ /**
80
+ * Checks if R2 object exists without downloading
81
+ * @llm-rule WHEN: Validating R2 object existence efficiently
82
+ * @llm-rule AVOID: Downloading objects just to check existence
83
+ */
84
+ exists(key: string): Promise<boolean>;
85
+ /**
86
+ * Copies R2 object efficiently using server-side copy (zero egress cost)
87
+ * @llm-rule WHEN: Duplicating R2 objects without bandwidth costs
88
+ * @llm-rule AVOID: Download and upload - R2 server-side copy has zero egress fees
89
+ */
90
+ copy(sourceKey: string, destKey: string): Promise<string>;
91
+ /**
92
+ * Disconnects R2 strategy gracefully
93
+ * @llm-rule WHEN: App shutdown or storage cleanup
94
+ * @llm-rule AVOID: Abrupt disconnection - graceful shutdown prevents connection issues
95
+ */
96
+ disconnect(): Promise<void>;
97
+ /**
98
+ * Converts readable stream to buffer
99
+ */
100
+ private streamToBuffer;
101
+ /**
102
+ * Detects content type from file extension and buffer
103
+ */
104
+ private detectContentType;
105
+ /**
106
+ * Gets content type for existing R2 object
107
+ */
108
+ private getObjectContentType;
109
+ /**
110
+ * Gets R2 connection info for debugging
111
+ */
112
+ getConnectionInfo(): {
113
+ connected: boolean;
114
+ bucket: string;
115
+ accountId: string;
116
+ endpoint: string;
117
+ cdnEnabled: boolean;
118
+ zeroEgressFees: boolean;
119
+ };
120
+ /**
121
+ * Gets R2-specific cost optimization info
122
+ */
123
+ getCostInfo(): {
124
+ egressFees: string;
125
+ storageClass: string;
126
+ cdnIntegration: boolean;
127
+ recommendedFor: string[];
128
+ };
129
+ }
130
+ //# sourceMappingURL=r2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../../src/storage/strategies/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,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,UAAW,YAAW,eAAe;IAChD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;OAIG;gBACS,MAAM,EAAE,aAAa;IAejC;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C9B;;OAEG;YACW,cAAc;IAgB5B;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IA6C3E;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmCvC;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2B3C;;;;OAIG;IACG,IAAI,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA8CvD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAYxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;OAIG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IA4BvE;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB3C;;;;OAIG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0B/D;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;OAEG;YACW,cAAc;IAU5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkDzB;;OAEG;YACW,oBAAoB;IAiBlC;;OAEG;IACH,iBAAiB,IAAI;QACnB,SAAS,EAAE,OAAO,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,OAAO,CAAC;QACpB,cAAc,EAAE,OAAO,CAAC;KACzB;IAWD;;OAEG;IACH,WAAW,IAAI;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,EAAE,MAAM,EAAE,CAAC;KAC1B;CAaF"}