@stacksjs/defaults 0.70.207 → 0.70.208

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 (408) hide show
  1. package/TODO.md +21 -0
  2. package/ai/AGENTS.md +79 -0
  3. package/ai/README.md +45 -0
  4. package/ai/claude/launch.json +12 -0
  5. package/ai/skills/stacks-actions/SKILL.md +128 -0
  6. package/ai/skills/stacks-ai/SKILL.md +276 -0
  7. package/ai/skills/stacks-alias/SKILL.md +94 -0
  8. package/ai/skills/stacks-analytics/SKILL.md +91 -0
  9. package/ai/skills/stacks-api/SKILL.md +738 -0
  10. package/ai/skills/stacks-arrays/SKILL.md +277 -0
  11. package/ai/skills/stacks-auth/SKILL.md +422 -0
  12. package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
  13. package/ai/skills/stacks-brandkit/SKILL.md +811 -0
  14. package/ai/skills/stacks-browse/SKILL.md +127 -0
  15. package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
  16. package/ai/skills/stacks-browser/SKILL.md +145 -0
  17. package/ai/skills/stacks-buddy/SKILL.md +676 -0
  18. package/ai/skills/stacks-build/SKILL.md +163 -0
  19. package/ai/skills/stacks-cache/SKILL.md +125 -0
  20. package/ai/skills/stacks-calendar/SKILL.md +113 -0
  21. package/ai/skills/stacks-chat/SKILL.md +371 -0
  22. package/ai/skills/stacks-cli/SKILL.md +112 -0
  23. package/ai/skills/stacks-cloud/SKILL.md +192 -0
  24. package/ai/skills/stacks-cms/SKILL.md +217 -0
  25. package/ai/skills/stacks-collections/SKILL.md +82 -0
  26. package/ai/skills/stacks-commerce/SKILL.md +114 -0
  27. package/ai/skills/stacks-composables/SKILL.md +161 -0
  28. package/ai/skills/stacks-config/SKILL.md +144 -0
  29. package/ai/skills/stacks-configuration/SKILL.md +154 -0
  30. package/ai/skills/stacks-cron/SKILL.md +123 -0
  31. package/ai/skills/stacks-crosswind/SKILL.md +190 -0
  32. package/ai/skills/stacks-dashboard/SKILL.md +173 -0
  33. package/ai/skills/stacks-database/SKILL.md +286 -0
  34. package/ai/skills/stacks-datetime/SKILL.md +269 -0
  35. package/ai/skills/stacks-dependencies/SKILL.md +111 -0
  36. package/ai/skills/stacks-deploy/SKILL.md +102 -0
  37. package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
  38. package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
  39. package/ai/skills/stacks-design-output/SKILL.md +55 -0
  40. package/ai/skills/stacks-design-soft/SKILL.md +156 -0
  41. package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
  42. package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
  43. package/ai/skills/stacks-desktop/SKILL.md +78 -0
  44. package/ai/skills/stacks-development/SKILL.md +298 -0
  45. package/ai/skills/stacks-dns/SKILL.md +149 -0
  46. package/ai/skills/stacks-docs/SKILL.md +109 -0
  47. package/ai/skills/stacks-email/SKILL.md +236 -0
  48. package/ai/skills/stacks-enums/SKILL.md +100 -0
  49. package/ai/skills/stacks-env/SKILL.md +181 -0
  50. package/ai/skills/stacks-error-handling/SKILL.md +137 -0
  51. package/ai/skills/stacks-events/SKILL.md +228 -0
  52. package/ai/skills/stacks-faker/SKILL.md +158 -0
  53. package/ai/skills/stacks-git/SKILL.md +158 -0
  54. package/ai/skills/stacks-guard/SKILL.md +98 -0
  55. package/ai/skills/stacks-health/SKILL.md +75 -0
  56. package/ai/skills/stacks-http/SKILL.md +316 -0
  57. package/ai/skills/stacks-i18n/SKILL.md +198 -0
  58. package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
  59. package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
  60. package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
  61. package/ai/skills/stacks-investigate/SKILL.md +119 -0
  62. package/ai/skills/stacks-jobs/SKILL.md +136 -0
  63. package/ai/skills/stacks-lint/SKILL.md +184 -0
  64. package/ai/skills/stacks-listeners/SKILL.md +99 -0
  65. package/ai/skills/stacks-logging/SKILL.md +78 -0
  66. package/ai/skills/stacks-mail/SKILL.md +120 -0
  67. package/ai/skills/stacks-middleware/SKILL.md +249 -0
  68. package/ai/skills/stacks-migrations/SKILL.md +105 -0
  69. package/ai/skills/stacks-models/SKILL.md +267 -0
  70. package/ai/skills/stacks-new-feature/SKILL.md +206 -0
  71. package/ai/skills/stacks-notifications/SKILL.md +210 -0
  72. package/ai/skills/stacks-objects/SKILL.md +205 -0
  73. package/ai/skills/stacks-office-hours/SKILL.md +134 -0
  74. package/ai/skills/stacks-orm/SKILL.md +342 -0
  75. package/ai/skills/stacks-path/SKILL.md +118 -0
  76. package/ai/skills/stacks-payments/SKILL.md +373 -0
  77. package/ai/skills/stacks-plan-review/SKILL.md +152 -0
  78. package/ai/skills/stacks-plugins/SKILL.md +149 -0
  79. package/ai/skills/stacks-push/SKILL.md +376 -0
  80. package/ai/skills/stacks-query-builder/SKILL.md +128 -0
  81. package/ai/skills/stacks-queue/SKILL.md +559 -0
  82. package/ai/skills/stacks-realtime/SKILL.md +442 -0
  83. package/ai/skills/stacks-redesign/SKILL.md +182 -0
  84. package/ai/skills/stacks-registry/SKILL.md +58 -0
  85. package/ai/skills/stacks-repl/SKILL.md +80 -0
  86. package/ai/skills/stacks-retro/SKILL.md +122 -0
  87. package/ai/skills/stacks-review/SKILL.md +135 -0
  88. package/ai/skills/stacks-router/SKILL.md +231 -0
  89. package/ai/skills/stacks-routes/SKILL.md +105 -0
  90. package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
  91. package/ai/skills/stacks-scheduler/SKILL.md +363 -0
  92. package/ai/skills/stacks-search-engine/SKILL.md +112 -0
  93. package/ai/skills/stacks-security/SKILL.md +129 -0
  94. package/ai/skills/stacks-security-audit/SKILL.md +128 -0
  95. package/ai/skills/stacks-server/SKILL.md +458 -0
  96. package/ai/skills/stacks-shell/SKILL.md +62 -0
  97. package/ai/skills/stacks-slug/SKILL.md +87 -0
  98. package/ai/skills/stacks-sms/SKILL.md +385 -0
  99. package/ai/skills/stacks-socials/SKILL.md +303 -0
  100. package/ai/skills/stacks-storage/SKILL.md +576 -0
  101. package/ai/skills/stacks-strings/SKILL.md +416 -0
  102. package/ai/skills/stacks-stx/SKILL.md +176 -0
  103. package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
  104. package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
  105. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
  106. package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
  107. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
  108. package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
  109. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
  110. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
  111. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
  112. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
  113. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
  114. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
  115. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
  116. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
  117. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
  118. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
  119. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
  120. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
  121. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
  122. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
  123. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
  124. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
  125. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
  126. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
  127. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
  128. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
  129. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
  130. package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
  131. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
  132. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
  133. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
  134. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
  135. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
  136. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
  137. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
  138. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
  139. package/ai/skills/stacks-testing/SKILL.md +129 -0
  140. package/ai/skills/stacks-tunnel/SKILL.md +125 -0
  141. package/ai/skills/stacks-types/SKILL.md +178 -0
  142. package/ai/skills/stacks-ui/SKILL.md +246 -0
  143. package/ai/skills/stacks-utils/SKILL.md +444 -0
  144. package/ai/skills/stacks-validation/SKILL.md +371 -0
  145. package/ai/skills/stacks-whois/SKILL.md +315 -0
  146. package/assets/world-map-data.ts +121 -0
  147. package/bootstrap.ts +114 -0
  148. package/docs/api-examples.md +46 -0
  149. package/docs/index.md +24 -0
  150. package/docs/markdown-examples.md +87 -0
  151. package/functions/analytics.ts +97 -0
  152. package/functions/api.ts +143 -0
  153. package/functions/auth.ts +208 -0
  154. package/functions/billing/payments.ts +149 -0
  155. package/functions/blog.ts +120 -0
  156. package/functions/cms/categorizables.ts +107 -0
  157. package/functions/cms/pages.ts +108 -0
  158. package/functions/cms/posts.ts +100 -0
  159. package/functions/cms/taggables.ts +102 -0
  160. package/functions/commerce/coupons.ts +128 -0
  161. package/functions/commerce/customers.ts +128 -0
  162. package/functions/commerce/gift-cards.ts +119 -0
  163. package/functions/commerce/orders.ts +112 -0
  164. package/functions/commerce/payments.ts +119 -0
  165. package/functions/commerce/products/categories.ts +123 -0
  166. package/functions/commerce/products/manufacturers.ts +123 -0
  167. package/functions/commerce/products/products.ts +123 -0
  168. package/functions/commerce/products/reviews.ts +123 -0
  169. package/functions/commerce/products/units.ts +123 -0
  170. package/functions/commerce/products/variants.ts +123 -0
  171. package/functions/commerce/shippings/delivery-routes.ts +123 -0
  172. package/functions/commerce/shippings/digital-deliveries.ts +119 -0
  173. package/functions/commerce/shippings/drivers.ts +123 -0
  174. package/functions/commerce/shippings/license-keys.ts +123 -0
  175. package/functions/commerce/shippings/shipping-methods.ts +123 -0
  176. package/functions/commerce/shippings/shipping-rates.ts +119 -0
  177. package/functions/commerce/shippings/shipping-zones.ts +119 -0
  178. package/functions/commerce/taxes.ts +119 -0
  179. package/functions/commerce/waitlist/products.ts +123 -0
  180. package/functions/commerce/waitlist/restaurants.ts +123 -0
  181. package/functions/craft.ts +107 -0
  182. package/functions/dashboard.ts +153 -0
  183. package/functions/inbox.ts +95 -0
  184. package/functions/jobs.ts +86 -0
  185. package/functions/monitoring/errors.ts +295 -0
  186. package/functions/queue.ts +111 -0
  187. package/functions/realtime/websockets.ts +96 -0
  188. package/functions/realtime.ts +52 -0
  189. package/functions/releases.ts +49 -0
  190. package/functions/search.ts +126 -0
  191. package/functions/toasts.ts +95 -0
  192. package/functions/uploads.ts +216 -0
  193. package/ide/.gitignore +4 -0
  194. package/ide/cursor/rules/auto-imports.mdc +574 -0
  195. package/ide/cursor/rules/code-style.mdc +12 -0
  196. package/ide/cursor/rules/documentation.mdc +9 -0
  197. package/ide/cursor/rules/error-handling-validation.mdc +11 -0
  198. package/ide/cursor/rules/key-conventions.mdc +11 -0
  199. package/ide/cursor/rules/project-structure.mdc +169 -0
  200. package/ide/cursor/rules/readme.mdc +318 -0
  201. package/ide/cursor/rules/syntax-formatting.mdc +9 -0
  202. package/ide/cursor/rules/testing.mdc +10 -0
  203. package/ide/cursor/rules/typescript.mdc +9 -0
  204. package/ide/cursor/rules/ui-styling.mdc +0 -0
  205. package/ide/dictionary.txt +397 -0
  206. package/ide/jetbrains/.fleet/settings.json +4 -0
  207. package/ide/jetbrains/.idea/.gitignore +5 -0
  208. package/ide/jetbrains/.idea/.name +1 -0
  209. package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
  210. package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
  211. package/ide/jetbrains/.idea/modules.xml +8 -0
  212. package/ide/jetbrains/.idea/stacks.iml +22 -0
  213. package/ide/jetbrains/.idea/vcs.xml +6 -0
  214. package/ide/jetbrains/.idea/webResources.xml +14 -0
  215. package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
  216. package/ide/jetbrains/installed.txt +4 -0
  217. package/ide/jetbrains/options/github-copilot.xml +5 -0
  218. package/ide/jetbrains/options/nodejs.xml +7 -0
  219. package/ide/jetbrains/options/templates.xml +124 -0
  220. package/ide/jetbrains/templates/JavaScript.xml +6 -0
  221. package/ide/jetbrains/templates/Stacks.xml +8 -0
  222. package/ide/vscode/.vscode/README.md +23 -0
  223. package/ide/vscode/.vscode/extensions.json +5 -0
  224. package/ide/vscode/.vscode/settings.json +176 -0
  225. package/ide/vscode/.vscode/stacks.code-snippets +181 -0
  226. package/ide/vscode/LICENSE.md +21 -0
  227. package/ide/vscode/README.md +36 -0
  228. package/ide/vscode/logo.png +0 -0
  229. package/ide/vscode/package.json +79 -0
  230. package/ide/zed/.zed/settings.json +139 -0
  231. package/lang/README.md +28 -0
  232. package/lang/de.yml +14 -0
  233. package/lang/en.yml +15 -0
  234. package/package.json +19 -3
  235. package/project/bootstrap +161 -0
  236. package/project/buddy +175 -0
  237. package/project/storage/framework/tsconfig.app.json +50 -0
  238. package/project/storage/framework/tsconfig.base.json +58 -0
  239. package/routes/core.ts +78 -0
  240. package/routes/dashboard-api.ts +233 -0
  241. package/routes/dashboard.ts +739 -0
  242. package/routes/email.ts +129 -0
  243. package/stores/[name].stx +16 -0
  244. package/stores/git.ts +71 -0
  245. package/stores/payment.ts +474 -0
  246. package/stores/queue.ts +43 -0
  247. package/stores/user.ts +29 -0
  248. package/stx-components-plugin.ts +25 -0
  249. package/styles/design-tokens.css +597 -0
  250. package/types/dashboard.ts +70 -0
  251. package/types/defaults.ts +438 -0
  252. package/vcs/github/CODE_OF_CONDUCT.md +83 -0
  253. package/vcs/github/CONTRIBUTING.md +187 -0
  254. package/vcs/github/EXPLANATIONS.md +41 -0
  255. package/vcs/github/FUNDING.yml +1 -0
  256. package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  257. package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
  258. package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  259. package/vcs/github/SECURITY.md +70 -0
  260. package/vcs/github/renovate.json +5 -0
  261. package/vcs/github/stale.yml +14 -0
  262. package/vcs/github/workflows/README.md +16 -0
  263. package/vcs/github/workflows/ci.yml +114 -0
  264. package/vcs/github/workflows/export-size.yml +25 -0
  265. package/vcs/github/workflows/labeler.yml +13 -0
  266. package/vcs/github/workflows/release.yml +219 -0
  267. package/views/[...all].stx +8 -0
  268. package/views/about.md +3 -0
  269. package/views/auth/login.stx +1 -0
  270. package/views/auth/signup.stx +85 -0
  271. package/views/dashboard/.discovered-models.json +542 -0
  272. package/views/dashboard/AUDIT.md +904 -0
  273. package/views/dashboard/[...all].stx +89 -0
  274. package/views/dashboard/access-tokens/index.stx +177 -0
  275. package/views/dashboard/actions/index.stx +129 -0
  276. package/views/dashboard/analytics/blog/index.stx +356 -0
  277. package/views/dashboard/analytics/browsers/index.stx +263 -0
  278. package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
  279. package/views/dashboard/analytics/commerce/web/index.stx +379 -0
  280. package/views/dashboard/analytics/countries/index.stx +289 -0
  281. package/views/dashboard/analytics/devices/index.stx +305 -0
  282. package/views/dashboard/analytics/events/index.stx +536 -0
  283. package/views/dashboard/analytics/index.stx +88 -0
  284. package/views/dashboard/analytics/marketing/index.stx +315 -0
  285. package/views/dashboard/analytics/pages/index.stx +271 -0
  286. package/views/dashboard/analytics/referrers/index.stx +319 -0
  287. package/views/dashboard/analytics/web/index.stx +356 -0
  288. package/views/dashboard/buddy/index.stx +198 -0
  289. package/views/dashboard/ci/index.stx +462 -0
  290. package/views/dashboard/cloud/index.stx +452 -0
  291. package/views/dashboard/commands/index.stx +295 -0
  292. package/views/dashboard/commerce/categories/index.stx +406 -0
  293. package/views/dashboard/commerce/coupons/index.stx +485 -0
  294. package/views/dashboard/commerce/customers/index.stx +410 -0
  295. package/views/dashboard/commerce/dashboard/index.stx +287 -0
  296. package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
  297. package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
  298. package/views/dashboard/commerce/delivery/drivers.stx +397 -0
  299. package/views/dashboard/commerce/delivery/index.stx +18 -0
  300. package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
  301. package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
  302. package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
  303. package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
  304. package/views/dashboard/commerce/delivery/tabs.ts +25 -0
  305. package/views/dashboard/commerce/gift-cards/index.stx +561 -0
  306. package/views/dashboard/commerce/manufacturers/index.stx +308 -0
  307. package/views/dashboard/commerce/orders/index.stx +247 -0
  308. package/views/dashboard/commerce/payments/index.stx +535 -0
  309. package/views/dashboard/commerce/pos/index.stx +653 -0
  310. package/views/dashboard/commerce/printers/devices/index.stx +273 -0
  311. package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
  312. package/views/dashboard/commerce/products/detail.stx +563 -0
  313. package/views/dashboard/commerce/products/index.stx +370 -0
  314. package/views/dashboard/commerce/reviews/index.stx +656 -0
  315. package/views/dashboard/commerce/reviews/index.ts +0 -0
  316. package/views/dashboard/commerce/taxes/index.stx +377 -0
  317. package/views/dashboard/commerce/units/index.stx +317 -0
  318. package/views/dashboard/commerce/variants/index.stx +319 -0
  319. package/views/dashboard/commerce/waitlist/products.stx +942 -0
  320. package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
  321. package/views/dashboard/components/index.stx +330 -0
  322. package/views/dashboard/composables/index.ts +19 -0
  323. package/views/dashboard/composables/useChart.ts +77 -0
  324. package/views/dashboard/composables/useNavigation.ts +99 -0
  325. package/views/dashboard/composables/useRole.ts +58 -0
  326. package/views/dashboard/composables/useTheme.ts +74 -0
  327. package/views/dashboard/content/authors/index.stx +171 -0
  328. package/views/dashboard/content/blog/index.stx +493 -0
  329. package/views/dashboard/content/categories/index.stx +169 -0
  330. package/views/dashboard/content/comments/index.stx +189 -0
  331. package/views/dashboard/content/dashboard.stx +383 -0
  332. package/views/dashboard/content/files/index.stx +706 -0
  333. package/views/dashboard/content/pages/index.stx +174 -0
  334. package/views/dashboard/content/posts/index.stx +269 -0
  335. package/views/dashboard/content/seo/index.stx +240 -0
  336. package/views/dashboard/content/tags/index.stx +167 -0
  337. package/views/dashboard/data/activity/index.stx +261 -0
  338. package/views/dashboard/data/dashboard/index.stx +116 -0
  339. package/views/dashboard/data/subscribers.stx +270 -0
  340. package/views/dashboard/data/teams.stx +275 -0
  341. package/views/dashboard/data/users.stx +279 -0
  342. package/views/dashboard/dependencies/index.stx +178 -0
  343. package/views/dashboard/deployments/[id].stx +234 -0
  344. package/views/dashboard/deployments/index.stx +9 -0
  345. package/views/dashboard/dns/index.stx +163 -0
  346. package/views/dashboard/environment/index.stx +283 -0
  347. package/views/dashboard/errors/index.stx +274 -0
  348. package/views/dashboard/forgot-password.stx +57 -0
  349. package/views/dashboard/functions/index.stx +159 -0
  350. package/views/dashboard/health/index.stx +248 -0
  351. package/views/dashboard/inbox/activity.stx +350 -0
  352. package/views/dashboard/inbox/index.stx +452 -0
  353. package/views/dashboard/inbox/settings.stx +290 -0
  354. package/views/dashboard/index.stx +252 -0
  355. package/views/dashboard/insights/index.stx +529 -0
  356. package/views/dashboard/jobs/[id].stx +430 -0
  357. package/views/dashboard/jobs/history.stx +222 -0
  358. package/views/dashboard/jobs/index.stx +214 -0
  359. package/views/dashboard/kanban/[id].stx +899 -0
  360. package/views/dashboard/kanban/index.stx +260 -0
  361. package/views/dashboard/layouts/default.stx +565 -0
  362. package/views/dashboard/layouts/guest.stx +10 -0
  363. package/views/dashboard/login.stx +48 -0
  364. package/views/dashboard/logs/index.stx +540 -0
  365. package/views/dashboard/mailboxes/index.stx +149 -0
  366. package/views/dashboard/management/permissions/index.stx +490 -0
  367. package/views/dashboard/marketing/campaigns/index.stx +604 -0
  368. package/views/dashboard/marketing/lists/index.stx +514 -0
  369. package/views/dashboard/marketing/reviews/index.stx +475 -0
  370. package/views/dashboard/marketing/social-posts/index.stx +560 -0
  371. package/views/dashboard/models/[model].stx +195 -0
  372. package/views/dashboard/models/index.stx +159 -0
  373. package/views/dashboard/monitoring/errors/index.stx +415 -0
  374. package/views/dashboard/notifications/dashboard.stx +383 -0
  375. package/views/dashboard/notifications/email.stx +336 -0
  376. package/views/dashboard/notifications/history.stx +373 -0
  377. package/views/dashboard/notifications/sms.stx +332 -0
  378. package/views/dashboard/packages/index.stx +195 -0
  379. package/views/dashboard/queries/[id].stx +381 -0
  380. package/views/dashboard/queries/history.stx +227 -0
  381. package/views/dashboard/queries/index.stx +335 -0
  382. package/views/dashboard/queries/slow.stx +318 -0
  383. package/views/dashboard/queue/index.stx +427 -0
  384. package/views/dashboard/realtime/index.stx +429 -0
  385. package/views/dashboard/register.stx +46 -0
  386. package/views/dashboard/releases/index.stx +389 -0
  387. package/views/dashboard/requests/index.stx +462 -0
  388. package/views/dashboard/serverless/index.stx +475 -0
  389. package/views/dashboard/servers/[id].stx +299 -0
  390. package/views/dashboard/servers/index.stx +483 -0
  391. package/views/dashboard/settings/billing.stx +50 -0
  392. package/views/dashboard/settings/index.stx +256 -0
  393. package/views/dashboard/settings/mail.stx +252 -0
  394. package/views/dashboard/stores/auth.ts +123 -0
  395. package/views/dashboard/stores/ci.ts +342 -0
  396. package/views/dashboard/stores/index.ts +129 -0
  397. package/views/dashboard/stores/kanban.ts +723 -0
  398. package/views/dashboard/stores/rbac.ts +350 -0
  399. package/views/dashboard/stx.config.ts +34 -0
  400. package/views/dashboard/teams/[id].stx +170 -0
  401. package/views/forum/category.stx +92 -0
  402. package/views/forum/index.stx +209 -0
  403. package/views/forum/new-topic.stx +113 -0
  404. package/views/forum/profile.stx +1 -0
  405. package/views/forum/topic.stx +143 -0
  406. package/views/hello-world/[name].stx +47 -0
  407. package/views/index.stx +21 -0
  408. package/views/system-tray/index.stx +147 -0
