alepha 0.15.1 → 0.15.3

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 (523) hide show
  1. package/README.md +68 -80
  2. package/dist/api/audits/index.d.ts +10 -33
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +10 -33
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +10 -3
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +10 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +162 -155
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/jobs/index.js +10 -3
  13. package/dist/api/jobs/index.js.map +1 -1
  14. package/dist/api/keys/index.d.ts +413 -0
  15. package/dist/api/keys/index.d.ts.map +1 -0
  16. package/dist/api/keys/index.js +476 -0
  17. package/dist/api/keys/index.js.map +1 -0
  18. package/dist/api/notifications/index.d.ts +10 -4
  19. package/dist/api/notifications/index.d.ts.map +1 -1
  20. package/dist/api/notifications/index.js +10 -4
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +43 -50
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +30 -37
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +1081 -760
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +2539 -218
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts +138 -132
  31. package/dist/api/verifications/index.d.ts.map +1 -1
  32. package/dist/api/verifications/index.js +12 -4
  33. package/dist/api/verifications/index.js.map +1 -1
  34. package/dist/batch/index.d.ts +20 -40
  35. package/dist/batch/index.d.ts.map +1 -1
  36. package/dist/batch/index.js +31 -44
  37. package/dist/batch/index.js.map +1 -1
  38. package/dist/bucket/index.d.ts +440 -8
  39. package/dist/bucket/index.d.ts.map +1 -1
  40. package/dist/bucket/index.js +1861 -12
  41. package/dist/bucket/index.js.map +1 -1
  42. package/dist/cache/core/index.d.ts +179 -7
  43. package/dist/cache/core/index.d.ts.map +1 -1
  44. package/dist/cache/core/index.js +213 -7
  45. package/dist/cache/core/index.js.map +1 -1
  46. package/dist/cache/redis/index.d.ts +1 -0
  47. package/dist/cache/redis/index.d.ts.map +1 -1
  48. package/dist/cache/redis/index.js +4 -0
  49. package/dist/cache/redis/index.js.map +1 -1
  50. package/dist/cli/index.d.ts +638 -5645
  51. package/dist/cli/index.d.ts.map +1 -1
  52. package/dist/cli/index.js +2550 -368
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/command/index.d.ts +203 -45
  55. package/dist/command/index.d.ts.map +1 -1
  56. package/dist/command/index.js +2060 -71
  57. package/dist/command/index.js.map +1 -1
  58. package/dist/core/index.browser.js +70 -40
  59. package/dist/core/index.browser.js.map +1 -1
  60. package/dist/core/index.d.ts +34 -13
  61. package/dist/core/index.d.ts.map +1 -1
  62. package/dist/core/index.js +90 -40
  63. package/dist/core/index.js.map +1 -1
  64. package/dist/core/index.native.js +70 -40
  65. package/dist/core/index.native.js.map +1 -1
  66. package/dist/datetime/index.d.ts +15 -0
  67. package/dist/datetime/index.d.ts.map +1 -1
  68. package/dist/datetime/index.js +15 -0
  69. package/dist/datetime/index.js.map +1 -1
  70. package/dist/email/index.d.ts +323 -20
  71. package/dist/email/index.d.ts.map +1 -1
  72. package/dist/email/index.js +1857 -7
  73. package/dist/email/index.js.map +1 -1
  74. package/dist/fake/index.d.ts +90 -8
  75. package/dist/fake/index.d.ts.map +1 -1
  76. package/dist/fake/index.js +91 -20
  77. package/dist/fake/index.js.map +1 -1
  78. package/dist/lock/core/index.d.ts +11 -4
  79. package/dist/lock/core/index.d.ts.map +1 -1
  80. package/dist/lock/core/index.js +11 -4
  81. package/dist/lock/core/index.js.map +1 -1
  82. package/dist/logger/index.d.ts +17 -66
  83. package/dist/logger/index.d.ts.map +1 -1
  84. package/dist/logger/index.js +14 -63
  85. package/dist/logger/index.js.map +1 -1
  86. package/dist/mcp/index.d.ts +10 -30
  87. package/dist/mcp/index.d.ts.map +1 -1
  88. package/dist/mcp/index.js +12 -35
  89. package/dist/mcp/index.js.map +1 -1
  90. package/dist/orm/index.browser.js +3 -3
  91. package/dist/orm/index.browser.js.map +1 -1
  92. package/dist/orm/index.bun.js +39 -20
  93. package/dist/orm/index.bun.js.map +1 -1
  94. package/dist/orm/index.d.ts +517 -540
  95. package/dist/orm/index.d.ts.map +1 -1
  96. package/dist/orm/index.js +58 -71
  97. package/dist/orm/index.js.map +1 -1
  98. package/dist/queue/core/index.d.ts +18 -10
  99. package/dist/queue/core/index.d.ts.map +1 -1
  100. package/dist/queue/core/index.js +14 -6
  101. package/dist/queue/core/index.js.map +1 -1
  102. package/dist/react/auth/index.browser.js +108 -0
  103. package/dist/react/auth/index.browser.js.map +1 -0
  104. package/dist/react/auth/index.d.ts +100 -0
  105. package/dist/react/auth/index.d.ts.map +1 -0
  106. package/dist/react/auth/index.js +145 -0
  107. package/dist/react/auth/index.js.map +1 -0
  108. package/dist/react/core/index.d.ts +469 -0
  109. package/dist/react/core/index.d.ts.map +1 -0
  110. package/dist/react/core/index.js +464 -0
  111. package/dist/react/core/index.js.map +1 -0
  112. package/dist/react/form/index.d.ts +232 -0
  113. package/dist/react/form/index.d.ts.map +1 -0
  114. package/dist/react/form/index.js +432 -0
  115. package/dist/react/form/index.js.map +1 -0
  116. package/dist/react/head/index.browser.js +423 -0
  117. package/dist/react/head/index.browser.js.map +1 -0
  118. package/dist/react/head/index.d.ts +288 -0
  119. package/dist/react/head/index.d.ts.map +1 -0
  120. package/dist/react/head/index.js +465 -0
  121. package/dist/react/head/index.js.map +1 -0
  122. package/dist/react/i18n/index.d.ts +175 -0
  123. package/dist/react/i18n/index.d.ts.map +1 -0
  124. package/dist/react/i18n/index.js +224 -0
  125. package/dist/react/i18n/index.js.map +1 -0
  126. package/dist/react/router/index.browser.js +1974 -0
  127. package/dist/react/router/index.browser.js.map +1 -0
  128. package/dist/react/router/index.d.ts +1956 -0
  129. package/dist/react/router/index.d.ts.map +1 -0
  130. package/dist/react/router/index.js +4722 -0
  131. package/dist/react/router/index.js.map +1 -0
  132. package/dist/react/websocket/index.d.ts +117 -0
  133. package/dist/react/websocket/index.d.ts.map +1 -0
  134. package/dist/react/websocket/index.js +107 -0
  135. package/dist/react/websocket/index.js.map +1 -0
  136. package/dist/redis/index.bun.js +4 -0
  137. package/dist/redis/index.bun.js.map +1 -1
  138. package/dist/redis/index.d.ts +41 -44
  139. package/dist/redis/index.d.ts.map +1 -1
  140. package/dist/redis/index.js +16 -25
  141. package/dist/redis/index.js.map +1 -1
  142. package/dist/retry/index.d.ts +11 -2
  143. package/dist/retry/index.d.ts.map +1 -1
  144. package/dist/retry/index.js +11 -2
  145. package/dist/retry/index.js.map +1 -1
  146. package/dist/scheduler/index.d.ts +11 -2
  147. package/dist/scheduler/index.d.ts.map +1 -1
  148. package/dist/scheduler/index.js +11 -2
  149. package/dist/scheduler/index.js.map +1 -1
  150. package/dist/security/index.d.ts +140 -49
  151. package/dist/security/index.d.ts.map +1 -1
  152. package/dist/security/index.js +164 -32
  153. package/dist/security/index.js.map +1 -1
  154. package/dist/server/auth/index.d.ts +12 -7
  155. package/dist/server/auth/index.d.ts.map +1 -1
  156. package/dist/server/auth/index.js +12 -7
  157. package/dist/server/auth/index.js.map +1 -1
  158. package/dist/server/cache/index.d.ts +7 -22
  159. package/dist/server/cache/index.d.ts.map +1 -1
  160. package/dist/server/cache/index.js +7 -22
  161. package/dist/server/cache/index.js.map +1 -1
  162. package/dist/server/compress/index.d.ts +10 -2
  163. package/dist/server/compress/index.d.ts.map +1 -1
  164. package/dist/server/compress/index.js +10 -2
  165. package/dist/server/compress/index.js.map +1 -1
  166. package/dist/server/cookies/index.d.ts +40 -16
  167. package/dist/server/cookies/index.d.ts.map +1 -1
  168. package/dist/server/cookies/index.js +7 -5
  169. package/dist/server/cookies/index.js.map +1 -1
  170. package/dist/server/core/index.d.ts +124 -23
  171. package/dist/server/core/index.d.ts.map +1 -1
  172. package/dist/server/core/index.js +231 -14
  173. package/dist/server/core/index.js.map +1 -1
  174. package/dist/server/cors/index.d.ts +13 -23
  175. package/dist/server/cors/index.d.ts.map +1 -1
  176. package/dist/server/cors/index.js +7 -21
  177. package/dist/server/cors/index.js.map +1 -1
  178. package/dist/server/health/index.d.ts +8 -2
  179. package/dist/server/health/index.d.ts.map +1 -1
  180. package/dist/server/health/index.js +8 -2
  181. package/dist/server/health/index.js.map +1 -1
  182. package/dist/server/helmet/index.d.ts +11 -3
  183. package/dist/server/helmet/index.d.ts.map +1 -1
  184. package/dist/server/helmet/index.js +11 -3
  185. package/dist/server/helmet/index.js.map +1 -1
  186. package/dist/server/links/index.d.ts +11 -6
  187. package/dist/server/links/index.d.ts.map +1 -1
  188. package/dist/server/links/index.js +11 -6
  189. package/dist/server/links/index.js.map +1 -1
  190. package/dist/server/metrics/index.d.ts +10 -3
  191. package/dist/server/metrics/index.d.ts.map +1 -1
  192. package/dist/server/metrics/index.js +10 -3
  193. package/dist/server/metrics/index.js.map +1 -1
  194. package/dist/server/multipart/index.d.ts +9 -3
  195. package/dist/server/multipart/index.d.ts.map +1 -1
  196. package/dist/server/multipart/index.js +9 -3
  197. package/dist/server/multipart/index.js.map +1 -1
  198. package/dist/server/proxy/index.d.ts +8 -2
  199. package/dist/server/proxy/index.d.ts.map +1 -1
  200. package/dist/server/proxy/index.js +8 -2
  201. package/dist/server/proxy/index.js.map +1 -1
  202. package/dist/server/rate-limit/index.d.ts +30 -35
  203. package/dist/server/rate-limit/index.d.ts.map +1 -1
  204. package/dist/server/rate-limit/index.js +18 -55
  205. package/dist/server/rate-limit/index.js.map +1 -1
  206. package/dist/server/static/index.d.ts +137 -4
  207. package/dist/server/static/index.d.ts.map +1 -1
  208. package/dist/server/static/index.js +1853 -5
  209. package/dist/server/static/index.js.map +1 -1
  210. package/dist/server/swagger/index.d.ts +309 -6
  211. package/dist/server/swagger/index.d.ts.map +1 -1
  212. package/dist/server/swagger/index.js +1854 -6
  213. package/dist/server/swagger/index.js.map +1 -1
  214. package/dist/sms/index.d.ts +309 -7
  215. package/dist/sms/index.d.ts.map +1 -1
  216. package/dist/sms/index.js +1856 -7
  217. package/dist/sms/index.js.map +1 -1
  218. package/dist/system/index.browser.js +1218 -0
  219. package/dist/system/index.browser.js.map +1 -0
  220. package/dist/{file → system}/index.d.ts +343 -16
  221. package/dist/system/index.d.ts.map +1 -0
  222. package/dist/{file → system}/index.js +419 -22
  223. package/dist/system/index.js.map +1 -0
  224. package/dist/thread/index.d.ts +11 -2
  225. package/dist/thread/index.d.ts.map +1 -1
  226. package/dist/thread/index.js +11 -2
  227. package/dist/thread/index.js.map +1 -1
  228. package/dist/topic/core/index.d.ts +12 -5
  229. package/dist/topic/core/index.d.ts.map +1 -1
  230. package/dist/topic/core/index.js +12 -5
  231. package/dist/topic/core/index.js.map +1 -1
  232. package/dist/vite/index.d.ts +5 -6272
  233. package/dist/vite/index.d.ts.map +1 -1
  234. package/dist/vite/index.js +23 -10
  235. package/dist/vite/index.js.map +1 -1
  236. package/dist/websocket/index.d.ts +12 -8
  237. package/dist/websocket/index.d.ts.map +1 -1
  238. package/dist/websocket/index.js +12 -8
  239. package/dist/websocket/index.js.map +1 -1
  240. package/package.json +82 -11
  241. package/src/api/audits/index.ts +10 -33
  242. package/src/api/files/__tests__/$bucket.spec.ts +1 -1
  243. package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
  244. package/src/api/files/controllers/FileController.spec.ts +1 -1
  245. package/src/api/files/index.ts +10 -3
  246. package/src/api/files/jobs/FileJobs.spec.ts +1 -1
  247. package/src/api/files/services/FileService.spec.ts +1 -1
  248. package/src/api/jobs/index.ts +10 -3
  249. package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
  250. package/src/api/keys/controllers/ApiKeyController.ts +103 -0
  251. package/src/api/keys/entities/apiKeyEntity.ts +41 -0
  252. package/src/api/keys/index.ts +49 -0
  253. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
  254. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
  255. package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
  256. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
  257. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
  258. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
  259. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
  260. package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
  261. package/src/api/keys/services/ApiKeyService.ts +306 -0
  262. package/src/api/logs/TODO.md +55 -0
  263. package/src/api/notifications/index.ts +10 -4
  264. package/src/api/parameters/index.ts +9 -30
  265. package/src/api/parameters/primitives/$config.ts +12 -4
  266. package/src/api/parameters/services/ConfigStore.ts +9 -3
  267. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
  268. package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
  269. package/src/api/users/index.ts +14 -3
  270. package/src/api/users/primitives/$realm.ts +33 -5
  271. package/src/api/users/providers/RealmProvider.ts +1 -12
  272. package/src/api/users/services/SessionService.ts +1 -1
  273. package/src/api/verifications/controllers/VerificationController.ts +2 -0
  274. package/src/api/verifications/index.ts +10 -4
  275. package/src/batch/index.ts +9 -36
  276. package/src/batch/primitives/$batch.ts +0 -8
  277. package/src/batch/providers/BatchProvider.ts +29 -2
  278. package/src/bucket/__tests__/shared.ts +1 -1
  279. package/src/bucket/index.ts +13 -6
  280. package/src/bucket/primitives/$bucket.ts +1 -1
  281. package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
  282. package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
  283. package/src/cache/core/__tests__/shared.ts +30 -0
  284. package/src/cache/core/index.ts +11 -6
  285. package/src/cache/core/primitives/$cache.spec.ts +5 -0
  286. package/src/cache/core/providers/CacheProvider.ts +17 -0
  287. package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
  288. package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
  289. package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
  290. package/src/cli/apps/AlephaCli.ts +1 -14
  291. package/src/cli/apps/AlephaPackageBuilderCli.ts +10 -1
  292. package/src/cli/atoms/buildOptions.ts +99 -9
  293. package/src/cli/commands/build.ts +150 -37
  294. package/src/cli/commands/db.ts +22 -18
  295. package/src/cli/commands/deploy.ts +1 -1
  296. package/src/cli/commands/dev.ts +1 -20
  297. package/src/cli/commands/gen/env.ts +5 -2
  298. package/src/cli/commands/gen/openapi.ts +5 -2
  299. package/src/cli/commands/init.spec.ts +588 -0
  300. package/src/cli/commands/init.ts +115 -58
  301. package/src/cli/commands/lint.ts +7 -1
  302. package/src/cli/commands/typecheck.ts +11 -0
  303. package/src/cli/providers/AppEntryProvider.ts +1 -1
  304. package/src/cli/providers/ViteBuildProvider.ts +8 -50
  305. package/src/cli/providers/ViteDevServerProvider.ts +35 -16
  306. package/src/cli/services/AlephaCliUtils.ts +52 -121
  307. package/src/cli/services/PackageManagerUtils.ts +129 -11
  308. package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
  309. package/src/cli/services/ProjectScaffolder.ts +148 -81
  310. package/src/cli/services/ViteUtils.ts +82 -0
  311. package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +37 -24
  312. package/src/cli/templates/apiAppSecurityTs.ts +11 -0
  313. package/src/cli/templates/apiIndexTs.ts +30 -0
  314. package/src/cli/templates/gitignore.ts +39 -0
  315. package/src/cli/{assets → templates}/mainCss.ts +11 -2
  316. package/src/cli/templates/mainServerTs.ts +33 -0
  317. package/src/cli/templates/webAppRouterTs.ts +74 -0
  318. package/src/cli/templates/webHelloComponentTsx.ts +30 -0
  319. package/src/command/helpers/Runner.spec.ts +139 -0
  320. package/src/command/helpers/Runner.ts +7 -22
  321. package/src/command/index.ts +12 -4
  322. package/src/command/providers/CliProvider.spec.ts +1392 -0
  323. package/src/command/providers/CliProvider.ts +320 -47
  324. package/src/core/Alepha.ts +34 -27
  325. package/src/core/__tests__/Alepha-start.spec.ts +4 -4
  326. package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
  327. package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
  328. package/src/core/index.shared.ts +1 -0
  329. package/src/core/index.ts +20 -0
  330. package/src/core/providers/EventManager.spec.ts +0 -71
  331. package/src/core/providers/EventManager.ts +3 -15
  332. package/src/core/providers/Json.ts +2 -14
  333. package/src/datetime/index.ts +15 -0
  334. package/src/email/index.ts +10 -5
  335. package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
  336. package/src/email/providers/LocalEmailProvider.ts +1 -1
  337. package/src/fake/__tests__/keyName.example.ts +1 -1
  338. package/src/fake/__tests__/keyName.spec.ts +5 -5
  339. package/src/fake/index.ts +9 -6
  340. package/src/fake/providers/FakeProvider.spec.ts +258 -40
  341. package/src/fake/providers/FakeProvider.ts +133 -19
  342. package/src/lock/core/index.ts +11 -4
  343. package/src/logger/index.ts +17 -66
  344. package/src/mcp/index.ts +10 -27
  345. package/src/mcp/transports/SseMcpTransport.ts +0 -11
  346. package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
  347. package/src/orm/index.browser.ts +2 -2
  348. package/src/orm/index.bun.ts +5 -3
  349. package/src/orm/index.ts +23 -53
  350. package/src/orm/providers/drivers/BunSqliteProvider.ts +5 -1
  351. package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
  352. package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
  353. package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
  354. package/src/orm/services/Repository.ts +7 -3
  355. package/src/queue/core/index.ts +14 -6
  356. package/src/react/auth/__tests__/$auth.spec.ts +202 -0
  357. package/src/react/auth/hooks/useAuth.ts +32 -0
  358. package/src/react/auth/index.browser.ts +13 -0
  359. package/src/react/auth/index.shared.ts +2 -0
  360. package/src/react/auth/index.ts +48 -0
  361. package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
  362. package/src/react/auth/services/ReactAuth.ts +135 -0
  363. package/src/react/core/__tests__/Router.spec.tsx +169 -0
  364. package/src/react/core/components/ClientOnly.tsx +49 -0
  365. package/src/react/core/components/ErrorBoundary.tsx +73 -0
  366. package/src/react/core/contexts/AlephaContext.ts +7 -0
  367. package/src/react/core/contexts/AlephaProvider.tsx +42 -0
  368. package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
  369. package/src/react/core/hooks/useAction.ts +480 -0
  370. package/src/react/core/hooks/useAlepha.ts +26 -0
  371. package/src/react/core/hooks/useClient.ts +17 -0
  372. package/src/react/core/hooks/useEvents.ts +51 -0
  373. package/src/react/core/hooks/useInject.ts +12 -0
  374. package/src/react/core/hooks/useStore.ts +52 -0
  375. package/src/react/core/index.ts +90 -0
  376. package/src/react/form/components/FormState.tsx +17 -0
  377. package/src/react/form/errors/FormValidationError.ts +18 -0
  378. package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
  379. package/src/react/form/hooks/useForm.ts +47 -0
  380. package/src/react/form/hooks/useFormState.ts +130 -0
  381. package/src/react/form/index.ts +44 -0
  382. package/src/react/form/services/FormModel.ts +614 -0
  383. package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
  384. package/src/react/head/helpers/SeoExpander.ts +142 -0
  385. package/src/react/head/hooks/useHead.spec.tsx +288 -0
  386. package/src/react/head/hooks/useHead.ts +62 -0
  387. package/src/react/head/index.browser.ts +26 -0
  388. package/src/react/head/index.ts +44 -0
  389. package/src/react/head/interfaces/Head.ts +105 -0
  390. package/src/react/head/primitives/$head.ts +25 -0
  391. package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
  392. package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
  393. package/src/react/head/providers/HeadProvider.ts +168 -0
  394. package/src/react/head/providers/ServerHeadProvider.ts +31 -0
  395. package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
  396. package/src/react/i18n/components/Localize.spec.tsx +357 -0
  397. package/src/react/i18n/components/Localize.tsx +35 -0
  398. package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
  399. package/src/react/i18n/hooks/useI18n.ts +18 -0
  400. package/src/react/i18n/index.ts +41 -0
  401. package/src/react/i18n/primitives/$dictionary.ts +69 -0
  402. package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
  403. package/src/react/i18n/providers/I18nProvider.ts +278 -0
  404. package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
  405. package/src/react/router/__tests__/page-head.spec.ts +48 -0
  406. package/src/react/router/__tests__/seo-head.spec.ts +125 -0
  407. package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
  408. package/src/react/router/components/ErrorViewer.tsx +872 -0
  409. package/src/react/router/components/Link.tsx +23 -0
  410. package/src/react/router/components/NestedView.tsx +223 -0
  411. package/src/react/router/components/NotFound.tsx +30 -0
  412. package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
  413. package/src/react/router/contexts/RouterLayerContext.ts +12 -0
  414. package/src/react/router/errors/Redirection.ts +28 -0
  415. package/src/react/router/hooks/useActive.ts +52 -0
  416. package/src/react/router/hooks/useQueryParams.ts +63 -0
  417. package/src/react/router/hooks/useRouter.ts +20 -0
  418. package/src/react/router/hooks/useRouterState.ts +11 -0
  419. package/src/react/router/index.browser.ts +45 -0
  420. package/src/react/router/index.shared.ts +19 -0
  421. package/src/react/router/index.ts +146 -0
  422. package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
  423. package/src/react/router/primitives/$page.spec.tsx +676 -0
  424. package/src/react/router/primitives/$page.ts +489 -0
  425. package/src/react/router/providers/ReactBrowserProvider.ts +312 -0
  426. package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
  427. package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
  428. package/src/react/router/providers/ReactPageProvider.ts +726 -0
  429. package/src/react/router/providers/ReactPreloadProvider.spec.ts +142 -0
  430. package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
  431. package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
  432. package/src/react/router/providers/ReactServerProvider.ts +487 -0
  433. package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
  434. package/src/react/router/providers/ReactServerTemplateProvider.ts +542 -0
  435. package/src/react/router/providers/SSRManifestProvider.ts +334 -0
  436. package/src/react/router/services/ReactPageServerService.ts +48 -0
  437. package/src/react/router/services/ReactPageService.ts +27 -0
  438. package/src/react/router/services/ReactRouter.ts +262 -0
  439. package/src/react/websocket/hooks/useRoom.tsx +242 -0
  440. package/src/react/websocket/index.ts +7 -0
  441. package/src/redis/__tests__/redis.spec.ts +13 -0
  442. package/src/redis/index.ts +9 -25
  443. package/src/redis/providers/BunRedisProvider.ts +9 -0
  444. package/src/redis/providers/NodeRedisProvider.ts +8 -0
  445. package/src/redis/providers/RedisProvider.ts +16 -0
  446. package/src/retry/index.ts +11 -2
  447. package/src/router/index.ts +15 -0
  448. package/src/scheduler/index.ts +11 -2
  449. package/src/security/__tests__/BasicAuth.spec.ts +2 -0
  450. package/src/security/__tests__/ServerSecurityProvider.spec.ts +90 -5
  451. package/src/security/index.ts +15 -10
  452. package/src/security/interfaces/IssuerResolver.ts +27 -0
  453. package/src/security/primitives/$issuer.ts +55 -0
  454. package/src/security/providers/SecurityProvider.ts +179 -0
  455. package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
  456. package/src/security/providers/ServerSecurityProvider.ts +63 -41
  457. package/src/server/auth/index.ts +12 -7
  458. package/src/server/cache/index.ts +7 -22
  459. package/src/server/compress/index.ts +10 -2
  460. package/src/server/cookies/index.ts +7 -5
  461. package/src/server/cookies/primitives/$cookie.ts +33 -11
  462. package/src/server/core/index.ts +16 -6
  463. package/src/server/core/interfaces/ServerRequest.ts +83 -1
  464. package/src/server/core/primitives/$action.spec.ts +1 -1
  465. package/src/server/core/primitives/$action.ts +8 -3
  466. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
  467. package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
  468. package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
  469. package/src/server/core/services/ServerRequestParser.ts +306 -13
  470. package/src/server/cors/index.ts +7 -21
  471. package/src/server/cors/primitives/$cors.ts +6 -2
  472. package/src/server/health/index.ts +8 -2
  473. package/src/server/helmet/index.ts +11 -3
  474. package/src/server/links/index.ts +11 -6
  475. package/src/server/metrics/index.ts +10 -3
  476. package/src/server/multipart/index.ts +9 -3
  477. package/src/server/proxy/index.ts +8 -2
  478. package/src/server/rate-limit/index.ts +21 -25
  479. package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
  480. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
  481. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
  482. package/src/server/static/index.ts +8 -2
  483. package/src/server/static/providers/ServerStaticProvider.ts +1 -1
  484. package/src/server/swagger/index.ts +9 -4
  485. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  486. package/src/sms/index.ts +9 -5
  487. package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
  488. package/src/sms/providers/LocalSmsProvider.ts +1 -1
  489. package/src/system/index.browser.ts +36 -0
  490. package/src/system/index.ts +62 -0
  491. package/src/system/index.workerd.ts +1 -0
  492. package/src/{file → system}/providers/FileSystemProvider.ts +24 -0
  493. package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
  494. package/src/system/providers/MemoryShellProvider.ts +164 -0
  495. package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
  496. package/src/{file → system}/providers/NodeFileSystemProvider.ts +47 -2
  497. package/src/system/providers/NodeShellProvider.ts +184 -0
  498. package/src/system/providers/ShellProvider.ts +74 -0
  499. package/src/{file → system}/services/FileDetector.spec.ts +2 -2
  500. package/src/thread/index.ts +11 -2
  501. package/src/topic/core/index.ts +12 -5
  502. package/src/vite/tasks/buildClient.ts +2 -7
  503. package/src/vite/tasks/buildServer.ts +19 -13
  504. package/src/vite/tasks/generateCloudflare.ts +10 -7
  505. package/src/vite/tasks/generateDocker.ts +4 -0
  506. package/src/websocket/index.ts +12 -8
  507. package/dist/file/index.d.ts.map +0 -1
  508. package/dist/file/index.js.map +0 -1
  509. package/src/cli/assets/apiIndexTs.ts +0 -16
  510. package/src/cli/assets/mainServerTs.ts +0 -24
  511. package/src/cli/assets/webAppRouterTs.ts +0 -16
  512. package/src/cli/assets/webHelloComponentTsx.ts +0 -20
  513. package/src/cli/providers/ViteTemplateProvider.ts +0 -27
  514. package/src/file/index.ts +0 -43
  515. /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
  516. /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
  517. /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
  518. /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
  519. /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
  520. /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
  521. /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
  522. /package/src/{file → system}/errors/FileError.ts +0 -0
  523. /package/src/{file → system}/services/FileDetector.ts +0 -0
@@ -1,12 +1,1854 @@
1
- import { $atom, $hook, $inject, $module, $use, Alepha, AlephaError, KIND, Primitive, createPrimitive, t } from "alepha";
2
- import { FileDetector, FileSystemProvider } from "alepha/file";
3
- import { randomUUID } from "node:crypto";
4
- import { createReadStream } from "node:fs";
5
- import { mkdir, stat, unlink } from "node:fs/promises";
6
- import { tmpdir } from "node:os";
1
+ import { $atom, $hook, $inject, $module, $use, Alepha, AlephaError, Json, KIND, Primitive, createPrimitive, isFileLike, t } from "alepha";
7
2
  import { join } from "node:path";
3
+ import { createReadStream } from "node:fs";
4
+ import { access, copyFile, cp, mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
5
+ import { PassThrough, Readable } from "node:stream";
6
+ import { fileURLToPath } from "node:url";
7
+ import { exec, spawn } from "node:child_process";
8
8
  import { $logger } from "alepha/logger";
9
+ import { randomUUID } from "node:crypto";
10
+ import { tmpdir } from "node:os";
9
11
 
12
+ //#region ../../src/system/providers/FileSystemProvider.ts
13
+ /**
14
+ * FileSystem interface providing utilities for working with files.
15
+ */
16
+ var FileSystemProvider = class {};
17
+
18
+ //#endregion
19
+ //#region ../../src/system/providers/MemoryFileSystemProvider.ts
20
+ /**
21
+ * In-memory implementation of FileSystemProvider for testing.
22
+ *
23
+ * This provider stores all files and directories in memory, making it ideal for
24
+ * unit tests that need to verify file operations without touching the real file system.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // In tests, substitute the real FileSystemProvider with MemoryFileSystemProvider
29
+ * const alepha = Alepha.create().with({
30
+ * provide: FileSystemProvider,
31
+ * use: MemoryFileSystemProvider,
32
+ * });
33
+ *
34
+ * // Run code that uses FileSystemProvider
35
+ * const service = alepha.inject(MyService);
36
+ * await service.saveFile("test.txt", "Hello World");
37
+ *
38
+ * // Verify the file was written
39
+ * const memoryFs = alepha.inject(MemoryFileSystemProvider);
40
+ * expect(memoryFs.files.get("test.txt")?.toString()).toBe("Hello World");
41
+ * ```
42
+ */
43
+ var MemoryFileSystemProvider = class {
44
+ json = $inject(Json);
45
+ /**
46
+ * In-memory storage for files (path -> content)
47
+ */
48
+ files = /* @__PURE__ */ new Map();
49
+ /**
50
+ * In-memory storage for directories
51
+ */
52
+ directories = /* @__PURE__ */ new Set();
53
+ /**
54
+ * Track mkdir calls for test assertions
55
+ */
56
+ mkdirCalls = [];
57
+ /**
58
+ * Track writeFile calls for test assertions
59
+ */
60
+ writeFileCalls = [];
61
+ /**
62
+ * Track readFile calls for test assertions
63
+ */
64
+ readFileCalls = [];
65
+ /**
66
+ * Track rm calls for test assertions
67
+ */
68
+ rmCalls = [];
69
+ /**
70
+ * Track join calls for test assertions
71
+ */
72
+ joinCalls = [];
73
+ /**
74
+ * Error to throw on mkdir (for testing error handling)
75
+ */
76
+ mkdirError = null;
77
+ /**
78
+ * Error to throw on writeFile (for testing error handling)
79
+ */
80
+ writeFileError = null;
81
+ /**
82
+ * Error to throw on readFile (for testing error handling)
83
+ */
84
+ readFileError = null;
85
+ constructor(options = {}) {
86
+ this.mkdirError = options.mkdirError ?? null;
87
+ this.writeFileError = options.writeFileError ?? null;
88
+ this.readFileError = options.readFileError ?? null;
89
+ }
90
+ /**
91
+ * Join path segments using forward slashes.
92
+ * Uses Node's path.join for proper normalization (handles .. and .)
93
+ */
94
+ join(...paths) {
95
+ this.joinCalls.push(paths);
96
+ return join(...paths);
97
+ }
98
+ /**
99
+ * Create a FileLike object from various sources.
100
+ */
101
+ createFile(options) {
102
+ if ("path" in options) {
103
+ const filePath = options.path;
104
+ const buffer = this.files.get(filePath);
105
+ if (buffer === void 0) throw new Error(`ENOENT: no such file or directory, open '${filePath}'`);
106
+ return {
107
+ name: options.name ?? filePath.split("/").pop() ?? "file",
108
+ type: options.type ?? "application/octet-stream",
109
+ size: buffer.byteLength,
110
+ lastModified: Date.now(),
111
+ stream: () => {
112
+ throw new Error("Stream not implemented in MemoryFileSystemProvider");
113
+ },
114
+ arrayBuffer: async () => buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength),
115
+ text: async () => buffer.toString("utf-8")
116
+ };
117
+ }
118
+ if ("buffer" in options) {
119
+ const buffer = options.buffer;
120
+ return {
121
+ name: options.name ?? "file",
122
+ type: options.type ?? "application/octet-stream",
123
+ size: buffer.byteLength,
124
+ lastModified: Date.now(),
125
+ stream: () => {
126
+ throw new Error("Stream not implemented in MemoryFileSystemProvider");
127
+ },
128
+ arrayBuffer: async () => buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength),
129
+ text: async () => buffer.toString("utf-8")
130
+ };
131
+ }
132
+ if ("text" in options) {
133
+ const buffer = Buffer.from(options.text, "utf-8");
134
+ return {
135
+ name: options.name ?? "file.txt",
136
+ type: options.type ?? "text/plain",
137
+ size: buffer.byteLength,
138
+ lastModified: Date.now(),
139
+ stream: () => {
140
+ throw new Error("Stream not implemented in MemoryFileSystemProvider");
141
+ },
142
+ arrayBuffer: async () => buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength),
143
+ text: async () => options.text
144
+ };
145
+ }
146
+ throw new Error("MemoryFileSystemProvider.createFile: unsupported options. Only buffer and text are supported.");
147
+ }
148
+ /**
149
+ * Remove a file or directory from memory.
150
+ */
151
+ async rm(path, options) {
152
+ this.rmCalls.push({
153
+ path,
154
+ options
155
+ });
156
+ if (!(this.files.has(path) || this.directories.has(path)) && !options?.force) throw new Error(`ENOENT: no such file or directory, rm '${path}'`);
157
+ if (this.directories.has(path)) if (options?.recursive) {
158
+ this.directories.delete(path);
159
+ for (const filePath of this.files.keys()) if (filePath.startsWith(`${path}/`)) this.files.delete(filePath);
160
+ for (const dirPath of this.directories) if (dirPath.startsWith(`${path}/`)) this.directories.delete(dirPath);
161
+ } else throw new Error(`EISDIR: illegal operation on a directory, rm '${path}'`);
162
+ else this.files.delete(path);
163
+ }
164
+ /**
165
+ * Copy a file or directory in memory.
166
+ */
167
+ async cp(src, dest, options) {
168
+ if (this.directories.has(src)) {
169
+ if (!options?.recursive) throw new Error(`Cannot copy directory without recursive option: ${src}`);
170
+ this.directories.add(dest);
171
+ for (const [filePath, content] of this.files) if (filePath.startsWith(`${src}/`)) {
172
+ const newPath = filePath.replace(src, dest);
173
+ this.files.set(newPath, Buffer.from(content));
174
+ }
175
+ } else if (this.files.has(src)) {
176
+ const content = this.files.get(src);
177
+ this.files.set(dest, Buffer.from(content));
178
+ } else throw new Error(`ENOENT: no such file or directory, cp '${src}'`);
179
+ }
180
+ /**
181
+ * Move/rename a file or directory in memory.
182
+ */
183
+ async mv(src, dest) {
184
+ if (this.directories.has(src)) {
185
+ this.directories.delete(src);
186
+ this.directories.add(dest);
187
+ for (const [filePath, content] of this.files) if (filePath.startsWith(`${src}/`)) {
188
+ const newPath = filePath.replace(src, dest);
189
+ this.files.delete(filePath);
190
+ this.files.set(newPath, content);
191
+ }
192
+ } else if (this.files.has(src)) {
193
+ const content = this.files.get(src);
194
+ this.files.delete(src);
195
+ this.files.set(dest, content);
196
+ } else throw new Error(`ENOENT: no such file or directory, mv '${src}'`);
197
+ }
198
+ /**
199
+ * Create a directory in memory.
200
+ */
201
+ async mkdir(path, options) {
202
+ this.mkdirCalls.push({
203
+ path,
204
+ options
205
+ });
206
+ if (this.mkdirError) throw this.mkdirError;
207
+ if (this.directories.has(path) && !options?.recursive) throw new Error(`EEXIST: file already exists, mkdir '${path}'`);
208
+ this.directories.add(path);
209
+ if (options?.recursive) {
210
+ const parts = path.split("/").filter(Boolean);
211
+ let current = "";
212
+ for (const part of parts) {
213
+ current = current ? `${current}/${part}` : part;
214
+ this.directories.add(current);
215
+ }
216
+ }
217
+ }
218
+ /**
219
+ * List files in a directory.
220
+ */
221
+ async ls(path, options) {
222
+ const normalizedPath = path.replace(/\/$/, "");
223
+ const entries = /* @__PURE__ */ new Set();
224
+ for (const filePath of this.files.keys()) if (filePath.startsWith(`${normalizedPath}/`)) {
225
+ const relativePath = filePath.slice(normalizedPath.length + 1);
226
+ const parts = relativePath.split("/");
227
+ if (options?.recursive) entries.add(relativePath);
228
+ else entries.add(parts[0]);
229
+ }
230
+ for (const dirPath of this.directories) if (dirPath.startsWith(`${normalizedPath}/`) && dirPath !== normalizedPath) {
231
+ const relativePath = dirPath.slice(normalizedPath.length + 1);
232
+ const parts = relativePath.split("/");
233
+ if (options?.recursive) entries.add(relativePath);
234
+ else if (parts.length === 1) entries.add(parts[0]);
235
+ }
236
+ let result = Array.from(entries);
237
+ if (!options?.hidden) result = result.filter((entry) => !entry.startsWith("."));
238
+ return result.sort();
239
+ }
240
+ /**
241
+ * Check if a file or directory exists in memory.
242
+ */
243
+ async exists(path) {
244
+ return this.files.has(path) || this.directories.has(path);
245
+ }
246
+ /**
247
+ * Read a file from memory.
248
+ */
249
+ async readFile(path) {
250
+ this.readFileCalls.push(path);
251
+ if (this.readFileError) throw this.readFileError;
252
+ const content = this.files.get(path);
253
+ if (!content) throw new Error(`ENOENT: no such file or directory, open '${path}'`);
254
+ return content;
255
+ }
256
+ /**
257
+ * Read a file from memory as text.
258
+ */
259
+ async readTextFile(path) {
260
+ return (await this.readFile(path)).toString("utf-8");
261
+ }
262
+ /**
263
+ * Read a file from memory as JSON.
264
+ */
265
+ async readJsonFile(path) {
266
+ const text = await this.readTextFile(path);
267
+ return this.json.parse(text);
268
+ }
269
+ /**
270
+ * Write a file to memory.
271
+ */
272
+ async writeFile(path, data) {
273
+ const dataStr = typeof data === "string" ? data : data instanceof Buffer || data instanceof Uint8Array ? data.toString("utf-8") : await data.text();
274
+ this.writeFileCalls.push({
275
+ path,
276
+ data: dataStr
277
+ });
278
+ if (this.writeFileError) throw this.writeFileError;
279
+ const buffer = typeof data === "string" ? Buffer.from(data, "utf-8") : data instanceof Buffer ? data : data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(await data.text(), "utf-8");
280
+ this.files.set(path, buffer);
281
+ }
282
+ /**
283
+ * Reset all in-memory state (useful between tests).
284
+ */
285
+ reset() {
286
+ this.files.clear();
287
+ this.directories.clear();
288
+ this.mkdirCalls = [];
289
+ this.writeFileCalls = [];
290
+ this.readFileCalls = [];
291
+ this.rmCalls = [];
292
+ this.joinCalls = [];
293
+ this.mkdirError = null;
294
+ this.writeFileError = null;
295
+ this.readFileError = null;
296
+ }
297
+ /**
298
+ * Check if a file was written during the test.
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * expect(fs.wasWritten("/project/tsconfig.json")).toBe(true);
303
+ * ```
304
+ */
305
+ wasWritten(path) {
306
+ return this.writeFileCalls.some((call) => call.path === path);
307
+ }
308
+ /**
309
+ * Check if a file was written with content matching a pattern.
310
+ *
311
+ * @example
312
+ * ```typescript
313
+ * expect(fs.wasWrittenMatching("/project/tsconfig.json", /extends/)).toBe(true);
314
+ * ```
315
+ */
316
+ wasWrittenMatching(path, pattern) {
317
+ const call = this.writeFileCalls.find((c) => c.path === path);
318
+ return call ? pattern.test(call.data) : false;
319
+ }
320
+ /**
321
+ * Check if a file was read during the test.
322
+ *
323
+ * @example
324
+ * ```typescript
325
+ * expect(fs.wasRead("/project/package.json")).toBe(true);
326
+ * ```
327
+ */
328
+ wasRead(path) {
329
+ return this.readFileCalls.includes(path);
330
+ }
331
+ /**
332
+ * Check if a file was deleted during the test.
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * expect(fs.wasDeleted("/project/old-file.txt")).toBe(true);
337
+ * ```
338
+ */
339
+ wasDeleted(path) {
340
+ return this.rmCalls.some((call) => call.path === path);
341
+ }
342
+ /**
343
+ * Get the content of a file as a string (convenience method for testing).
344
+ */
345
+ getFileContent(path) {
346
+ return this.files.get(path)?.toString("utf-8");
347
+ }
348
+ };
349
+
350
+ //#endregion
351
+ //#region ../../src/system/providers/MemoryShellProvider.ts
352
+ /**
353
+ * In-memory implementation of ShellProvider for testing.
354
+ *
355
+ * Records all commands that would be executed without actually running them.
356
+ * Can be configured to return specific outputs or throw errors for testing.
357
+ *
358
+ * @example
359
+ * ```typescript
360
+ * // In tests, substitute the real ShellProvider with MemoryShellProvider
361
+ * const alepha = Alepha.create().with({
362
+ * provide: ShellProvider,
363
+ * use: MemoryShellProvider,
364
+ * });
365
+ *
366
+ * // Configure mock behavior
367
+ * const shell = alepha.inject(MemoryShellProvider);
368
+ * shell.configure({
369
+ * outputs: { "echo hello": "hello\n" },
370
+ * errors: { "failing-cmd": "Command failed" },
371
+ * });
372
+ *
373
+ * // Or use the fluent API
374
+ * shell.outputs.set("another-cmd", "output");
375
+ * shell.errors.set("another-error", "Error message");
376
+ *
377
+ * // Run code that uses ShellProvider
378
+ * const service = alepha.inject(MyService);
379
+ * await service.doSomething();
380
+ *
381
+ * // Verify commands were called
382
+ * expect(shell.calls).toHaveLength(2);
383
+ * expect(shell.calls[0].command).toBe("yarn install");
384
+ * ```
385
+ */
386
+ var MemoryShellProvider = class {
387
+ /**
388
+ * All recorded shell calls.
389
+ */
390
+ calls = [];
391
+ /**
392
+ * Simulated outputs for specific commands.
393
+ */
394
+ outputs = /* @__PURE__ */ new Map();
395
+ /**
396
+ * Commands that should throw an error.
397
+ */
398
+ errors = /* @__PURE__ */ new Map();
399
+ /**
400
+ * Commands considered installed in the system PATH.
401
+ */
402
+ installedCommands = /* @__PURE__ */ new Set();
403
+ /**
404
+ * Configure the mock with predefined outputs, errors, and installed commands.
405
+ */
406
+ configure(options) {
407
+ if (options.outputs) for (const [cmd, output] of Object.entries(options.outputs)) this.outputs.set(cmd, output);
408
+ if (options.errors) for (const [cmd, error] of Object.entries(options.errors)) this.errors.set(cmd, error);
409
+ if (options.installedCommands) for (const cmd of options.installedCommands) this.installedCommands.add(cmd);
410
+ return this;
411
+ }
412
+ /**
413
+ * Record command and return simulated output.
414
+ */
415
+ async run(command, options = {}) {
416
+ this.calls.push({
417
+ command,
418
+ options
419
+ });
420
+ const errorMsg = this.errors.get(command);
421
+ if (errorMsg) throw new Error(errorMsg);
422
+ return this.outputs.get(command) ?? "";
423
+ }
424
+ /**
425
+ * Check if a specific command was called.
426
+ */
427
+ wasCalled(command) {
428
+ return this.calls.some((call) => call.command === command);
429
+ }
430
+ /**
431
+ * Check if a command matching a pattern was called.
432
+ */
433
+ wasCalledMatching(pattern) {
434
+ return this.calls.some((call) => pattern.test(call.command));
435
+ }
436
+ /**
437
+ * Get all calls matching a pattern.
438
+ */
439
+ getCallsMatching(pattern) {
440
+ return this.calls.filter((call) => pattern.test(call.command));
441
+ }
442
+ /**
443
+ * Check if a command is installed.
444
+ */
445
+ async isInstalled(command) {
446
+ return this.installedCommands.has(command);
447
+ }
448
+ /**
449
+ * Reset all recorded state.
450
+ */
451
+ reset() {
452
+ this.calls = [];
453
+ this.outputs.clear();
454
+ this.errors.clear();
455
+ this.installedCommands.clear();
456
+ }
457
+ };
458
+
459
+ //#endregion
460
+ //#region ../../src/system/services/FileDetector.ts
461
+ /**
462
+ * Service for detecting file types and getting content types.
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * const detector = alepha.inject(FileDetector);
467
+ *
468
+ * // Get content type from filename
469
+ * const mimeType = detector.getContentType("image.png"); // "image/png"
470
+ *
471
+ * // Detect file type by magic bytes
472
+ * const stream = createReadStream('image.png');
473
+ * const result = await detector.detectFileType(stream, 'image.png');
474
+ * console.log(result.mimeType); // 'image/png'
475
+ * console.log(result.verified); // true if magic bytes match
476
+ * ```
477
+ */
478
+ var FileDetector = class FileDetector {
479
+ /**
480
+ * Magic byte signatures for common file formats.
481
+ * Each signature is represented as an array of bytes or null (wildcard).
482
+ */
483
+ static MAGIC_BYTES = {
484
+ png: [{
485
+ signature: [
486
+ 137,
487
+ 80,
488
+ 78,
489
+ 71,
490
+ 13,
491
+ 10,
492
+ 26,
493
+ 10
494
+ ],
495
+ mimeType: "image/png"
496
+ }],
497
+ jpg: [
498
+ {
499
+ signature: [
500
+ 255,
501
+ 216,
502
+ 255,
503
+ 224
504
+ ],
505
+ mimeType: "image/jpeg"
506
+ },
507
+ {
508
+ signature: [
509
+ 255,
510
+ 216,
511
+ 255,
512
+ 225
513
+ ],
514
+ mimeType: "image/jpeg"
515
+ },
516
+ {
517
+ signature: [
518
+ 255,
519
+ 216,
520
+ 255,
521
+ 226
522
+ ],
523
+ mimeType: "image/jpeg"
524
+ },
525
+ {
526
+ signature: [
527
+ 255,
528
+ 216,
529
+ 255,
530
+ 227
531
+ ],
532
+ mimeType: "image/jpeg"
533
+ },
534
+ {
535
+ signature: [
536
+ 255,
537
+ 216,
538
+ 255,
539
+ 232
540
+ ],
541
+ mimeType: "image/jpeg"
542
+ }
543
+ ],
544
+ jpeg: [
545
+ {
546
+ signature: [
547
+ 255,
548
+ 216,
549
+ 255,
550
+ 224
551
+ ],
552
+ mimeType: "image/jpeg"
553
+ },
554
+ {
555
+ signature: [
556
+ 255,
557
+ 216,
558
+ 255,
559
+ 225
560
+ ],
561
+ mimeType: "image/jpeg"
562
+ },
563
+ {
564
+ signature: [
565
+ 255,
566
+ 216,
567
+ 255,
568
+ 226
569
+ ],
570
+ mimeType: "image/jpeg"
571
+ },
572
+ {
573
+ signature: [
574
+ 255,
575
+ 216,
576
+ 255,
577
+ 227
578
+ ],
579
+ mimeType: "image/jpeg"
580
+ },
581
+ {
582
+ signature: [
583
+ 255,
584
+ 216,
585
+ 255,
586
+ 232
587
+ ],
588
+ mimeType: "image/jpeg"
589
+ }
590
+ ],
591
+ gif: [{
592
+ signature: [
593
+ 71,
594
+ 73,
595
+ 70,
596
+ 56,
597
+ 55,
598
+ 97
599
+ ],
600
+ mimeType: "image/gif"
601
+ }, {
602
+ signature: [
603
+ 71,
604
+ 73,
605
+ 70,
606
+ 56,
607
+ 57,
608
+ 97
609
+ ],
610
+ mimeType: "image/gif"
611
+ }],
612
+ webp: [{
613
+ signature: [
614
+ 82,
615
+ 73,
616
+ 70,
617
+ 70,
618
+ null,
619
+ null,
620
+ null,
621
+ null,
622
+ 87,
623
+ 69,
624
+ 66,
625
+ 80
626
+ ],
627
+ mimeType: "image/webp"
628
+ }],
629
+ bmp: [{
630
+ signature: [66, 77],
631
+ mimeType: "image/bmp"
632
+ }],
633
+ ico: [{
634
+ signature: [
635
+ 0,
636
+ 0,
637
+ 1,
638
+ 0
639
+ ],
640
+ mimeType: "image/x-icon"
641
+ }],
642
+ tiff: [{
643
+ signature: [
644
+ 73,
645
+ 73,
646
+ 42,
647
+ 0
648
+ ],
649
+ mimeType: "image/tiff"
650
+ }, {
651
+ signature: [
652
+ 77,
653
+ 77,
654
+ 0,
655
+ 42
656
+ ],
657
+ mimeType: "image/tiff"
658
+ }],
659
+ tif: [{
660
+ signature: [
661
+ 73,
662
+ 73,
663
+ 42,
664
+ 0
665
+ ],
666
+ mimeType: "image/tiff"
667
+ }, {
668
+ signature: [
669
+ 77,
670
+ 77,
671
+ 0,
672
+ 42
673
+ ],
674
+ mimeType: "image/tiff"
675
+ }],
676
+ pdf: [{
677
+ signature: [
678
+ 37,
679
+ 80,
680
+ 68,
681
+ 70,
682
+ 45
683
+ ],
684
+ mimeType: "application/pdf"
685
+ }],
686
+ zip: [
687
+ {
688
+ signature: [
689
+ 80,
690
+ 75,
691
+ 3,
692
+ 4
693
+ ],
694
+ mimeType: "application/zip"
695
+ },
696
+ {
697
+ signature: [
698
+ 80,
699
+ 75,
700
+ 5,
701
+ 6
702
+ ],
703
+ mimeType: "application/zip"
704
+ },
705
+ {
706
+ signature: [
707
+ 80,
708
+ 75,
709
+ 7,
710
+ 8
711
+ ],
712
+ mimeType: "application/zip"
713
+ }
714
+ ],
715
+ rar: [{
716
+ signature: [
717
+ 82,
718
+ 97,
719
+ 114,
720
+ 33,
721
+ 26,
722
+ 7
723
+ ],
724
+ mimeType: "application/vnd.rar"
725
+ }],
726
+ "7z": [{
727
+ signature: [
728
+ 55,
729
+ 122,
730
+ 188,
731
+ 175,
732
+ 39,
733
+ 28
734
+ ],
735
+ mimeType: "application/x-7z-compressed"
736
+ }],
737
+ tar: [{
738
+ signature: [
739
+ 117,
740
+ 115,
741
+ 116,
742
+ 97,
743
+ 114
744
+ ],
745
+ mimeType: "application/x-tar"
746
+ }],
747
+ gz: [{
748
+ signature: [31, 139],
749
+ mimeType: "application/gzip"
750
+ }],
751
+ tgz: [{
752
+ signature: [31, 139],
753
+ mimeType: "application/gzip"
754
+ }],
755
+ mp3: [
756
+ {
757
+ signature: [255, 251],
758
+ mimeType: "audio/mpeg"
759
+ },
760
+ {
761
+ signature: [255, 243],
762
+ mimeType: "audio/mpeg"
763
+ },
764
+ {
765
+ signature: [255, 242],
766
+ mimeType: "audio/mpeg"
767
+ },
768
+ {
769
+ signature: [
770
+ 73,
771
+ 68,
772
+ 51
773
+ ],
774
+ mimeType: "audio/mpeg"
775
+ }
776
+ ],
777
+ wav: [{
778
+ signature: [
779
+ 82,
780
+ 73,
781
+ 70,
782
+ 70,
783
+ null,
784
+ null,
785
+ null,
786
+ null,
787
+ 87,
788
+ 65,
789
+ 86,
790
+ 69
791
+ ],
792
+ mimeType: "audio/wav"
793
+ }],
794
+ ogg: [{
795
+ signature: [
796
+ 79,
797
+ 103,
798
+ 103,
799
+ 83
800
+ ],
801
+ mimeType: "audio/ogg"
802
+ }],
803
+ flac: [{
804
+ signature: [
805
+ 102,
806
+ 76,
807
+ 97,
808
+ 67
809
+ ],
810
+ mimeType: "audio/flac"
811
+ }],
812
+ mp4: [
813
+ {
814
+ signature: [
815
+ null,
816
+ null,
817
+ null,
818
+ null,
819
+ 102,
820
+ 116,
821
+ 121,
822
+ 112
823
+ ],
824
+ mimeType: "video/mp4"
825
+ },
826
+ {
827
+ signature: [
828
+ null,
829
+ null,
830
+ null,
831
+ null,
832
+ 102,
833
+ 116,
834
+ 121,
835
+ 112,
836
+ 105,
837
+ 115,
838
+ 111,
839
+ 109
840
+ ],
841
+ mimeType: "video/mp4"
842
+ },
843
+ {
844
+ signature: [
845
+ null,
846
+ null,
847
+ null,
848
+ null,
849
+ 102,
850
+ 116,
851
+ 121,
852
+ 112,
853
+ 109,
854
+ 112,
855
+ 52,
856
+ 50
857
+ ],
858
+ mimeType: "video/mp4"
859
+ }
860
+ ],
861
+ webm: [{
862
+ signature: [
863
+ 26,
864
+ 69,
865
+ 223,
866
+ 163
867
+ ],
868
+ mimeType: "video/webm"
869
+ }],
870
+ avi: [{
871
+ signature: [
872
+ 82,
873
+ 73,
874
+ 70,
875
+ 70,
876
+ null,
877
+ null,
878
+ null,
879
+ null,
880
+ 65,
881
+ 86,
882
+ 73,
883
+ 32
884
+ ],
885
+ mimeType: "video/x-msvideo"
886
+ }],
887
+ mov: [{
888
+ signature: [
889
+ null,
890
+ null,
891
+ null,
892
+ null,
893
+ 102,
894
+ 116,
895
+ 121,
896
+ 112,
897
+ 113,
898
+ 116,
899
+ 32,
900
+ 32
901
+ ],
902
+ mimeType: "video/quicktime"
903
+ }],
904
+ mkv: [{
905
+ signature: [
906
+ 26,
907
+ 69,
908
+ 223,
909
+ 163
910
+ ],
911
+ mimeType: "video/x-matroska"
912
+ }],
913
+ docx: [{
914
+ signature: [
915
+ 80,
916
+ 75,
917
+ 3,
918
+ 4
919
+ ],
920
+ mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
921
+ }],
922
+ xlsx: [{
923
+ signature: [
924
+ 80,
925
+ 75,
926
+ 3,
927
+ 4
928
+ ],
929
+ mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
930
+ }],
931
+ pptx: [{
932
+ signature: [
933
+ 80,
934
+ 75,
935
+ 3,
936
+ 4
937
+ ],
938
+ mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
939
+ }],
940
+ doc: [{
941
+ signature: [
942
+ 208,
943
+ 207,
944
+ 17,
945
+ 224,
946
+ 161,
947
+ 177,
948
+ 26,
949
+ 225
950
+ ],
951
+ mimeType: "application/msword"
952
+ }],
953
+ xls: [{
954
+ signature: [
955
+ 208,
956
+ 207,
957
+ 17,
958
+ 224,
959
+ 161,
960
+ 177,
961
+ 26,
962
+ 225
963
+ ],
964
+ mimeType: "application/vnd.ms-excel"
965
+ }],
966
+ ppt: [{
967
+ signature: [
968
+ 208,
969
+ 207,
970
+ 17,
971
+ 224,
972
+ 161,
973
+ 177,
974
+ 26,
975
+ 225
976
+ ],
977
+ mimeType: "application/vnd.ms-powerpoint"
978
+ }]
979
+ };
980
+ /**
981
+ * All possible format signatures for checking against actual file content
982
+ */
983
+ static ALL_SIGNATURES = Object.entries(FileDetector.MAGIC_BYTES).flatMap(([ext, signatures]) => signatures.map((sig) => ({
984
+ ext,
985
+ ...sig
986
+ })));
987
+ /**
988
+ * MIME type map for file extensions.
989
+ *
990
+ * Can be used to get the content type of file based on its extension.
991
+ * Feel free to add more mime types in your project!
992
+ */
993
+ static mimeMap = {
994
+ json: "application/json",
995
+ txt: "text/plain",
996
+ html: "text/html",
997
+ htm: "text/html",
998
+ xml: "application/xml",
999
+ csv: "text/csv",
1000
+ pdf: "application/pdf",
1001
+ md: "text/markdown",
1002
+ markdown: "text/markdown",
1003
+ rtf: "application/rtf",
1004
+ css: "text/css",
1005
+ js: "application/javascript",
1006
+ mjs: "application/javascript",
1007
+ ts: "application/typescript",
1008
+ jsx: "text/jsx",
1009
+ tsx: "text/tsx",
1010
+ zip: "application/zip",
1011
+ rar: "application/vnd.rar",
1012
+ "7z": "application/x-7z-compressed",
1013
+ tar: "application/x-tar",
1014
+ gz: "application/gzip",
1015
+ tgz: "application/gzip",
1016
+ png: "image/png",
1017
+ jpg: "image/jpeg",
1018
+ jpeg: "image/jpeg",
1019
+ gif: "image/gif",
1020
+ webp: "image/webp",
1021
+ svg: "image/svg+xml",
1022
+ bmp: "image/bmp",
1023
+ ico: "image/x-icon",
1024
+ tiff: "image/tiff",
1025
+ tif: "image/tiff",
1026
+ mp3: "audio/mpeg",
1027
+ wav: "audio/wav",
1028
+ ogg: "audio/ogg",
1029
+ m4a: "audio/mp4",
1030
+ aac: "audio/aac",
1031
+ flac: "audio/flac",
1032
+ mp4: "video/mp4",
1033
+ webm: "video/webm",
1034
+ avi: "video/x-msvideo",
1035
+ mov: "video/quicktime",
1036
+ wmv: "video/x-ms-wmv",
1037
+ flv: "video/x-flv",
1038
+ mkv: "video/x-matroska",
1039
+ doc: "application/msword",
1040
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1041
+ xls: "application/vnd.ms-excel",
1042
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1043
+ ppt: "application/vnd.ms-powerpoint",
1044
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1045
+ woff: "font/woff",
1046
+ woff2: "font/woff2",
1047
+ ttf: "font/ttf",
1048
+ otf: "font/otf",
1049
+ eot: "application/vnd.ms-fontobject"
1050
+ };
1051
+ /**
1052
+ * Reverse MIME type map for looking up extensions from MIME types.
1053
+ * Prefers shorter, more common extensions when multiple exist.
1054
+ */
1055
+ static reverseMimeMap = (() => {
1056
+ const reverse = {};
1057
+ for (const [ext, mimeType] of Object.entries(FileDetector.mimeMap)) if (!reverse[mimeType]) reverse[mimeType] = ext;
1058
+ return reverse;
1059
+ })();
1060
+ /**
1061
+ * Returns the file extension for a given MIME type.
1062
+ *
1063
+ * @param mimeType - The MIME type to look up
1064
+ * @returns The file extension (without dot), or "bin" if not found
1065
+ *
1066
+ * @example
1067
+ * ```typescript
1068
+ * const detector = alepha.inject(FileDetector);
1069
+ * const ext = detector.getExtensionFromMimeType("image/png"); // "png"
1070
+ * const ext2 = detector.getExtensionFromMimeType("application/octet-stream"); // "bin"
1071
+ * ```
1072
+ */
1073
+ getExtensionFromMimeType(mimeType) {
1074
+ return FileDetector.reverseMimeMap[mimeType] || "bin";
1075
+ }
1076
+ /**
1077
+ * Returns the content type of file based on its filename.
1078
+ *
1079
+ * @param filename - The filename to check
1080
+ * @returns The MIME type
1081
+ *
1082
+ * @example
1083
+ * ```typescript
1084
+ * const detector = alepha.inject(FileDetector);
1085
+ * const mimeType = detector.getContentType("image.png"); // "image/png"
1086
+ * ```
1087
+ */
1088
+ getContentType(filename) {
1089
+ const ext = filename.toLowerCase().split(".").pop() || "";
1090
+ return FileDetector.mimeMap[ext] || "application/octet-stream";
1091
+ }
1092
+ /**
1093
+ * Detects the file type by checking magic bytes against the stream content.
1094
+ *
1095
+ * @param stream - The readable stream to check
1096
+ * @param filename - The filename (used to get the extension)
1097
+ * @returns File type information including MIME type, extension, and verification status
1098
+ *
1099
+ * @example
1100
+ * ```typescript
1101
+ * const detector = alepha.inject(FileDetector);
1102
+ * const stream = createReadStream('image.png');
1103
+ * const result = await detector.detectFileType(stream, 'image.png');
1104
+ * console.log(result.mimeType); // 'image/png'
1105
+ * console.log(result.verified); // true if magic bytes match
1106
+ * ```
1107
+ */
1108
+ async detectFileType(stream, filename) {
1109
+ const expectedMimeType = this.getContentType(filename);
1110
+ const lastDotIndex = filename.lastIndexOf(".");
1111
+ const ext = lastDotIndex > 0 ? filename.substring(lastDotIndex + 1).toLowerCase() : "";
1112
+ const { buffer, stream: newStream } = await this.peekBytes(stream, 16);
1113
+ const expectedSignatures = FileDetector.MAGIC_BYTES[ext];
1114
+ if (expectedSignatures) {
1115
+ for (const { signature, mimeType } of expectedSignatures) if (this.matchesSignature(buffer, signature)) return {
1116
+ mimeType,
1117
+ extension: ext,
1118
+ verified: true,
1119
+ stream: newStream
1120
+ };
1121
+ }
1122
+ for (const { ext: detectedExt, signature, mimeType } of FileDetector.ALL_SIGNATURES) if (detectedExt !== ext && this.matchesSignature(buffer, signature)) return {
1123
+ mimeType,
1124
+ extension: detectedExt,
1125
+ verified: true,
1126
+ stream: newStream
1127
+ };
1128
+ return {
1129
+ mimeType: expectedMimeType,
1130
+ extension: ext,
1131
+ verified: false,
1132
+ stream: newStream
1133
+ };
1134
+ }
1135
+ /**
1136
+ * Reads all bytes from a stream and returns the first N bytes along with a new stream containing all data.
1137
+ * This approach reads the entire stream upfront to avoid complex async handling issues.
1138
+ *
1139
+ * @protected
1140
+ */
1141
+ async peekBytes(stream, numBytes) {
1142
+ const chunks = [];
1143
+ for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1144
+ const allData = Buffer.concat(chunks);
1145
+ return {
1146
+ buffer: allData.subarray(0, numBytes),
1147
+ stream: Readable.from(allData)
1148
+ };
1149
+ }
1150
+ /**
1151
+ * Checks if a buffer matches a magic byte signature.
1152
+ *
1153
+ * @protected
1154
+ */
1155
+ matchesSignature(buffer, signature) {
1156
+ if (buffer.length < signature.length) return false;
1157
+ for (let i = 0; i < signature.length; i++) if (signature[i] !== null && buffer[i] !== signature[i]) return false;
1158
+ return true;
1159
+ }
1160
+ };
1161
+
1162
+ //#endregion
1163
+ //#region ../../src/system/providers/NodeFileSystemProvider.ts
1164
+ /**
1165
+ * Node.js implementation of FileSystem interface.
1166
+ *
1167
+ * @example
1168
+ * ```typescript
1169
+ * const fs = alepha.inject(NodeFileSystemProvider);
1170
+ *
1171
+ * // Create from URL
1172
+ * const file1 = fs.createFile({ url: "file:///path/to/file.png" });
1173
+ *
1174
+ * // Create from Buffer
1175
+ * const file2 = fs.createFile({ buffer: Buffer.from("hello"), name: "hello.txt" });
1176
+ *
1177
+ * // Create from text
1178
+ * const file3 = fs.createFile({ text: "Hello, world!", name: "greeting.txt" });
1179
+ *
1180
+ * // File operations
1181
+ * await fs.mkdir("/tmp/mydir", { recursive: true });
1182
+ * await fs.cp("/src/file.txt", "/dest/file.txt");
1183
+ * await fs.mv("/old/path.txt", "/new/path.txt");
1184
+ * const files = await fs.ls("/tmp");
1185
+ * await fs.rm("/tmp/file.txt");
1186
+ * ```
1187
+ */
1188
+ var NodeFileSystemProvider = class {
1189
+ detector = $inject(FileDetector);
1190
+ json = $inject(Json);
1191
+ join(...paths) {
1192
+ return join(...paths);
1193
+ }
1194
+ /**
1195
+ * Creates a FileLike object from various sources.
1196
+ *
1197
+ * @param options - Options for creating the file
1198
+ * @returns A FileLike object
1199
+ *
1200
+ * @example
1201
+ * ```typescript
1202
+ * const fs = alepha.inject(NodeFileSystemProvider);
1203
+ *
1204
+ * // From URL
1205
+ * const file1 = fs.createFile({ url: "https://example.com/image.png" });
1206
+ *
1207
+ * // From Buffer
1208
+ * const file2 = fs.createFile({
1209
+ * buffer: Buffer.from("hello"),
1210
+ * name: "hello.txt",
1211
+ * type: "text/plain"
1212
+ * });
1213
+ *
1214
+ * // From text
1215
+ * const file3 = fs.createFile({ text: "Hello!", name: "greeting.txt" });
1216
+ *
1217
+ * // From stream with detection
1218
+ * const stream = createReadStream("/path/to/file.png");
1219
+ * const file4 = fs.createFile({ stream, name: "image.png" });
1220
+ * ```
1221
+ */
1222
+ createFile(options) {
1223
+ if ("path" in options) {
1224
+ const path = options.path;
1225
+ const filename = path.split("/").pop() || "file";
1226
+ return this.createFileFromUrl(`file://${path}`, {
1227
+ type: options.type,
1228
+ name: options.name || filename
1229
+ });
1230
+ }
1231
+ if ("url" in options) return this.createFileFromUrl(options.url, {
1232
+ type: options.type,
1233
+ name: options.name
1234
+ });
1235
+ if ("response" in options) {
1236
+ if (!options.response.body) throw new AlephaError("Response has no body stream");
1237
+ const res = options.response;
1238
+ const sizeHeader = res.headers.get("content-length");
1239
+ const size = sizeHeader ? parseInt(sizeHeader, 10) : void 0;
1240
+ let name = options.name;
1241
+ const contentDisposition = res.headers.get("content-disposition");
1242
+ if (contentDisposition && !name) {
1243
+ const match = contentDisposition.match(/filename="?([^"]+)"?/);
1244
+ if (match) name = match[1];
1245
+ }
1246
+ const type = options.type || res.headers.get("content-type") || void 0;
1247
+ return this.createFileFromStream(options.response.body, {
1248
+ type,
1249
+ name,
1250
+ size
1251
+ });
1252
+ }
1253
+ if ("file" in options) return this.createFileFromWebFile(options.file, {
1254
+ type: options.type,
1255
+ name: options.name,
1256
+ size: options.size
1257
+ });
1258
+ if ("buffer" in options) return this.createFileFromBuffer(options.buffer, {
1259
+ type: options.type,
1260
+ name: options.name
1261
+ });
1262
+ if ("arrayBuffer" in options) return this.createFileFromBuffer(Buffer.from(options.arrayBuffer), {
1263
+ type: options.type,
1264
+ name: options.name
1265
+ });
1266
+ if ("text" in options) return this.createFileFromBuffer(Buffer.from(options.text, "utf-8"), {
1267
+ type: options.type || "text/plain",
1268
+ name: options.name || "file.txt"
1269
+ });
1270
+ if ("stream" in options) return this.createFileFromStream(options.stream, {
1271
+ type: options.type,
1272
+ name: options.name,
1273
+ size: options.size
1274
+ });
1275
+ throw new AlephaError("Invalid createFile options: no valid source provided");
1276
+ }
1277
+ /**
1278
+ * Removes a file or directory.
1279
+ *
1280
+ * @param path - The path to remove
1281
+ * @param options - Remove options
1282
+ *
1283
+ * @example
1284
+ * ```typescript
1285
+ * const fs = alepha.inject(NodeFileSystemProvider);
1286
+ *
1287
+ * // Remove a file
1288
+ * await fs.rm("/tmp/file.txt");
1289
+ *
1290
+ * // Remove a directory recursively
1291
+ * await fs.rm("/tmp/mydir", { recursive: true });
1292
+ *
1293
+ * // Remove with force (no error if doesn't exist)
1294
+ * await fs.rm("/tmp/maybe-exists.txt", { force: true });
1295
+ * ```
1296
+ */
1297
+ async rm(path, options) {
1298
+ await rm(path, options);
1299
+ }
1300
+ /**
1301
+ * Copies a file or directory.
1302
+ *
1303
+ * @param src - Source path
1304
+ * @param dest - Destination path
1305
+ * @param options - Copy options
1306
+ *
1307
+ * @example
1308
+ * ```typescript
1309
+ * const fs = alepha.inject(NodeFileSystemProvider);
1310
+ *
1311
+ * // Copy a file
1312
+ * await fs.cp("/src/file.txt", "/dest/file.txt");
1313
+ *
1314
+ * // Copy a directory recursively
1315
+ * await fs.cp("/src/dir", "/dest/dir", { recursive: true });
1316
+ *
1317
+ * // Copy with force (overwrite existing)
1318
+ * await fs.cp("/src/file.txt", "/dest/file.txt", { force: true });
1319
+ * ```
1320
+ */
1321
+ async cp(src, dest, options) {
1322
+ if ((await stat(src)).isDirectory()) {
1323
+ if (!options?.recursive) throw new Error(`Cannot copy directory without recursive option: ${src}`);
1324
+ await cp(src, dest, {
1325
+ recursive: true,
1326
+ force: options?.force ?? false
1327
+ });
1328
+ } else await copyFile(src, dest);
1329
+ }
1330
+ /**
1331
+ * Moves/renames a file or directory.
1332
+ *
1333
+ * @param src - Source path
1334
+ * @param dest - Destination path
1335
+ *
1336
+ * @example
1337
+ * ```typescript
1338
+ * const fs = alepha.inject(NodeFileSystemProvider);
1339
+ *
1340
+ * // Move/rename a file
1341
+ * await fs.mv("/old/path.txt", "/new/path.txt");
1342
+ *
1343
+ * // Move a directory
1344
+ * await fs.mv("/old/dir", "/new/dir");
1345
+ * ```
1346
+ */
1347
+ async mv(src, dest) {
1348
+ await rename(src, dest);
1349
+ }
1350
+ /**
1351
+ * Creates a directory.
1352
+ *
1353
+ * @param path - The directory path to create
1354
+ * @param options - Mkdir options
1355
+ *
1356
+ * @example
1357
+ * ```typescript
1358
+ * const fs = alepha.inject(NodeFileSystemProvider);
1359
+ *
1360
+ * // Create a directory
1361
+ * await fs.mkdir("/tmp/mydir");
1362
+ *
1363
+ * // Create nested directories
1364
+ * await fs.mkdir("/tmp/path/to/dir", { recursive: true });
1365
+ *
1366
+ * // Create with specific permissions
1367
+ * await fs.mkdir("/tmp/mydir", { mode: 0o755 });
1368
+ * ```
1369
+ */
1370
+ async mkdir(path, options = {}) {
1371
+ const p = mkdir(path, {
1372
+ recursive: options.recursive ?? true,
1373
+ mode: options.mode
1374
+ });
1375
+ if (options.force === false) await p;
1376
+ else await p.catch(() => {});
1377
+ }
1378
+ /**
1379
+ * Lists files in a directory.
1380
+ *
1381
+ * @param path - The directory path to list
1382
+ * @param options - List options
1383
+ * @returns Array of filenames
1384
+ *
1385
+ * @example
1386
+ * ```typescript
1387
+ * const fs = alepha.inject(NodeFileSystemProvider);
1388
+ *
1389
+ * // List files in a directory
1390
+ * const files = await fs.ls("/tmp");
1391
+ * console.log(files); // ["file1.txt", "file2.txt", "subdir"]
1392
+ *
1393
+ * // List with hidden files
1394
+ * const allFiles = await fs.ls("/tmp", { hidden: true });
1395
+ *
1396
+ * // List recursively
1397
+ * const allFilesRecursive = await fs.ls("/tmp", { recursive: true });
1398
+ * ```
1399
+ */
1400
+ async ls(path, options) {
1401
+ const entries = await readdir(path);
1402
+ const filteredEntries = options?.hidden ? entries : entries.filter((e) => !e.startsWith("."));
1403
+ if (options?.recursive) {
1404
+ const allFiles = [];
1405
+ for (const entry of filteredEntries) {
1406
+ const fullPath = join(path, entry);
1407
+ if ((await stat(fullPath)).isDirectory()) {
1408
+ allFiles.push(entry);
1409
+ const subFiles = await this.ls(fullPath, options);
1410
+ allFiles.push(...subFiles.map((f) => join(entry, f)));
1411
+ } else allFiles.push(entry);
1412
+ }
1413
+ return allFiles;
1414
+ }
1415
+ return filteredEntries;
1416
+ }
1417
+ /**
1418
+ * Checks if a file or directory exists.
1419
+ *
1420
+ * @param path - The path to check
1421
+ * @returns True if the path exists, false otherwise
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * const fs = alepha.inject(NodeFileSystemProvider);
1426
+ *
1427
+ * if (await fs.exists("/tmp/file.txt")) {
1428
+ * console.log("File exists");
1429
+ * }
1430
+ * ```
1431
+ */
1432
+ async exists(path) {
1433
+ try {
1434
+ await access(path);
1435
+ return true;
1436
+ } catch {
1437
+ return false;
1438
+ }
1439
+ }
1440
+ /**
1441
+ * Reads the content of a file.
1442
+ *
1443
+ * @param path - The file path to read
1444
+ * @returns The file content as a Buffer
1445
+ *
1446
+ * @example
1447
+ * ```typescript
1448
+ * const fs = alepha.inject(NodeFileSystemProvider);
1449
+ *
1450
+ * const buffer = await fs.readFile("/tmp/file.txt");
1451
+ * console.log(buffer.toString("utf-8"));
1452
+ * ```
1453
+ */
1454
+ async readFile(path) {
1455
+ return await readFile(path);
1456
+ }
1457
+ /**
1458
+ * Writes data to a file.
1459
+ *
1460
+ * @param path - The file path to write to
1461
+ * @param data - The data to write (Buffer or string)
1462
+ *
1463
+ * @example
1464
+ * ```typescript
1465
+ * const fs = alepha.inject(NodeFileSystemProvider);
1466
+ *
1467
+ * // Write string
1468
+ * await fs.writeFile("/tmp/file.txt", "Hello, world!");
1469
+ *
1470
+ * // Write Buffer
1471
+ * await fs.writeFile("/tmp/file.bin", Buffer.from([0x01, 0x02, 0x03]));
1472
+ * ```
1473
+ */
1474
+ async writeFile(path, data) {
1475
+ if (isFileLike(data)) {
1476
+ await writeFile(path, Readable.from(data.stream()));
1477
+ return;
1478
+ }
1479
+ await writeFile(path, data);
1480
+ }
1481
+ /**
1482
+ * Reads the content of a file as a string.
1483
+ *
1484
+ * @param path - The file path to read
1485
+ * @returns The file content as a string
1486
+ *
1487
+ * @example
1488
+ * ```typescript
1489
+ * const fs = alepha.inject(NodeFileSystemProvider);
1490
+ * const content = await fs.readTextFile("/tmp/file.txt");
1491
+ * ```
1492
+ */
1493
+ async readTextFile(path) {
1494
+ return (await this.readFile(path)).toString("utf-8");
1495
+ }
1496
+ /**
1497
+ * Reads the content of a file as JSON.
1498
+ *
1499
+ * @param path - The file path to read
1500
+ * @returns The parsed JSON content
1501
+ *
1502
+ * @example
1503
+ * ```typescript
1504
+ * const fs = alepha.inject(NodeFileSystemProvider);
1505
+ * const config = await fs.readJsonFile<{ name: string }>("/tmp/config.json");
1506
+ * ```
1507
+ */
1508
+ async readJsonFile(path) {
1509
+ const text = await this.readTextFile(path);
1510
+ return this.json.parse(text);
1511
+ }
1512
+ /**
1513
+ * Creates a FileLike object from a Web File.
1514
+ *
1515
+ * @protected
1516
+ */
1517
+ createFileFromWebFile(source, options = {}) {
1518
+ const name = options.name ?? source.name;
1519
+ return {
1520
+ name,
1521
+ type: options.type ?? (source.type || this.detector.getContentType(name)),
1522
+ size: options.size ?? source.size ?? 0,
1523
+ lastModified: source.lastModified || Date.now(),
1524
+ stream: () => source.stream(),
1525
+ arrayBuffer: async () => {
1526
+ return await source.arrayBuffer();
1527
+ },
1528
+ text: async () => {
1529
+ return await source.text();
1530
+ }
1531
+ };
1532
+ }
1533
+ /**
1534
+ * Creates a FileLike object from a Buffer.
1535
+ *
1536
+ * @protected
1537
+ */
1538
+ createFileFromBuffer(source, options = {}) {
1539
+ const name = options.name ?? "file";
1540
+ return {
1541
+ name,
1542
+ type: options.type ?? this.detector.getContentType(options.name ?? name),
1543
+ size: source.byteLength,
1544
+ lastModified: Date.now(),
1545
+ stream: () => Readable.from(source),
1546
+ arrayBuffer: async () => {
1547
+ return this.bufferToArrayBuffer(source);
1548
+ },
1549
+ text: async () => {
1550
+ return source.toString("utf-8");
1551
+ }
1552
+ };
1553
+ }
1554
+ /**
1555
+ * Creates a FileLike object from a stream.
1556
+ *
1557
+ * @protected
1558
+ */
1559
+ createFileFromStream(source, options = {}) {
1560
+ let buffer = null;
1561
+ return {
1562
+ name: options.name ?? "file",
1563
+ type: options.type ?? this.detector.getContentType(options.name ?? "file"),
1564
+ size: options.size ?? 0,
1565
+ lastModified: Date.now(),
1566
+ stream: () => source,
1567
+ _buffer: null,
1568
+ arrayBuffer: async () => {
1569
+ buffer ??= await this.streamToBuffer(source);
1570
+ return this.bufferToArrayBuffer(buffer);
1571
+ },
1572
+ text: async () => {
1573
+ buffer ??= await this.streamToBuffer(source);
1574
+ return buffer.toString("utf-8");
1575
+ }
1576
+ };
1577
+ }
1578
+ /**
1579
+ * Creates a FileLike object from a URL.
1580
+ *
1581
+ * @protected
1582
+ */
1583
+ createFileFromUrl(url, options = {}) {
1584
+ const parsedUrl = new URL(url);
1585
+ const filename = options.name || parsedUrl.pathname.split("/").pop() || "file";
1586
+ let buffer = null;
1587
+ return {
1588
+ name: filename,
1589
+ type: options.type ?? this.detector.getContentType(filename),
1590
+ size: 0,
1591
+ lastModified: Date.now(),
1592
+ stream: () => this.createStreamFromUrl(url),
1593
+ arrayBuffer: async () => {
1594
+ buffer ??= await this.loadFromUrl(url);
1595
+ return this.bufferToArrayBuffer(buffer);
1596
+ },
1597
+ text: async () => {
1598
+ buffer ??= await this.loadFromUrl(url);
1599
+ return buffer.toString("utf-8");
1600
+ },
1601
+ filepath: url
1602
+ };
1603
+ }
1604
+ /**
1605
+ * Gets a streaming response from a URL.
1606
+ *
1607
+ * @protected
1608
+ */
1609
+ getStreamingResponse(url) {
1610
+ const stream = new PassThrough();
1611
+ fetch(url).then((res) => Readable.fromWeb(res.body).pipe(stream)).catch((err) => stream.destroy(err));
1612
+ return stream;
1613
+ }
1614
+ /**
1615
+ * Loads data from a URL.
1616
+ *
1617
+ * @protected
1618
+ */
1619
+ async loadFromUrl(url) {
1620
+ const parsedUrl = new URL(url);
1621
+ if (parsedUrl.protocol === "file:") return await readFile(fileURLToPath(url));
1622
+ else if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") {
1623
+ const response = await fetch(url);
1624
+ if (!response.ok) throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
1625
+ const arrayBuffer = await response.arrayBuffer();
1626
+ return Buffer.from(arrayBuffer);
1627
+ } else throw new Error(`Unsupported protocol: ${parsedUrl.protocol}`);
1628
+ }
1629
+ /**
1630
+ * Creates a stream from a URL.
1631
+ *
1632
+ * @protected
1633
+ */
1634
+ createStreamFromUrl(url) {
1635
+ const parsedUrl = new URL(url);
1636
+ if (parsedUrl.protocol === "file:") return createReadStream(fileURLToPath(url));
1637
+ else if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") return this.getStreamingResponse(url);
1638
+ else throw new AlephaError(`Unsupported protocol: ${parsedUrl.protocol}`);
1639
+ }
1640
+ /**
1641
+ * Converts a stream-like object to a Buffer.
1642
+ *
1643
+ * @protected
1644
+ */
1645
+ async streamToBuffer(streamLike) {
1646
+ const stream = streamLike instanceof Readable ? streamLike : Readable.fromWeb(streamLike);
1647
+ return new Promise((resolve, reject) => {
1648
+ const buffer = [];
1649
+ stream.on("data", (chunk) => buffer.push(Buffer.from(chunk)));
1650
+ stream.on("end", () => resolve(Buffer.concat(buffer)));
1651
+ stream.on("error", (err) => reject(new AlephaError("Error converting stream", { cause: err })));
1652
+ });
1653
+ }
1654
+ /**
1655
+ * Converts a Node.js Buffer to an ArrayBuffer.
1656
+ *
1657
+ * @protected
1658
+ */
1659
+ bufferToArrayBuffer(buffer) {
1660
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
1661
+ }
1662
+ };
1663
+
1664
+ //#endregion
1665
+ //#region ../../src/system/providers/NodeShellProvider.ts
1666
+ /**
1667
+ * Node.js implementation of ShellProvider.
1668
+ *
1669
+ * Executes shell commands using Node.js child_process module.
1670
+ * Supports binary resolution from node_modules/.bin for local packages.
1671
+ */
1672
+ var NodeShellProvider = class {
1673
+ log = $logger();
1674
+ fs = $inject(FileSystemProvider);
1675
+ /**
1676
+ * Run a shell command or binary.
1677
+ */
1678
+ async run(command, options = {}) {
1679
+ const { resolve = false, capture = false, root, env } = options;
1680
+ const cwd = root ?? process.cwd();
1681
+ this.log.debug(`Shell: ${command}`, {
1682
+ cwd,
1683
+ resolve,
1684
+ capture
1685
+ });
1686
+ let executable;
1687
+ let args;
1688
+ if (resolve) {
1689
+ const [bin, ...rest] = command.split(" ");
1690
+ executable = await this.resolveExecutable(bin, cwd);
1691
+ args = rest;
1692
+ } else [executable, ...args] = command.split(" ");
1693
+ if (capture) return this.execCapture(command, {
1694
+ cwd,
1695
+ env
1696
+ });
1697
+ return this.execInherit(executable, args, {
1698
+ cwd,
1699
+ env
1700
+ });
1701
+ }
1702
+ /**
1703
+ * Execute command with inherited stdio (streams to terminal).
1704
+ */
1705
+ async execInherit(executable, args, options) {
1706
+ const proc = spawn(executable, args, {
1707
+ stdio: "inherit",
1708
+ cwd: options.cwd,
1709
+ env: {
1710
+ ...process.env,
1711
+ ...options.env
1712
+ }
1713
+ });
1714
+ return new Promise((resolve, reject) => {
1715
+ proc.on("exit", (code) => {
1716
+ if (code === 0 || code === null) resolve("");
1717
+ else reject(new AlephaError(`Command exited with code ${code}`));
1718
+ });
1719
+ proc.on("error", reject);
1720
+ });
1721
+ }
1722
+ /**
1723
+ * Execute command and capture stdout.
1724
+ */
1725
+ execCapture(command, options) {
1726
+ return new Promise((resolve, reject) => {
1727
+ exec(command, {
1728
+ cwd: options.cwd,
1729
+ env: {
1730
+ ...process.env,
1731
+ LOG_FORMAT: "pretty",
1732
+ ...options.env
1733
+ }
1734
+ }, (err, stdout) => {
1735
+ if (err) {
1736
+ err.stdout = stdout;
1737
+ reject(err);
1738
+ } else resolve(stdout);
1739
+ });
1740
+ });
1741
+ }
1742
+ /**
1743
+ * Resolve executable path from node_modules/.bin.
1744
+ *
1745
+ * Search order:
1746
+ * 1. Local: node_modules/.bin/
1747
+ * 2. Pnpm nested: node_modules/alepha/node_modules/.bin/
1748
+ * 3. Monorepo: Walk up to 3 parent directories
1749
+ */
1750
+ async resolveExecutable(name, root) {
1751
+ const suffix = process.platform === "win32" ? ".cmd" : "";
1752
+ let execPath = await this.findExecutable(root, `node_modules/.bin/${name}${suffix}`);
1753
+ if (!execPath) execPath = await this.findExecutable(root, `node_modules/alepha/node_modules/.bin/${name}${suffix}`);
1754
+ if (!execPath) {
1755
+ let parentDir = this.fs.join(root, "..");
1756
+ for (let i = 0; i < 3; i++) {
1757
+ execPath = await this.findExecutable(parentDir, `node_modules/.bin/${name}${suffix}`);
1758
+ if (execPath) break;
1759
+ parentDir = this.fs.join(parentDir, "..");
1760
+ }
1761
+ }
1762
+ if (!execPath) throw new AlephaError(`Could not find executable for '${name}'. Make sure the package is installed.`);
1763
+ return execPath;
1764
+ }
1765
+ /**
1766
+ * Check if executable exists at path.
1767
+ */
1768
+ async findExecutable(root, relativePath) {
1769
+ const fullPath = this.fs.join(root, relativePath);
1770
+ if (await this.fs.exists(fullPath)) return fullPath;
1771
+ }
1772
+ /**
1773
+ * Check if a command is installed and available in the system PATH.
1774
+ */
1775
+ isInstalled(command) {
1776
+ return new Promise((resolve) => {
1777
+ exec(process.platform === "win32" ? `where ${command}` : `command -v ${command}`, (error) => resolve(!error));
1778
+ });
1779
+ }
1780
+ };
1781
+
1782
+ //#endregion
1783
+ //#region ../../src/system/providers/ShellProvider.ts
1784
+ /**
1785
+ * Abstract provider for executing shell commands and binaries.
1786
+ *
1787
+ * Implementations:
1788
+ * - `NodeShellProvider` - Real shell execution using Node.js child_process
1789
+ * - `MemoryShellProvider` - In-memory mock for testing
1790
+ *
1791
+ * @example
1792
+ * ```typescript
1793
+ * class MyService {
1794
+ * protected readonly shell = $inject(ShellProvider);
1795
+ *
1796
+ * async build() {
1797
+ * // Run shell command directly
1798
+ * await this.shell.run("yarn install");
1799
+ *
1800
+ * // Run local binary with resolution
1801
+ * await this.shell.run("vite build", { resolve: true });
1802
+ *
1803
+ * // Capture output
1804
+ * const output = await this.shell.run("echo hello", { capture: true });
1805
+ * }
1806
+ * }
1807
+ * ```
1808
+ */
1809
+ var ShellProvider = class {};
1810
+
1811
+ //#endregion
1812
+ //#region ../../src/system/index.ts
1813
+ /**
1814
+ * | type | quality | stability |
1815
+ * |------|---------|-----------|
1816
+ * | tooling | standard | stable |
1817
+ *
1818
+ * System-level abstractions for portable code across runtimes.
1819
+ *
1820
+ * **Features:**
1821
+ * - File system operations (read, write, exists, etc.)
1822
+ * - Shell command execution
1823
+ * - File type detection and MIME utilities
1824
+ * - Memory implementations for testing
1825
+ *
1826
+ * @module alepha.system
1827
+ */
1828
+ const AlephaSystem = $module({
1829
+ name: "alepha.system",
1830
+ primitives: [],
1831
+ services: [
1832
+ FileDetector,
1833
+ FileSystemProvider,
1834
+ MemoryFileSystemProvider,
1835
+ NodeFileSystemProvider,
1836
+ ShellProvider,
1837
+ MemoryShellProvider,
1838
+ NodeShellProvider
1839
+ ],
1840
+ register: (alepha) => alepha.with({
1841
+ optional: true,
1842
+ provide: FileSystemProvider,
1843
+ use: NodeFileSystemProvider
1844
+ }).with({
1845
+ optional: true,
1846
+ provide: ShellProvider,
1847
+ use: alepha.isTest() ? MemoryShellProvider : NodeShellProvider
1848
+ })
1849
+ });
1850
+
1851
+ //#endregion
10
1852
  //#region ../../src/bucket/errors/InvalidFileError.ts