@@ -0,0 +1,576 @@
1
+ ---
2
+ name: stacks-storage
3
+ description: Use when working with file storage in Stacks — the Storage facade (put/get/delete/copy/move/list), StorageAdapter interface, local and S3 disk configurations, file uploads (UploadedFile class), file operations (read/write/copy/move/delete/hash/glob/zip), visibility management, checksums, MIME types, temporary URLs, or filesystem configuration. Covers @stacksjs/storage and config/filesystems.ts.
4
+ license: MIT
5
+ compatibility: Bun >= 1.3.0, TypeScript
6
+ allowed-tools: Read Edit Write Bash Grep Glob
7
+ ---
8
+
9
+ # Stacks Storage
10
+
11
+ File system abstraction with a Laravel-style Storage facade, local/S3 adapters, file upload handling, and low-level file utilities.
12
+
13
+ ## Key Paths
14
+ - Core package: `storage/framework/core/storage/src/`
15
+ - Storage facade: `storage/framework/core/storage/src/facade.ts`
16
+ - Uploaded file: `storage/framework/core/storage/src/uploaded-file.ts`
17
+ - Types: `storage/framework/core/storage/src/types.ts`
18
+ - Filesystem config types: `storage/framework/core/storage/src/types/filesystem.ts`
19
+ - Local adapter: `storage/framework/core/storage/src/adapters/local.ts`
20
+ - S3 adapter: `storage/framework/core/storage/src/adapters/s3.ts`
21
+ - Memory adapter: `storage/framework/core/storage/src/adapters/memory.ts`
22
+ - Bun adapter: `storage/framework/core/storage/src/adapters/bun.ts`
23
+ - File utilities: `storage/framework/core/storage/src/files.ts`
24
+ - Folder utilities: `storage/framework/core/storage/src/folders.ts`
25
+ - Copy: `storage/framework/core/storage/src/copy.ts`
26
+ - Move: `storage/framework/core/storage/src/move.ts`
27
+ - Delete: `storage/framework/core/storage/src/delete.ts`
28
+ - Hash: `storage/framework/core/storage/src/hash.ts`
29
+ - Glob: `storage/framework/core/storage/src/glob.ts`
30
+ - Zip: `storage/framework/core/storage/src/zip.ts`
31
+ - Helpers: `storage/framework/core/storage/src/helpers.ts`
32
+ - Configuration: `config/filesystems.ts`
33
+
34
+ ## Package Exports
35
+
36
+ ```typescript
37
+ // Storage facade (Laravel-style)
38
+ import { Storage, StorageManager } from '@stacksjs/storage'
39
+
40
+ // File uploads
41
+ import { UploadedFile, uploadedFile, uploadedFiles } from '@stacksjs/storage'
42
+
43
+ // Adapters
44
+ import { createLocalStorage, LocalStorageAdapter } from '@stacksjs/storage'
45
+ import { createS3Storage, S3StorageAdapter } from '@stacksjs/storage'
46
+
47
+ // Config helpers
48
+ import { localDisk, s3Disk, configFromEnv } from '@stacksjs/storage'
49
+
50
+ // Types
51
+ import type { StorageAdapter, FileContents, StatEntry, DirectoryEntry, DirectoryListing } from '@stacksjs/storage'
52
+ import type { ListOptions, PublicUrlOptions, TemporaryUrlOptions, ChecksumOptions, MimeTypeOptions } from '@stacksjs/storage'
53
+ import type { DiskConfig, FilesystemConfig, LocalDiskConfig, S3DiskConfig } from '@stacksjs/storage'
54
+ import { Visibility, createDirectoryListing, normalizeExpiryToMilliseconds, normalizeExpiryToDate, isFile, isDirectory } from '@stacksjs/storage'
55
+
56
+ // Low-level file operations
57
+ import { copy, copyFile, copyFolder } from '@stacksjs/storage'
58
+ import { move, rename } from '@stacksjs/storage'
59
+ import { del, deleteFile, deleteFolder, deleteEmptyFolder, deleteEmptyFolders, deleteGlob, isDirectoryEmpty } from '@stacksjs/storage'
60
+ import { readJsonFile, readPackageJson, readTextFile, writeFile, writeJsonFile, writeTextFile, put, get, getFiles, deleteFiles, hasFiles } from '@stacksjs/storage'
61
+ import { isFolder, isDir, doesFolderExist, createFolder, getFolders } from '@stacksjs/storage'
62
+ import { glob, globSync } from '@stacksjs/storage'
63
+ import { hashDirectory, hashPath, hashPaths } from '@stacksjs/storage'
64
+ import { zip, unzip, archive, unarchive, compress, decompress, gzipSync, gunzipSync, deflateSync, inflateSync } from '@stacksjs/storage'
65
+ import * as storage from '@stacksjs/storage'
66
+ ```
67
+
68
+ ## Storage Facade (StorageManager)
69
+
70
+ The `Storage` singleton is a pre-instantiated `StorageManager`. It lazily builds its config from `@stacksjs/config` (which reads `config/filesystems.ts` and env vars).
71
+
72
+ ### Basic Operations
73
+
74
+ ```typescript
75
+ import { Storage } from '@stacksjs/storage'
76
+
77
+ // Write a file (to default disk)
78
+ await Storage.put('file.txt', 'Hello World')
79
+ await Storage.put('data.bin', new Uint8Array([1, 2, 3]))
80
+
81
+ // Read a file as string
82
+ const content = await Storage.get('file.txt')
83
+
84
+ // Check existence
85
+ const exists = await Storage.exists('file.txt')
86
+ const missing = await Storage.missing('file.txt')
87
+
88
+ // Delete
89
+ await Storage.delete('file.txt')
90
+
91
+ // Copy and move
92
+ await Storage.copy('source.txt', 'dest.txt')
93
+ await Storage.move('old.txt', 'new.txt')
94
+
95
+ // File info
96
+ const size = await Storage.size('file.txt') // bytes
97
+ const modified = await Storage.lastModified('file.txt') // ms timestamp
98
+ const mime = await Storage.mimeType('file.txt')
99
+ const hash = await Storage.checksum('file.txt', 'sha256') // 'md5' | 'sha1' | 'sha256'
100
+
101
+ // Public URL
102
+ const url = await Storage.url('file.txt')
103
+
104
+ // Directories
105
+ await Storage.makeDirectory('uploads/images')
106
+ await Storage.deleteDirectory('uploads/old')
107
+
108
+ // List files (returns AsyncIterable<{ path, type }>)
109
+ for await (const entry of Storage.files('uploads/')) {
110
+ console.log(entry.path, entry.type) // 'file' or 'directory'
111
+ }
112
+
113
+ // Recursive listing
114
+ for await (const entry of Storage.allFiles('uploads/')) {
115
+ console.log(entry.path)
116
+ }
117
+ ```
118
+
119
+ ### Using Named Disks
120
+
121
+ ```typescript
122
+ // Use a specific disk
123
+ await Storage.disk('s3').write('uploads/file.txt', contents)
124
+ await Storage.disk('public').write('images/logo.png', imageData)
125
+ await Storage.disk('local').readToString('config.json')
126
+
127
+ // Disk instances are cached -- subsequent calls return the same adapter
128
+ ```
129
+
130
+ ### Configuring Disks
131
+
132
+ ```typescript
133
+ // Initialize with custom config (overrides env-based config)
134
+ Storage.init({
135
+ default: 's3',
136
+ disks: {
137
+ custom: { driver: 'local', root: '/custom/path' },
138
+ },
139
+ })
140
+
141
+ // Add/update a disk at runtime
142
+ Storage.configure('backups', { driver: 's3', bucket: 'my-backups', region: 'eu-west-1' })
143
+
144
+ // Change default disk
145
+ Storage.setDefaultDisk('s3')
146
+
147
+ // Query configuration
148
+ Storage.getDefaultDisk() // 'local'
149
+ Storage.getConfiguredDisks() // ['local', 'public', 's3']
150
+ Storage.getDiskConfig('s3') // S3DiskConfig object
151
+
152
+ // Reset all caches (useful for testing)
153
+ Storage.reset()
154
+ ```
155
+
156
+ ### Built-in Disk Configurations
157
+
158
+ The facade auto-configures these disks from `config/filesystems.ts`:
159
+
160
+ - **`local`** -- `driver: 'local'`, root: `<project>/storage/app`, visibility: from config (default `'private'`)
161
+ - **`public`** -- `driver: 'local'`, root: `<project>/public`, url: `<appUrl>/storage`, visibility: `'public'`
162
+ - **`s3`** -- only added if `s3.bucket` is configured in filesystems config
163
+
164
+ ## StorageAdapter Interface
165
+
166
+ All adapters implement this interface:
167
+
168
+ ```typescript
169
+ interface StorageAdapter {
170
+ write(path: string, contents: FileContents): Promise<void>
171
+ read(path: string): Promise<FileContents>
172
+ readToString(path: string): Promise<string>
173
+ readToBuffer(path: string): Promise<Buffer>
174
+ readToUint8Array(path: string): Promise<Uint8Array>
175
+ deleteFile(path: string): Promise<void>
176
+ deleteDirectory(path: string): Promise<void>
177
+ createDirectory(path: string): Promise<void>
178
+ moveFile(from: string, to: string): Promise<void>
179
+ copyFile(from: string, to: string): Promise<void>
180
+ stat(path: string): Promise<StatEntry>
181
+ list(path: string, options?: ListOptions): DirectoryListing // AsyncIterable
182
+ changeVisibility(path: string, visibility: Visibility): Promise<void>
183
+ visibility(path: string): Promise<Visibility>
184
+ fileExists(path: string): Promise<boolean>
185
+ directoryExists(path: string): Promise<boolean>
186
+ publicUrl(path: string, options?: PublicUrlOptions): Promise<string>
187
+ temporaryUrl(path: string, options: TemporaryUrlOptions): Promise<string>
188
+ checksum(path: string, options?: ChecksumOptions): Promise<string>
189
+ mimeType(path: string, options?: MimeTypeOptions): Promise<string>
190
+ lastModified(path: string): Promise<number>
191
+ fileSize(path: string): Promise<number>
192
+ }
193
+ ```
194
+
195
+ ### Local Adapter (`LocalStorageAdapter`)
196
+
197
+ ```typescript
198
+ import { createLocalStorage } from '@stacksjs/storage'
199
+
200
+ const local = createLocalStorage({ root: './storage' })
201
+ ```
202
+
203
+ - Uses Node.js `fs/promises` for file operations
204
+ - Path traversal protection: throws if resolved path escapes the root directory
205
+ - `write()` auto-creates parent directories with `mkdir({ recursive: true })`
206
+ - `moveFile()` uses `fs.rename()`; `copyFile()` uses `fs.copyFile()`
207
+ - `checksum()` uses `Bun.CryptoHasher` (default algorithm: `sha256`)
208
+ - `temporaryUrl()` generates HMAC-signed URLs using `APP_KEY` env var
209
+ - `changeVisibility()` is a no-op (Node.js doesn't map to public/private simply)
210
+ - `visibility()` always returns `'private'`
211
+ - MIME type detection is extension-based (supports txt, html, css, js, json, xml, pdf, zip, jpg, jpeg, png, gif, svg, mp4, mp3, wav)
212
+ - `list()` returns an async iterable; supports `deep: true` for recursive listing
213
+
214
+ ### S3 Adapter (`S3StorageAdapter`)
215
+
216
+ ```typescript
217
+ import { createS3Storage, S3StorageAdapter } from '@stacksjs/storage'
218
+ import { S3Client } from '@stacksjs/ts-cloud'
219
+
220
+ const client = new S3Client('us-east-1')
221
+ const s3 = new S3StorageAdapter(client, { bucket: 'my-bucket', region: 'us-east-1', prefix: 'uploads/' })
222
+ ```
223
+
224
+ - Uses `@stacksjs/ts-cloud` S3Client for AWS operations
225
+ - Supports key prefix: all paths are prefixed with `config.prefix`
226
+ - `write()` auto-detects MIME type from extension and sets `contentType`
227
+ - `createDirectory()` is a no-op (S3 directories are implicit)
228
+ - `moveFile()` = `copyFile()` + `deleteFile()`
229
+ - `deleteDirectory()` lists all objects with prefix and deletes them in bulk
230
+ - `temporaryUrl()` uses `client.getSignedUrl()` for pre-signed URLs
231
+ - `checksum()` downloads the file content and hashes with `Bun.CryptoHasher`
232
+ - `publicUrl()` defaults to `https://<bucket>.s3.<region>.amazonaws.com/<key>`
233
+ - `list()` supports pagination via continuation tokens; `deep: true` uses `listAllObjects()`
234
+ - `fileExists()` uses `headObject()` and catches 404/NoSuchKey/NotFound errors
235
+
236
+ ## File Uploads (UploadedFile)
237
+
238
+ ```typescript
239
+ import { UploadedFile, uploadedFile, uploadedFiles } from '@stacksjs/storage'
240
+
241
+ // Create from native File object
242
+ const file = uploadedFile(nativeFile)
243
+ const files = uploadedFiles([file1, file2])
244
+
245
+ // Properties
246
+ file.name // original filename
247
+ file.extension // lowercase extension without dot
248
+ file.mimeType // client MIME type
249
+ file.size // size in bytes
250
+ file.file // underlying File object
251
+
252
+ // Content access
253
+ const buffer = await file.arrayBuffer()
254
+ const bytes = await file.bytes() // Uint8Array
255
+ const text = await file.text()
256
+
257
+ // Validation
258
+ file.isValid() // size > 0
259
+ file.isImage() // MIME starts with 'image/'
260
+ file.isVideo() // MIME starts with 'video/'
261
+ file.isAudio() // MIME starts with 'audio/'
262
+ file.isPdf() // MIME is 'application/pdf'
263
+ file.isOneOf(['image/*', 'application/pdf']) // wildcard match
264
+
265
+ // Name helpers
266
+ file.hashName() // UUID-based hash filename: 'a1b2c3d4...f5.jpg'
267
+ file.hashName('png') // override extension: 'a1b2c3d4...f5.png'
268
+ file.getClientOriginalName() // filename without extension
269
+ file.getClientOriginalExtension() // same as .extension
270
+ file.getClientMimeType() // same as .mimeType
271
+ file.getSize() // human-readable: '1.50 MB'
272
+
273
+ // Store to disk
274
+ const path = await file.store('uploads/avatars') // default disk: 'local', hash name
275
+ const path = await file.store('uploads/', 's3') // specify disk
276
+ const path = await file.storeAs('uploads/', 'avatar.jpg') // specific name, 'local' disk
277
+ const path = await file.storeAs('uploads/', 'pic.jpg', 's3') // specific name, specific disk
278
+ const path = await file.storePublicly('images/') // stores to 'public' disk
279
+ const path = await file.storePubliclyAs('images/', 'logo.png')
280
+
281
+ // Move (write to new location)
282
+ const path = await file.move('new/path/file.jpg', 'local')
283
+ ```
284
+
285
+ `store()` generates a hash-based filename using `crypto.randomUUID()`. `storeAs()` validates the filename: rejects path traversal (`..`), forward slashes, and backslashes.
286
+
287
+ ## Low-Level File Operations
288
+
289
+ ### Read/Write Files
290
+
291
+ ```typescript
292
+ import { readJsonFile, readTextFile, readPackageJson, writeFile, writeJsonFile, writeTextFile, put, get } from '@stacksjs/storage'
293
+
294
+ // JSON files (auto-detects indent and newline style)
295
+ const jsonFile = await readJsonFile('package.json')
296
+ // Returns { path, data (parsed), indent, newline }
297
+ await writeJsonFile(jsonFile) // preserves formatting
298
+
299
+ // Package.json helper
300
+ const pkg = await readPackageJson('package.json')
301
+
302
+ // Text files
303
+ const textFile = await readTextFile('config.txt')
304
+ // Returns { path, data (string) }
305
+ await writeTextFile({ path: 'out.txt', data: 'content' })
306
+
307
+ // Bun.write shorthand
308
+ const bytes = await writeFile('output.txt', 'data') // returns bytes written
309
+
310
+ // Simple put/get
311
+ put('file.txt', 'contents') // sync write, auto-creates dirs
312
+ const content = await get('file.txt') // async read via Bun.file().text()
313
+ ```
314
+
315
+ ### Copy
316
+
317
+ ```typescript
318
+ import { copy, copyFile, copyFolder } from '@stacksjs/storage'
319
+
320
+ copy('src.txt', 'dest.txt') // single file
321
+ copy(['a.txt', 'b.txt'], 'dest/') // multiple files
322
+ copy('srcDir/', 'destDir/') // directory (recursive)
323
+ copy('srcDir/', 'destDir/', ['node_modules']) // with exclusions
324
+ copyFile('src.txt', 'dest.txt') // single file only
325
+ copyFolder('srcDir/', 'destDir/', ['dist']) // directory with exclusions
326
+ ```
327
+
328
+ ### Move/Rename
329
+
330
+ ```typescript
331
+ import { move, rename } from '@stacksjs/storage'
332
+
333
+ const result = await move('old.txt', 'new.txt') // single file
334
+ const result = await move(['a.txt', 'b.txt'], 'dest/') // multiple files to directory
335
+ const result = await move('old.txt', 'new.txt', { overwrite: true })
336
+
337
+ const result = await rename('old.txt', 'new.txt')
338
+ // Returns Result<{ message: string }, Error>
339
+ ```
340
+
341
+ `move()` creates destination directories if needed. Without `overwrite: true`, throws if destination exists.
342
+
343
+ ### Delete
344
+
345
+ ```typescript
346
+ import { del, deleteFile, deleteFolder, deleteEmptyFolder, deleteEmptyFolders, deleteGlob, isDirectoryEmpty } from '@stacksjs/storage'
347
+
348
+ await del('path') // auto-detects: file, folder, or glob
349
+ await deleteFile('file.txt') // file only
350
+ await deleteFolder('dir/') // recursive delete
351
+ await deleteEmptyFolder('dir/') // only if empty
352
+ await deleteEmptyFolders('parent/') // recursively delete all empty subdirs
353
+ await deleteGlob('dist/*') // delete matching directories
354
+
355
+ const result = await isDirectoryEmpty('dir/') // Result<boolean, Error>
356
+ ```
357
+
358
+ All delete functions return `Result<string, Error>` using `@stacksjs/error-handling`.
359
+
360
+ ### Glob
361
+
362
+ ```typescript
363
+ import { glob, globSync } from '@stacksjs/storage'
364
+
365
+ const files = await glob('**/*.ts')
366
+ const files = await glob(['src/**/*.ts', 'tests/**/*.ts'])
367
+ const files = await glob('**/*.ts', {
368
+ cwd: '/project',
369
+ absolute: true,
370
+ dot: true, // include dotfiles
371
+ onlyFiles: true,
372
+ })
373
+
374
+ // Sync version
375
+ const files = globSync('**/*.ts', { cwd: '/project' })
376
+ ```
377
+
378
+ Uses `Bun.Glob` internally.
379
+
380
+ ### Hash
381
+
382
+ ```typescript
383
+ import { hashDirectory, hashPath, hashPaths } from '@stacksjs/storage'
384
+
385
+ const hash = hashDirectory('src/') // SHA-256 of all files
386
+ const hash = hashPath('src/index.ts') // SHA-256 of single file or directory
387
+ const hash = hashPaths(['src/', 'tests/']) // combined SHA-256
388
+ const hash = hashPaths('src/index.ts') // accepts single string too
389
+ ```
390
+
391
+ All use `createHash('sha256')` from Node.js crypto.
392
+
393
+ ### Zip/Compression
394
+
395
+ ```typescript
396
+ import { zip, unzip, archive, unarchive, compress, decompress } from '@stacksjs/storage'
397
+ import { gzipSync, gunzipSync, deflateSync, inflateSync } from '@stacksjs/storage'
398
+
399
+ // Shell-based zip (via `zip -r` command)
400
+ await zip('src/', 'archive.zip')
401
+ await zip(['file1.txt', 'file2.txt'], 'archive.zip')
402
+ await zip('src/', 'archive.zip', { cwd: '/project' })
403
+ await unzip('archive.zip')
404
+ await unzip(['a.zip', 'b.zip'])
405
+
406
+ // Aliases
407
+ archive('src/') // = zip
408
+ unarchive('a.zip') // = unzip
409
+ compress(['a', 'b']) // = zip
410
+ decompress('a.zip') // = unzip
411
+
412
+ // Bun-native compression (synchronous)
413
+ const compressed = gzipSync(data) // Bun.gzipSync
414
+ const decompressed = gunzipSync(compressed) // Bun.gunzipSync
415
+ const deflated = deflateSync(data) // Bun.deflateSync
416
+ const inflated = inflateSync(deflated) // Bun.inflateSync
417
+ ```
418
+
419
+ ### Folder Utilities
420
+
421
+ ```typescript
422
+ import { isFolder, isDir, doesFolderExist, createFolder, getFolders } from '@stacksjs/storage'
423
+
424
+ isFolder('/path') // boolean, checks fs.statSync().isDirectory()
425
+ isDir('/path') // alias for isFolder
426
+ doesFolderExist('/path') // boolean, checks fs.existsSync()
427
+ await createFolder('dir/') // mkdirSync with recursive: true
428
+ const dirs = getFolders('parent/') // returns subdirectory names
429
+ ```
430
+
431
+ ### File Query Utilities
432
+
433
+ ```typescript
434
+ import { doesExist, doesNotExist, hasFiles, getFiles, deleteFiles } from '@stacksjs/storage'
435
+
436
+ doesExist('/path') // file or folder exists
437
+ doesNotExist('/path') // neither file nor folder
438
+ hasFiles('dir/') // directory has any entries
439
+ const files = getFiles('dir/') // all files recursively
440
+ const files = getFiles('dir/', ['node_modules']) // with exclusions
441
+ deleteFiles('dir/', ['keep.txt']) // delete all except exclusions
442
+ ```
443
+
444
+ ### Config File Helper
445
+
446
+ ```typescript
447
+ import { updateConfigFile } from '@stacksjs/storage'
448
+
449
+ await updateConfigFile('config.json', { key: 'newValue' })
450
+ // Reads, merges, writes JSON config file
451
+ ```
452
+
453
+ ## Types
454
+
455
+ ```typescript
456
+ type FileContents = string | Buffer | Uint8Array | ReadableStream
457
+
458
+ enum Visibility {
459
+ PUBLIC = 'public',
460
+ PRIVATE = 'private',
461
+ }
462
+
463
+ interface StatEntry {
464
+ path: string
465
+ type: 'file' | 'directory'
466
+ visibility: Visibility
467
+ size: number
468
+ lastModified: number // milliseconds
469
+ mimeType?: string
470
+ metadata?: Record<string, any>
471
+ }
472
+
473
+ interface DirectoryEntry {
474
+ path: string
475
+ type: 'file' | 'directory'
476
+ }
477
+
478
+ interface DirectoryListing extends AsyncIterable<DirectoryEntry> {}
479
+
480
+ interface ListOptions {
481
+ deep?: boolean
482
+ }
483
+
484
+ interface TemporaryUrlOptions {
485
+ expiresIn: number | Date // seconds or Date object
486
+ }
487
+
488
+ interface ChecksumOptions {
489
+ algorithm?: 'md5' | 'sha1' | 'sha256'
490
+ }
491
+
492
+ // Filesystem config types
493
+ type FilesystemDriver = 'local' | 's3'
494
+ type DiskConfig = LocalDiskConfig | S3DiskConfig
495
+
496
+ interface LocalDiskConfig {
497
+ driver: 'local'
498
+ root: string
499
+ url?: string
500
+ visibility?: 'public' | 'private'
501
+ }
502
+
503
+ interface S3DiskConfig {
504
+ driver: 's3'
505
+ bucket: string
506
+ region?: string
507
+ prefix?: string
508
+ endpoint?: string
509
+ usePathStyleEndpoint?: boolean
510
+ url?: string
511
+ credentials?: { key: string; secret: string }
512
+ visibility?: 'public' | 'private'
513
+ }
514
+
515
+ interface FilesystemConfig {
516
+ default: string
517
+ disks: Record<string, DiskConfig>
518
+ }
519
+ ```
520
+
521
+ ## Config Helpers
522
+
523
+ ```typescript
524
+ import { localDisk, s3Disk, configFromEnv } from '@stacksjs/storage'
525
+
526
+ // Create a local disk config
527
+ const disk = localDisk('/storage/app', { visibility: 'public', url: '/storage' })
528
+
529
+ // Create an S3 disk config (region defaults to AWS_DEFAULT_REGION env or 'us-east-1')
530
+ const disk = s3Disk('my-bucket', { region: 'eu-west-1', prefix: 'uploads/' })
531
+
532
+ // Build config from environment variables
533
+ // Reads: FILESYSTEM_DISK, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET, AWS_ENDPOINT, AWS_URL, AWS_USE_PATH_STYLE_ENDPOINT
534
+ const config = configFromEnv({ default: 'local' })
535
+ ```
536
+
537
+ ## config/filesystems.ts
538
+
539
+ ```typescript
540
+ {
541
+ driver: (env.STORAGE_DRIVER || 'bun') as any, // 'local' | 'bun' | 's3' | 'memory'
542
+ root: env.STORAGE_ROOT || process.cwd(),
543
+ s3: {
544
+ bucket: env.AWS_S3_BUCKET || '',
545
+ region: env.AWS_REGION || 'us-east-1',
546
+ prefix: env.AWS_S3_PREFIX || '',
547
+ credentials: env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY
548
+ ? { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY }
549
+ : undefined,
550
+ },
551
+ publicUrl: {
552
+ domain: env.STORAGE_PUBLIC_URL || env.APP_URL || 'http://localhost',
553
+ },
554
+ defaultVisibility: 'private',
555
+ } satisfies FilesystemsConfig
556
+ ```
557
+
558
+ ## Gotchas
559
+ - Default driver is `'bun'` (not `'local'`), but the Storage facade only supports `'local'` and `'s3'` drivers -- the `buildConfig()` in the facade maps the filesystems config to `'local'` as the default disk driver
560
+ - The `local` disk root is `<project>/storage/app`, not the project root
561
+ - The `public` disk root is `<project>/public` with URL prefix `<appUrl>/storage`
562
+ - S3 disk is only added if `s3.bucket` is configured
563
+ - `list()` returns an `AsyncIterable` -- use `for await` to iterate
564
+ - `checksum()` defaults to `sha256` in both adapters (not `md5`)
565
+ - `temporaryUrl()` on local adapter generates HMAC-signed URLs using `APP_KEY` env var
566
+ - `temporaryUrl()` on S3 adapter uses pre-signed URLs via `getSignedUrl()`
567
+ - `LocalStorageAdapter` prevents path traversal -- throws if resolved path escapes the root
568
+ - `S3StorageAdapter` requires a bucket name -- throws on construction if missing
569
+ - `changeVisibility()` is a no-op on both local and S3 adapters
570
+ - `visibility()` always returns `'private'` on both adapters
571
+ - The `Storage` singleton is pre-instantiated -- use `Storage.reset()` to clear caches for testing
572
+ - `UploadedFile.storeAs()` rejects filenames containing `..`, `/`, or `\` to prevent path traversal
573
+ - `UploadedFile.hashName()` is cached -- calling it multiple times returns the same hash
574
+ - Low-level operations (`copy`, `move`, `delete*`, etc.) use synchronous `fs` methods, while the Storage facade uses async operations
575
+ - `zip()` and `unzip()` shell out to the `zip`/`unzip` commands -- they require these tools to be installed on the system
576
+ - `STORAGE_DRIVER` env var controls the driver selection in `config/filesystems.ts`