11
1853
  var InvalidFileError = class extends Error {
12
1854
  status = 400;
@@ -266,14 +2108,21 @@ var LocalFileStorageProvider = class {
266
2108
  //#endregion
267
2109
  //#region ../../src/bucket/index.ts
268
2110
  /**
269
- * Provides file storage capabilities through declarative bucket primitives with support for multiple storage backends.
2111
+ * | type | quality | stability |
2112
+ * |------|---------|-----------|
2113
+ * | backend | rare | stable |
2114
+ *
2115
+ * Unified file storage abstraction across multiple backends.
270
2116
  *
271
- * The bucket module enables unified file operations across different storage systems using the `$bucket` primitive
272
- * on class properties. It abstracts storage provider differences, offering consistent APIs for local filesystem,
273
- * cloud storage, or in-memory storage for testing environments.
2117
+ * **Features:**
2118
+ * - File storage buckets with constraints
2119
+ * - Unified API across all storage backends
2120
+ * - MIME type validation
2121
+ * - File size limits
2122
+ * - Upload/download/delete operations
2123
+ * - TTL-based file expiration
2124
+ * - Providers: Memory (testing), Local filesystem, AWS S3 / Cloudflare R2 / MinIO, Azure Blob Storage, Vercel Blob
274
2125
  *
275
- * @see {@link $bucket}
276
- * @see {@link FileStorageProvider}
277
2126
  * @module alepha.bucket
278
2127
  */
279
2128
  const AlephaBucket = $module({