@aurostack/stacks 0.1.0

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 (601) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -0
  3. package/cli/src/extract.mjs +165 -0
  4. package/cli/src/fsx.mjs +197 -0
  5. package/cli/src/generate.mjs +235 -0
  6. package/cli/src/hooks.mjs +55 -0
  7. package/cli/src/manifest.mjs +163 -0
  8. package/cli/src/strip.mjs +208 -0
  9. package/cli/src/tokens.mjs +102 -0
  10. package/cli/stack.mjs +672 -0
  11. package/package.json +37 -0
  12. package/templates/nest-api/files/.bin/db.ts +123 -0
  13. package/templates/nest-api/files/.bin/dc.ts +74 -0
  14. package/templates/nest-api/files/.bin/helpers.ts +49 -0
  15. package/templates/nest-api/files/.bin/secrets.ts +68 -0
  16. package/templates/nest-api/files/.bin/start.ts +47 -0
  17. package/templates/nest-api/files/.dockerignore +7 -0
  18. package/templates/nest-api/files/.env.example +91 -0
  19. package/templates/nest-api/files/.env.test.example +75 -0
  20. package/templates/nest-api/files/.forgejo/workflows/build-and-push.yml +41 -0
  21. package/templates/nest-api/files/.forgejo/workflows/test-e2e.yml +83 -0
  22. package/templates/nest-api/files/.forgejo/workflows/test.yml +53 -0
  23. package/templates/nest-api/files/.npmrc.example +1 -0
  24. package/templates/nest-api/files/.nvmrc +1 -0
  25. package/templates/nest-api/files/.prettierrc +8 -0
  26. package/templates/nest-api/files/.swcrc +15 -0
  27. package/templates/nest-api/files/.watchmanconfig +3 -0
  28. package/templates/nest-api/files/.yarnrc.yml +1 -0
  29. package/templates/nest-api/files/Dockerfile +40 -0
  30. package/templates/nest-api/files/__mocks__/activation-twofa.js +7 -0
  31. package/templates/nest-api/files/__mocks__/activation.js +7 -0
  32. package/templates/nest-api/files/__mocks__/forgot-password.js +7 -0
  33. package/templates/nest-api/files/__mocks__/main-layout.js +7 -0
  34. package/templates/nest-api/files/__mocks__/password-changed.js +7 -0
  35. package/templates/nest-api/files/__mocks__/reset-password.js +7 -0
  36. package/templates/nest-api/files/__mocks__/set-password.js +7 -0
  37. package/templates/nest-api/files/__mocks__/welcome.js +7 -0
  38. package/templates/nest-api/files/_gitignore +62 -0
  39. package/templates/nest-api/files/compose.test.yml +33 -0
  40. package/templates/nest-api/files/compose.yml +39 -0
  41. package/templates/nest-api/files/emails/activation-twofa.tsx +58 -0
  42. package/templates/nest-api/files/emails/activation.tsx +36 -0
  43. package/templates/nest-api/files/emails/forgot-password.tsx +29 -0
  44. package/templates/nest-api/files/emails/main-layout.tsx +134 -0
  45. package/templates/nest-api/files/emails/password-changed.tsx +24 -0
  46. package/templates/nest-api/files/emails/reset-password.tsx +24 -0
  47. package/templates/nest-api/files/emails/set-password.tsx +25 -0
  48. package/templates/nest-api/files/emails/welcome.tsx +39 -0
  49. package/templates/nest-api/files/eslint.config.mjs +28 -0
  50. package/templates/nest-api/files/global.d.ts +5 -0
  51. package/templates/nest-api/files/nest-cli.json +8 -0
  52. package/templates/nest-api/files/package.json +150 -0
  53. package/templates/nest-api/files/prisma/schema/auth.prisma +75 -0
  54. package/templates/nest-api/files/prisma/schema/base.prisma +17 -0
  55. package/templates/nest-api/files/prisma/schema/enum.prisma +17 -0
  56. package/templates/nest-api/files/prisma/schema/notification.prisma +14 -0
  57. package/templates/nest-api/files/prisma.config.ts +13 -0
  58. package/templates/nest-api/files/public/.gitkeep +0 -0
  59. package/templates/nest-api/files/seeders/index.ts +27 -0
  60. package/templates/nest-api/files/seeders/util.ts +88 -0
  61. package/templates/nest-api/files/src/__tests__/app.controller.spec.ts +29 -0
  62. package/templates/nest-api/files/src/app.controller.ts +40 -0
  63. package/templates/nest-api/files/src/app.module.ts +268 -0
  64. package/templates/nest-api/files/src/app.resolver.ts +32 -0
  65. package/templates/nest-api/files/src/app.setup.ts +178 -0
  66. package/templates/nest-api/files/src/common/__tests__/auth.service.spec.ts +31 -0
  67. package/templates/nest-api/files/src/common/__tests__/cache.service.spec.ts +214 -0
  68. package/templates/nest-api/files/src/common/__tests__/config.service.spec.ts +56 -0
  69. package/templates/nest-api/files/src/common/__tests__/generator.service.spec.ts +114 -0
  70. package/templates/nest-api/files/src/common/__tests__/health.controller.spec.ts +72 -0
  71. package/templates/nest-api/files/src/common/__tests__/helpers.spec.ts +124 -0
  72. package/templates/nest-api/files/src/common/__tests__/mail.service.spec.ts +75 -0
  73. package/templates/nest-api/files/src/common/__tests__/prisma.indicator.spec.ts +39 -0
  74. package/templates/nest-api/files/src/common/__tests__/prisma.service.spec.ts +15 -0
  75. package/templates/nest-api/files/src/common/__tests__/records.spec.ts +87 -0
  76. package/templates/nest-api/files/src/common/__tests__/schemas.spec.ts +142 -0
  77. package/templates/nest-api/files/src/common/__tests__/throttler-storage.service.spec.ts +80 -0
  78. package/templates/nest-api/files/src/common/common.module.ts +72 -0
  79. package/templates/nest-api/files/src/common/constants/index.ts +2 -0
  80. package/templates/nest-api/files/src/common/constants/options.ts +52 -0
  81. package/templates/nest-api/files/src/common/constants/pino.ts +24 -0
  82. package/templates/nest-api/files/src/common/controllers/health.controller.ts +54 -0
  83. package/templates/nest-api/files/src/common/controllers/index.ts +2 -0
  84. package/templates/nest-api/files/src/common/controllers/metrics.controller.ts +21 -0
  85. package/templates/nest-api/files/src/common/decorators/index.ts +2 -0
  86. package/templates/nest-api/files/src/common/decorators/misc.decorator.ts +49 -0
  87. package/templates/nest-api/files/src/common/decorators/multi-part.decorator.ts +6 -0
  88. package/templates/nest-api/files/src/common/dto/filters.dto.ts +25 -0
  89. package/templates/nest-api/files/src/common/dto/index.ts +1 -0
  90. package/templates/nest-api/files/src/common/entity/index.ts +2 -0
  91. package/templates/nest-api/files/src/common/entity/ok.entity.ts +11 -0
  92. package/templates/nest-api/files/src/common/entity/pagination.entity.ts +24 -0
  93. package/templates/nest-api/files/src/common/exceptions/index.ts +1 -0
  94. package/templates/nest-api/files/src/common/exceptions/prisma.exception.ts +57 -0
  95. package/templates/nest-api/files/src/common/guards/feature-flag.guard.ts +51 -0
  96. package/templates/nest-api/files/src/common/guards/index.ts +1 -0
  97. package/templates/nest-api/files/src/common/interceptors/index.ts +1 -0
  98. package/templates/nest-api/files/src/common/interceptors/metrics.interceptor.ts +37 -0
  99. package/templates/nest-api/files/src/common/misc/helpers.ts +26 -0
  100. package/templates/nest-api/files/src/common/misc/index.ts +3 -0
  101. package/templates/nest-api/files/src/common/misc/origin-builder.ts +56 -0
  102. package/templates/nest-api/files/src/common/misc/prisma.indicator.ts +24 -0
  103. package/templates/nest-api/files/src/common/modules/index.ts +3 -0
  104. package/templates/nest-api/files/src/common/modules/logger.module.ts +104 -0
  105. package/templates/nest-api/files/src/common/modules/metrics.module.ts +28 -0
  106. package/templates/nest-api/files/src/common/modules/queue.module.ts +23 -0
  107. package/templates/nest-api/files/src/common/processors/index.ts +1 -0
  108. package/templates/nest-api/files/src/common/processors/mail/index.ts +47 -0
  109. package/templates/nest-api/files/src/common/processors/mail/process.ts +225 -0
  110. package/templates/nest-api/files/src/common/schemas/fields.ts +76 -0
  111. package/templates/nest-api/files/src/common/schemas/index.ts +1 -0
  112. package/templates/nest-api/files/src/common/services/auth-rate-limit.storage.ts +79 -0
  113. package/templates/nest-api/files/src/common/services/auth.service.ts +16 -0
  114. package/templates/nest-api/files/src/common/services/cache.service.ts +118 -0
  115. package/templates/nest-api/files/src/common/services/config.service.ts +388 -0
  116. package/templates/nest-api/files/src/common/services/feature-flag.service.ts +117 -0
  117. package/templates/nest-api/files/src/common/services/generator.service.ts +54 -0
  118. package/templates/nest-api/files/src/common/services/index.ts +10 -0
  119. package/templates/nest-api/files/src/common/services/logger.service.ts +14 -0
  120. package/templates/nest-api/files/src/common/services/mail.service.ts +44 -0
  121. package/templates/nest-api/files/src/common/services/prisma.service.ts +106 -0
  122. package/templates/nest-api/files/src/common/services/throttler-storage.service.ts +112 -0
  123. package/templates/nest-api/files/src/common/types/email.ts +55 -0
  124. package/templates/nest-api/files/src/common/types/index.ts +3 -0
  125. package/templates/nest-api/files/src/common/types/misc.ts +20 -0
  126. package/templates/nest-api/files/src/common/types/prisma.ts +18 -0
  127. package/templates/nest-api/files/src/common/utils/enum.ts +39 -0
  128. package/templates/nest-api/files/src/common/utils/helpers.ts +139 -0
  129. package/templates/nest-api/files/src/common/utils/index.ts +5 -0
  130. package/templates/nest-api/files/src/common/utils/ip.ts +22 -0
  131. package/templates/nest-api/files/src/common/utils/records.ts +66 -0
  132. package/templates/nest-api/files/src/common/utils/redis.keys.ts +31 -0
  133. package/templates/nest-api/files/src/lib/__tests__/access.spec.ts +33 -0
  134. package/templates/nest-api/files/src/lib/access.ts +114 -0
  135. package/templates/nest-api/files/src/lib/auth.ts +76 -0
  136. package/templates/nest-api/files/src/lib/rate-limit.ts +20 -0
  137. package/templates/nest-api/files/src/main.ts +28 -0
  138. package/templates/nest-api/files/src/media/__tests__/media.service.spec.ts +60 -0
  139. package/templates/nest-api/files/src/media/__tests__/s3.service.spec.ts +159 -0
  140. package/templates/nest-api/files/src/media/entity/file.entity.ts +7 -0
  141. package/templates/nest-api/files/src/media/entity/index.ts +1 -0
  142. package/templates/nest-api/files/src/media/media.module.ts +20 -0
  143. package/templates/nest-api/files/src/media/processors/index.ts +44 -0
  144. package/templates/nest-api/files/src/media/services/index.ts +2 -0
  145. package/templates/nest-api/files/src/media/services/media.service.ts +29 -0
  146. package/templates/nest-api/files/src/media/services/s3.service.ts +168 -0
  147. package/templates/nest-api/files/src/notifications/controllers/index.ts +1 -0
  148. package/templates/nest-api/files/src/notifications/controllers/notifications.controller.ts +72 -0
  149. package/templates/nest-api/files/src/notifications/dto/index.ts +1 -0
  150. package/templates/nest-api/files/src/notifications/dto/notification.dto.ts +11 -0
  151. package/templates/nest-api/files/src/notifications/entity/index.ts +1 -0
  152. package/templates/nest-api/files/src/notifications/entity/notification.entity.ts +37 -0
  153. package/templates/nest-api/files/src/notifications/notifications.module.ts +11 -0
  154. package/templates/nest-api/files/src/notifications/services/index.ts +1 -0
  155. package/templates/nest-api/files/src/notifications/services/notifications.service.ts +98 -0
  156. package/templates/nest-api/files/src/realtime/__tests__/events.gateway.spec.ts +88 -0
  157. package/templates/nest-api/files/src/realtime/__tests__/rooms.spec.ts +29 -0
  158. package/templates/nest-api/files/src/realtime/__tests__/ws-permissions.guard.spec.ts +54 -0
  159. package/templates/nest-api/files/src/realtime/adapters/redis-io.adapter.ts +57 -0
  160. package/templates/nest-api/files/src/realtime/constants/index.ts +68 -0
  161. package/templates/nest-api/files/src/realtime/decorators/index.ts +1 -0
  162. package/templates/nest-api/files/src/realtime/decorators/ws-permissions.decorator.ts +14 -0
  163. package/templates/nest-api/files/src/realtime/gateways/events.gateway.ts +187 -0
  164. package/templates/nest-api/files/src/realtime/guards/index.ts +2 -0
  165. package/templates/nest-api/files/src/realtime/guards/ws-auth.guard.ts +20 -0
  166. package/templates/nest-api/files/src/realtime/guards/ws-permissions.guard.ts +35 -0
  167. package/templates/nest-api/files/src/realtime/misc/session-from-socket.ts +54 -0
  168. package/templates/nest-api/files/src/realtime/realtime.module.ts +26 -0
  169. package/templates/nest-api/files/src/realtime/services/presence.service.ts +56 -0
  170. package/templates/nest-api/files/src/realtime/services/realtime.service.ts +72 -0
  171. package/templates/nest-api/files/src/users/__tests__/current-user.controller.spec.ts +77 -0
  172. package/templates/nest-api/files/src/users/__tests__/current-user.service.spec.ts +159 -0
  173. package/templates/nest-api/files/src/users/__tests__/user.entity.spec.ts +175 -0
  174. package/templates/nest-api/files/src/users/__tests__/users.controller.spec.ts +89 -0
  175. package/templates/nest-api/files/src/users/__tests__/users.service.spec.ts +398 -0
  176. package/templates/nest-api/files/src/users/controllers/current-user.controller.ts +82 -0
  177. package/templates/nest-api/files/src/users/controllers/index.ts +2 -0
  178. package/templates/nest-api/files/src/users/controllers/users.controller.ts +40 -0
  179. package/templates/nest-api/files/src/users/decorators/index.ts +1 -0
  180. package/templates/nest-api/files/src/users/decorators/permissions.decorator.ts +24 -0
  181. package/templates/nest-api/files/src/users/dto/avatar.dto.ts +13 -0
  182. package/templates/nest-api/files/src/users/dto/filters.dto.ts +8 -0
  183. package/templates/nest-api/files/src/users/dto/index.ts +2 -0
  184. package/templates/nest-api/files/src/users/entity/index.ts +1 -0
  185. package/templates/nest-api/files/src/users/entity/user.entity.ts +53 -0
  186. package/templates/nest-api/files/src/users/services/current-user.service.ts +46 -0
  187. package/templates/nest-api/files/src/users/services/index.ts +2 -0
  188. package/templates/nest-api/files/src/users/services/users.service.ts +88 -0
  189. package/templates/nest-api/files/src/users/users.module.ts +10 -0
  190. package/templates/nest-api/files/test/app.spec.ts +102 -0
  191. package/templates/nest-api/files/test/auth.spec.ts +108 -0
  192. package/templates/nest-api/files/test/current-user.spec.ts +154 -0
  193. package/templates/nest-api/files/test/factory/app.ts +172 -0
  194. package/templates/nest-api/files/test/factory/constants.ts +22 -0
  195. package/templates/nest-api/files/test/factory/dto.ts +27 -0
  196. package/templates/nest-api/files/test/factory/entity.ts +70 -0
  197. package/templates/nest-api/files/test/factory/gen.ts +75 -0
  198. package/templates/nest-api/files/test/factory/util.ts +21 -0
  199. package/templates/nest-api/files/test/notifications.spec.ts +176 -0
  200. package/templates/nest-api/files/test/rate-limit.spec.ts +180 -0
  201. package/templates/nest-api/files/test/setup.ts +1 -0
  202. package/templates/nest-api/files/test/users.spec.ts +437 -0
  203. package/templates/nest-api/files/tsconfig.build.json +13 -0
  204. package/templates/nest-api/files/tsconfig.json +35 -0
  205. package/templates/nest-api/files/vitest.config.ts +53 -0
  206. package/templates/nest-api/template.json +452 -0
  207. package/templates/node-worker/files/.bin/db.ts +123 -0
  208. package/templates/node-worker/files/.bin/helpers.ts +49 -0
  209. package/templates/node-worker/files/.bin/secrets.ts +68 -0
  210. package/templates/node-worker/files/.dockerignore +5 -0
  211. package/templates/node-worker/files/.env.example +21 -0
  212. package/templates/node-worker/files/.forgejo/workflows/build-and-push.yml +41 -0
  213. package/templates/node-worker/files/.nvmrc +1 -0
  214. package/templates/node-worker/files/.prettierignore +4 -0
  215. package/templates/node-worker/files/.prettierrc +8 -0
  216. package/templates/node-worker/files/.yarnrc.yml +5 -0
  217. package/templates/node-worker/files/Dockerfile +63 -0
  218. package/templates/node-worker/files/Dockerfile.dev +59 -0
  219. package/templates/node-worker/files/_gitignore +48 -0
  220. package/templates/node-worker/files/ecosystem.config.cjs +10 -0
  221. package/templates/node-worker/files/eslint.config.js +37 -0
  222. package/templates/node-worker/files/package.json +67 -0
  223. package/templates/node-worker/files/prisma/_gitignore +1 -0
  224. package/templates/node-worker/files/prisma/schema/base.prisma +36 -0
  225. package/templates/node-worker/files/prisma.config.ts +13 -0
  226. package/templates/node-worker/files/src/config.ts +55 -0
  227. package/templates/node-worker/files/src/db.ts +118 -0
  228. package/templates/node-worker/files/src/index.ts +7 -0
  229. package/templates/node-worker/files/src/logger.ts +45 -0
  230. package/templates/node-worker/files/src/types.ts +23 -0
  231. package/templates/node-worker/files/src/utils/browser.ts +16 -0
  232. package/templates/node-worker/files/src/utils/date.ts +68 -0
  233. package/templates/node-worker/files/src/utils/helpers.ts +17 -0
  234. package/templates/node-worker/files/src/utils/number.ts +47 -0
  235. package/templates/node-worker/files/src/utils/worker.ts +29 -0
  236. package/templates/node-worker/files/src/workers/constants.ts +6 -0
  237. package/templates/node-worker/files/src/workers/example/index.ts +27 -0
  238. package/templates/node-worker/files/src/workers/index.ts +1 -0
  239. package/templates/node-worker/files/tsconfig.json +30 -0
  240. package/templates/node-worker/template.json +135 -0
  241. package/templates/py-worker/files/.dockerignore +176 -0
  242. package/templates/py-worker/files/.env.example +20 -0
  243. package/templates/py-worker/files/.forgejo/workflows/build-amd-push.yml +39 -0
  244. package/templates/py-worker/files/Dockerfile +10 -0
  245. package/templates/py-worker/files/README.md +3 -0
  246. package/templates/py-worker/files/_gitignore +176 -0
  247. package/templates/py-worker/files/config.py +89 -0
  248. package/templates/py-worker/files/models/decorators.py +42 -0
  249. package/templates/py-worker/files/models/enums.py +32 -0
  250. package/templates/py-worker/files/models/mixins.py +61 -0
  251. package/templates/py-worker/files/requirements.txt +18 -0
  252. package/templates/py-worker/files/utils/db.py +67 -0
  253. package/templates/py-worker/files/utils/logger.py +97 -0
  254. package/templates/py-worker/files/utils/misc.py +45 -0
  255. package/templates/py-worker/files/utils/worker.py +80 -0
  256. package/templates/py-worker/files/worker.py +41 -0
  257. package/templates/py-worker/files/workers/hello/process.py +22 -0
  258. package/templates/py-worker/template.json +87 -0
  259. package/templates/react-app/README.md +78 -0
  260. package/templates/react-app/derive.sh +128 -0
  261. package/templates/react-app/files/.bin/openapi.js +32 -0
  262. package/templates/react-app/files/.bin/secrets.js +47 -0
  263. package/templates/react-app/files/.dockerignore +16 -0
  264. package/templates/react-app/files/.editorconfig +12 -0
  265. package/templates/react-app/files/.env.example +34 -0
  266. package/templates/react-app/files/.forgejo/workflows/build-and-push.yml +55 -0
  267. package/templates/react-app/files/.forgejo/workflows/ci.yml +39 -0
  268. package/templates/react-app/files/.husky/pre-commit +1 -0
  269. package/templates/react-app/files/.nvmrc +1 -0
  270. package/templates/react-app/files/.prettierignore +6 -0
  271. package/templates/react-app/files/.prettierrc +9 -0
  272. package/templates/react-app/files/.yarnrc.yml +2 -0
  273. package/templates/react-app/files/Dockerfile +52 -0
  274. package/templates/react-app/files/_gitignore +33 -0
  275. package/templates/react-app/files/build.sh +53 -0
  276. package/templates/react-app/files/docker/nginx.conf +134 -0
  277. package/templates/react-app/files/eslint.config.mjs +75 -0
  278. package/templates/react-app/files/index.html +62 -0
  279. package/templates/react-app/files/openapi-ts.config.ts +22 -0
  280. package/templates/react-app/files/package.json +80 -0
  281. package/templates/react-app/files/src/app/nav.tsx +32 -0
  282. package/templates/react-app/files/src/app/providers.tsx +39 -0
  283. package/templates/react-app/files/src/app/router.tsx +142 -0
  284. package/templates/react-app/files/src/app/store.ts +20 -0
  285. package/templates/react-app/files/src/features/auth/components/auth-card.tsx +23 -0
  286. package/templates/react-app/files/src/features/auth/components/checkbox-field.tsx +32 -0
  287. package/templates/react-app/files/src/features/auth/components/google-button.tsx +41 -0
  288. package/templates/react-app/files/src/features/auth/components/or-divider.tsx +9 -0
  289. package/templates/react-app/files/src/features/auth/components/password-field.tsx +70 -0
  290. package/templates/react-app/files/src/features/auth/components/submit-button.tsx +16 -0
  291. package/templates/react-app/files/src/features/auth/lib/auth-actions.ts +68 -0
  292. package/templates/react-app/files/src/features/auth/lib/password-strength.ts +20 -0
  293. package/templates/react-app/files/src/features/auth/lib/redirect.ts +6 -0
  294. package/templates/react-app/files/src/features/auth/lib/schemas.ts +37 -0
  295. package/templates/react-app/files/src/features/seo/routes.ts +65 -0
  296. package/templates/react-app/files/src/lib/env.ts +28 -0
  297. package/templates/react-app/files/src/lib/paths.ts +58 -0
  298. package/templates/react-app/files/src/main.tsx +19 -0
  299. package/templates/react-app/files/src/routes/admin/home.tsx +24 -0
  300. package/templates/react-app/files/src/routes/auth/forgot-password.tsx +93 -0
  301. package/templates/react-app/files/src/routes/auth/login.tsx +87 -0
  302. package/templates/react-app/files/src/routes/auth/reset-password.tsx +83 -0
  303. package/templates/react-app/files/src/routes/auth/signup.tsx +117 -0
  304. package/templates/react-app/files/src/routes/auth/verified.tsx +31 -0
  305. package/templates/react-app/files/src/routes/auth/verify-email.tsx +97 -0
  306. package/templates/react-app/files/src/routes/home.tsx +17 -0
  307. package/templates/react-app/files/src/routes/legal/privacy.tsx +26 -0
  308. package/templates/react-app/files/src/routes/legal/terms.tsx +28 -0
  309. package/templates/react-app/files/src/routes/marketing/home.tsx +18 -0
  310. package/templates/react-app/files/src/routes/settings.tsx +10 -0
  311. package/templates/react-app/files/src/shared/api/base-api.ts +24 -0
  312. package/templates/react-app/files/src/shared/api/base-query.ts +29 -0
  313. package/templates/react-app/files/src/shared/api/config.ts +21 -0
  314. package/templates/react-app/files/src/shared/api/index.ts +15 -0
  315. package/templates/react-app/files/src/shared/api/realtime-events.ts +34 -0
  316. package/templates/react-app/files/src/shared/api/socket.ts +41 -0
  317. package/templates/react-app/files/src/shared/api/store.ts +39 -0
  318. package/templates/react-app/files/src/shared/api/upload-query.ts +115 -0
  319. package/templates/react-app/files/src/shared/auth/client.ts +27 -0
  320. package/templates/react-app/files/src/shared/auth/config.ts +28 -0
  321. package/templates/react-app/files/src/shared/auth/guards.tsx +75 -0
  322. package/templates/react-app/files/src/shared/auth/hooks.ts +13 -0
  323. package/templates/react-app/files/src/shared/auth/index.ts +20 -0
  324. package/templates/react-app/files/src/shared/auth/logout.ts +23 -0
  325. package/templates/react-app/files/src/shared/auth/provider.tsx +52 -0
  326. package/templates/react-app/files/src/shared/auth/redirect.ts +65 -0
  327. package/templates/react-app/files/src/shared/auth/slice.ts +54 -0
  328. package/templates/react-app/files/src/shared/hooks/index.ts +6 -0
  329. package/templates/react-app/files/src/shared/layouts/app-shell/app-shell.tsx +225 -0
  330. package/templates/react-app/files/src/shared/layouts/app-shell/user-menu.tsx +74 -0
  331. package/templates/react-app/files/src/shared/layouts/auth-layout.tsx +137 -0
  332. package/templates/react-app/files/src/shared/layouts/error-boundary.tsx +38 -0
  333. package/templates/react-app/files/src/shared/layouts/index.ts +23 -0
  334. package/templates/react-app/files/src/shared/layouts/marketing/marketing-layout.tsx +29 -0
  335. package/templates/react-app/files/src/shared/layouts/marketing/section-heading.tsx +38 -0
  336. package/templates/react-app/files/src/shared/layouts/marketing/section.tsx +30 -0
  337. package/templates/react-app/files/src/shared/layouts/states/app-shell-skeleton.tsx +47 -0
  338. package/templates/react-app/files/src/shared/layouts/states/empty.tsx +22 -0
  339. package/templates/react-app/files/src/shared/layouts/states/forbidden.tsx +14 -0
  340. package/templates/react-app/files/src/shared/layouts/states/loading.tsx +11 -0
  341. package/templates/react-app/files/src/shared/layouts/states/not-found.tsx +21 -0
  342. package/templates/react-app/files/src/shared/layouts/states/page-skeleton.tsx +39 -0
  343. package/templates/react-app/files/src/shared/layouts/states/route-fallback.tsx +26 -0
  344. package/templates/react-app/files/src/shared/layouts/states/state-screen.tsx +22 -0
  345. package/templates/react-app/files/src/shared/types/README.md +28 -0
  346. package/templates/react-app/files/src/shared/types/api/index.ts +9 -0
  347. package/templates/react-app/files/src/shared/types/api/zod.gen.ts +5 -0
  348. package/templates/react-app/files/src/shared/types/index.ts +4 -0
  349. package/templates/react-app/files/src/shared/ui/components/brand/logo.tsx +51 -0
  350. package/templates/react-app/files/src/shared/ui/components/brand/social-icons.tsx +37 -0
  351. package/templates/react-app/files/src/shared/ui/components/form/form.tsx +120 -0
  352. package/templates/react-app/files/src/shared/ui/components/ui/alert.tsx +25 -0
  353. package/templates/react-app/files/src/shared/ui/components/ui/button.tsx +43 -0
  354. package/templates/react-app/files/src/shared/ui/components/ui/calendar.tsx +78 -0
  355. package/templates/react-app/files/src/shared/ui/components/ui/card.tsx +44 -0
  356. package/templates/react-app/files/src/shared/ui/components/ui/checkbox.tsx +16 -0
  357. package/templates/react-app/files/src/shared/ui/components/ui/date-picker.tsx +76 -0
  358. package/templates/react-app/files/src/shared/ui/components/ui/input.tsx +22 -0
  359. package/templates/react-app/files/src/shared/ui/components/ui/label.tsx +19 -0
  360. package/templates/react-app/files/src/shared/ui/components/ui/modal.tsx +94 -0
  361. package/templates/react-app/files/src/shared/ui/components/ui/popover.tsx +31 -0
  362. package/templates/react-app/files/src/shared/ui/components/ui/progress.tsx +33 -0
  363. package/templates/react-app/files/src/shared/ui/components/ui/search-input.tsx +69 -0
  364. package/templates/react-app/files/src/shared/ui/components/ui/select.tsx +80 -0
  365. package/templates/react-app/files/src/shared/ui/components/ui/skeleton.tsx +12 -0
  366. package/templates/react-app/files/src/shared/ui/components/ui/sonner.tsx +23 -0
  367. package/templates/react-app/files/src/shared/ui/components/ui/spinner.tsx +8 -0
  368. package/templates/react-app/files/src/shared/ui/components/ui/textarea.tsx +22 -0
  369. package/templates/react-app/files/src/shared/ui/index.ts +45 -0
  370. package/templates/react-app/files/src/shared/ui/lib/utils.ts +7 -0
  371. package/templates/react-app/files/src/shared/ui/lib/zod-setup.ts +28 -0
  372. package/templates/react-app/files/src/shared/ui/meta/brand.ts +18 -0
  373. package/templates/react-app/files/src/shared/ui/meta/meta-context.ts +30 -0
  374. package/templates/react-app/files/src/shared/ui/meta/meta-provider.tsx +24 -0
  375. package/templates/react-app/files/src/shared/ui/meta/page-meta.tsx +69 -0
  376. package/templates/react-app/files/src/shared/ui/meta/use-meta-config.ts +11 -0
  377. package/templates/react-app/files/src/shared/ui/styles/globals.css +285 -0
  378. package/templates/react-app/files/src/shared/ui/styles/theme.css +48 -0
  379. package/templates/react-app/files/src/shared/ui/theme/init-script.ts +23 -0
  380. package/templates/react-app/files/src/shared/ui/theme/theme-colors.ts +14 -0
  381. package/templates/react-app/files/src/shared/ui/theme/theme-context.ts +60 -0
  382. package/templates/react-app/files/src/shared/ui/theme/theme-provider.tsx +101 -0
  383. package/templates/react-app/files/src/shared/ui/theme/theme-toggle.tsx +40 -0
  384. package/templates/react-app/files/src/shared/ui/theme/use-theme.ts +11 -0
  385. package/templates/react-app/files/src/vite-env.d.ts +13 -0
  386. package/templates/react-app/files/tsconfig.json +26 -0
  387. package/templates/react-app/files/tsconfig.node.json +25 -0
  388. package/templates/react-app/files/vite.config.ts +344 -0
  389. package/templates/react-app/overrides/src/routes/auth/forgot-password.tsx +93 -0
  390. package/templates/react-app/overrides/src/routes/auth/login.tsx +87 -0
  391. package/templates/react-app/overrides/src/routes/auth/signup.tsx +117 -0
  392. package/templates/react-app/overrides/src/routes/auth/verified.tsx +31 -0
  393. package/templates/react-app/overrides/src/routes/auth/verify-email.tsx +97 -0
  394. package/templates/react-app/overrides/src/shared/auth/config.ts +28 -0
  395. package/templates/react-app/overrides/src/shared/auth/guards.tsx +75 -0
  396. package/templates/react-app/overrides/src/shared/auth/index.ts +20 -0
  397. package/templates/react-app/overrides/src/shared/auth/redirect.ts +65 -0
  398. package/templates/react-app/overrides/src/shared/hooks/index.ts +6 -0
  399. package/templates/react-app/overrides/src/shared/types/README.md +28 -0
  400. package/templates/react-app/template.json +222 -0
  401. package/templates/react-monorepo/files/.dockerignore +19 -0
  402. package/templates/react-monorepo/files/.editorconfig +12 -0
  403. package/templates/react-monorepo/files/.forgejo/workflows/build-and-push.yml +98 -0
  404. package/templates/react-monorepo/files/.forgejo/workflows/ci.yml +35 -0
  405. package/templates/react-monorepo/files/.husky/pre-commit +1 -0
  406. package/templates/react-monorepo/files/.nvmrc +1 -0
  407. package/templates/react-monorepo/files/.prettierignore +6 -0
  408. package/templates/react-monorepo/files/.prettierrc +9 -0
  409. package/templates/react-monorepo/files/.yarnrc.yml +2 -0
  410. package/templates/react-monorepo/files/Dockerfile +90 -0
  411. package/templates/react-monorepo/files/_gitignore +35 -0
  412. package/templates/react-monorepo/files/apps/admin/.bin/secrets.js +57 -0
  413. package/templates/react-monorepo/files/apps/admin/.env.example +16 -0
  414. package/templates/react-monorepo/files/apps/admin/eslint.config.mjs +3 -0
  415. package/templates/react-monorepo/files/apps/admin/index.html +57 -0
  416. package/templates/react-monorepo/files/apps/admin/package.json +33 -0
  417. package/templates/react-monorepo/files/apps/admin/src/App.tsx +3 -0
  418. package/templates/react-monorepo/files/apps/admin/src/app/nav.tsx +14 -0
  419. package/templates/react-monorepo/files/apps/admin/src/app/providers.tsx +42 -0
  420. package/templates/react-monorepo/files/apps/admin/src/app/router.tsx +50 -0
  421. package/templates/react-monorepo/files/apps/admin/src/app/store.ts +15 -0
  422. package/templates/react-monorepo/files/apps/admin/src/lib/env.ts +12 -0
  423. package/templates/react-monorepo/files/apps/admin/src/main.tsx +14 -0
  424. package/templates/react-monorepo/files/apps/admin/src/routes/home.tsx +17 -0
  425. package/templates/react-monorepo/files/apps/admin/src/routes/settings.tsx +10 -0
  426. package/templates/react-monorepo/files/apps/admin/src/vite-env.d.ts +14 -0
  427. package/templates/react-monorepo/files/apps/admin/tsconfig.json +10 -0
  428. package/templates/react-monorepo/files/apps/admin/vite.config.ts +13 -0
  429. package/templates/react-monorepo/files/apps/auth/.bin/secrets.js +57 -0
  430. package/templates/react-monorepo/files/apps/auth/.env.example +16 -0
  431. package/templates/react-monorepo/files/apps/auth/eslint.config.mjs +3 -0
  432. package/templates/react-monorepo/files/apps/auth/index.html +57 -0
  433. package/templates/react-monorepo/files/apps/auth/package.json +32 -0
  434. package/templates/react-monorepo/files/apps/auth/src/App.tsx +3 -0
  435. package/templates/react-monorepo/files/apps/auth/src/app/providers.tsx +42 -0
  436. package/templates/react-monorepo/files/apps/auth/src/app/router.tsx +19 -0
  437. package/templates/react-monorepo/files/apps/auth/src/app/store.ts +15 -0
  438. package/templates/react-monorepo/files/apps/auth/src/components/auth-card.tsx +23 -0
  439. package/templates/react-monorepo/files/apps/auth/src/components/checkbox-field.tsx +32 -0
  440. package/templates/react-monorepo/files/apps/auth/src/components/google-button.tsx +41 -0
  441. package/templates/react-monorepo/files/apps/auth/src/components/or-divider.tsx +9 -0
  442. package/templates/react-monorepo/files/apps/auth/src/components/password-field.tsx +70 -0
  443. package/templates/react-monorepo/files/apps/auth/src/components/submit-button.tsx +16 -0
  444. package/templates/react-monorepo/files/apps/auth/src/lib/auth-actions.ts +68 -0
  445. package/templates/react-monorepo/files/apps/auth/src/lib/env.ts +8 -0
  446. package/templates/react-monorepo/files/apps/auth/src/lib/password-strength.ts +20 -0
  447. package/templates/react-monorepo/files/apps/auth/src/lib/redirect.ts +6 -0
  448. package/templates/react-monorepo/files/apps/auth/src/lib/schemas.ts +37 -0
  449. package/templates/react-monorepo/files/apps/auth/src/main.tsx +14 -0
  450. package/templates/react-monorepo/files/apps/auth/src/routes/forgot-password.tsx +91 -0
  451. package/templates/react-monorepo/files/apps/auth/src/routes/login.tsx +82 -0
  452. package/templates/react-monorepo/files/apps/auth/src/routes/reset-password.tsx +83 -0
  453. package/templates/react-monorepo/files/apps/auth/src/routes/signup.tsx +117 -0
  454. package/templates/react-monorepo/files/apps/auth/src/routes/verified.tsx +30 -0
  455. package/templates/react-monorepo/files/apps/auth/src/routes/verify-email.tsx +96 -0
  456. package/templates/react-monorepo/files/apps/auth/src/vite-env.d.ts +14 -0
  457. package/templates/react-monorepo/files/apps/auth/tsconfig.json +10 -0
  458. package/templates/react-monorepo/files/apps/auth/vite.config.ts +13 -0
  459. package/templates/react-monorepo/files/apps/client/.bin/secrets.js +57 -0
  460. package/templates/react-monorepo/files/apps/client/.env.example +16 -0
  461. package/templates/react-monorepo/files/apps/client/eslint.config.mjs +3 -0
  462. package/templates/react-monorepo/files/apps/client/index.html +57 -0
  463. package/templates/react-monorepo/files/apps/client/package.json +35 -0
  464. package/templates/react-monorepo/files/apps/client/src/App.tsx +3 -0
  465. package/templates/react-monorepo/files/apps/client/src/app/nav.tsx +14 -0
  466. package/templates/react-monorepo/files/apps/client/src/app/providers.tsx +42 -0
  467. package/templates/react-monorepo/files/apps/client/src/app/router.tsx +50 -0
  468. package/templates/react-monorepo/files/apps/client/src/app/store.ts +15 -0
  469. package/templates/react-monorepo/files/apps/client/src/lib/env.ts +12 -0
  470. package/templates/react-monorepo/files/apps/client/src/main.tsx +19 -0
  471. package/templates/react-monorepo/files/apps/client/src/routes/home.tsx +17 -0
  472. package/templates/react-monorepo/files/apps/client/src/routes/settings.tsx +10 -0
  473. package/templates/react-monorepo/files/apps/client/src/vite-env.d.ts +15 -0
  474. package/templates/react-monorepo/files/apps/client/tsconfig.json +10 -0
  475. package/templates/react-monorepo/files/apps/client/vite.config.ts +120 -0
  476. package/templates/react-monorepo/files/apps/landing/.bin/secrets.js +57 -0
  477. package/templates/react-monorepo/files/apps/landing/.env.example +20 -0
  478. package/templates/react-monorepo/files/apps/landing/eslint.config.mjs +3 -0
  479. package/templates/react-monorepo/files/apps/landing/index.html +51 -0
  480. package/templates/react-monorepo/files/apps/landing/package.json +33 -0
  481. package/templates/react-monorepo/files/apps/landing/src/App.tsx +3 -0
  482. package/templates/react-monorepo/files/apps/landing/src/app/providers.tsx +42 -0
  483. package/templates/react-monorepo/files/apps/landing/src/app/router.tsx +21 -0
  484. package/templates/react-monorepo/files/apps/landing/src/app/store.ts +18 -0
  485. package/templates/react-monorepo/files/apps/landing/src/features/seo/routes.ts +65 -0
  486. package/templates/react-monorepo/files/apps/landing/src/lib/env.ts +10 -0
  487. package/templates/react-monorepo/files/apps/landing/src/main.tsx +14 -0
  488. package/templates/react-monorepo/files/apps/landing/src/routes/home.tsx +18 -0
  489. package/templates/react-monorepo/files/apps/landing/src/vite-env.d.ts +15 -0
  490. package/templates/react-monorepo/files/apps/landing/tsconfig.json +10 -0
  491. package/templates/react-monorepo/files/apps/landing/vite.config.ts +169 -0
  492. package/templates/react-monorepo/files/build.sh +61 -0
  493. package/templates/react-monorepo/files/docker/nginx.conf +136 -0
  494. package/templates/react-monorepo/files/package.json +37 -0
  495. package/templates/react-monorepo/files/packages/.gitkeep +0 -0
  496. package/templates/react-monorepo/files/packages/api/eslint.config.mjs +3 -0
  497. package/templates/react-monorepo/files/packages/api/package.json +30 -0
  498. package/templates/react-monorepo/files/packages/api/src/base-api.ts +24 -0
  499. package/templates/react-monorepo/files/packages/api/src/base-query.ts +29 -0
  500. package/templates/react-monorepo/files/packages/api/src/config.ts +21 -0
  501. package/templates/react-monorepo/files/packages/api/src/index.ts +15 -0
  502. package/templates/react-monorepo/files/packages/api/src/realtime-events.ts +34 -0
  503. package/templates/react-monorepo/files/packages/api/src/socket.ts +41 -0
  504. package/templates/react-monorepo/files/packages/api/src/store.ts +39 -0
  505. package/templates/react-monorepo/files/packages/api/src/upload-query.ts +115 -0
  506. package/templates/react-monorepo/files/packages/api/tsconfig.json +4 -0
  507. package/templates/react-monorepo/files/packages/auth/eslint.config.mjs +3 -0
  508. package/templates/react-monorepo/files/packages/auth/package.json +33 -0
  509. package/templates/react-monorepo/files/packages/auth/src/client.ts +27 -0
  510. package/templates/react-monorepo/files/packages/auth/src/config.ts +22 -0
  511. package/templates/react-monorepo/files/packages/auth/src/guards.tsx +61 -0
  512. package/templates/react-monorepo/files/packages/auth/src/hooks.ts +13 -0
  513. package/templates/react-monorepo/files/packages/auth/src/index.ts +20 -0
  514. package/templates/react-monorepo/files/packages/auth/src/logout.ts +23 -0
  515. package/templates/react-monorepo/files/packages/auth/src/provider.tsx +52 -0
  516. package/templates/react-monorepo/files/packages/auth/src/redirect.ts +37 -0
  517. package/templates/react-monorepo/files/packages/auth/src/slice.ts +54 -0
  518. package/templates/react-monorepo/files/packages/auth/tsconfig.json +4 -0
  519. package/templates/react-monorepo/files/packages/config/README.md +47 -0
  520. package/templates/react-monorepo/files/packages/config/eslint/base.mjs +83 -0
  521. package/templates/react-monorepo/files/packages/config/package.json +37 -0
  522. package/templates/react-monorepo/files/packages/config/tailwind/theme.css +48 -0
  523. package/templates/react-monorepo/files/packages/config/tsconfig/base.json +22 -0
  524. package/templates/react-monorepo/files/packages/config/tsconfig/node.json +9 -0
  525. package/templates/react-monorepo/files/packages/config/tsconfig/react.json +9 -0
  526. package/templates/react-monorepo/files/packages/config/vite/index.d.ts +18 -0
  527. package/templates/react-monorepo/files/packages/config/vite/index.mjs +129 -0
  528. package/templates/react-monorepo/files/packages/hooks/eslint.config.mjs +3 -0
  529. package/templates/react-monorepo/files/packages/hooks/package.json +16 -0
  530. package/templates/react-monorepo/files/packages/hooks/src/index.ts +3 -0
  531. package/templates/react-monorepo/files/packages/hooks/tsconfig.json +4 -0
  532. package/templates/react-monorepo/files/packages/layouts/eslint.config.mjs +3 -0
  533. package/templates/react-monorepo/files/packages/layouts/package.json +30 -0
  534. package/templates/react-monorepo/files/packages/layouts/src/app-shell/app-shell.tsx +225 -0
  535. package/templates/react-monorepo/files/packages/layouts/src/app-shell/user-menu.tsx +74 -0
  536. package/templates/react-monorepo/files/packages/layouts/src/auth-layout.tsx +137 -0
  537. package/templates/react-monorepo/files/packages/layouts/src/error-boundary.tsx +38 -0
  538. package/templates/react-monorepo/files/packages/layouts/src/index.ts +23 -0
  539. package/templates/react-monorepo/files/packages/layouts/src/marketing/marketing-layout.tsx +29 -0
  540. package/templates/react-monorepo/files/packages/layouts/src/marketing/section-heading.tsx +38 -0
  541. package/templates/react-monorepo/files/packages/layouts/src/marketing/section.tsx +30 -0
  542. package/templates/react-monorepo/files/packages/layouts/src/states/app-shell-skeleton.tsx +47 -0
  543. package/templates/react-monorepo/files/packages/layouts/src/states/empty.tsx +22 -0
  544. package/templates/react-monorepo/files/packages/layouts/src/states/forbidden.tsx +14 -0
  545. package/templates/react-monorepo/files/packages/layouts/src/states/loading.tsx +11 -0
  546. package/templates/react-monorepo/files/packages/layouts/src/states/not-found.tsx +21 -0
  547. package/templates/react-monorepo/files/packages/layouts/src/states/page-skeleton.tsx +39 -0
  548. package/templates/react-monorepo/files/packages/layouts/src/states/route-fallback.tsx +26 -0
  549. package/templates/react-monorepo/files/packages/layouts/src/states/state-screen.tsx +22 -0
  550. package/templates/react-monorepo/files/packages/layouts/tsconfig.json +4 -0
  551. package/templates/react-monorepo/files/packages/types/.bin/openapi.js +32 -0
  552. package/templates/react-monorepo/files/packages/types/.bin/secrets.js +57 -0
  553. package/templates/react-monorepo/files/packages/types/README.md +28 -0
  554. package/templates/react-monorepo/files/packages/types/eslint.config.mjs +3 -0
  555. package/templates/react-monorepo/files/packages/types/openapi-ts.config.ts +22 -0
  556. package/templates/react-monorepo/files/packages/types/package.json +29 -0
  557. package/templates/react-monorepo/files/packages/types/src/index.ts +4 -0
  558. package/templates/react-monorepo/files/packages/types/src/types/api/index.ts +9 -0
  559. package/templates/react-monorepo/files/packages/types/src/types/api/zod.gen.ts +5 -0
  560. package/templates/react-monorepo/files/packages/types/tsconfig.json +7 -0
  561. package/templates/react-monorepo/files/packages/ui/components.json +21 -0
  562. package/templates/react-monorepo/files/packages/ui/eslint.config.mjs +13 -0
  563. package/templates/react-monorepo/files/packages/ui/package.json +44 -0
  564. package/templates/react-monorepo/files/packages/ui/src/components/brand/logo.tsx +51 -0
  565. package/templates/react-monorepo/files/packages/ui/src/components/brand/social-icons.tsx +37 -0
  566. package/templates/react-monorepo/files/packages/ui/src/components/form/form.tsx +120 -0
  567. package/templates/react-monorepo/files/packages/ui/src/components/ui/alert.tsx +25 -0
  568. package/templates/react-monorepo/files/packages/ui/src/components/ui/button.tsx +43 -0
  569. package/templates/react-monorepo/files/packages/ui/src/components/ui/calendar.tsx +78 -0
  570. package/templates/react-monorepo/files/packages/ui/src/components/ui/card.tsx +44 -0
  571. package/templates/react-monorepo/files/packages/ui/src/components/ui/checkbox.tsx +16 -0
  572. package/templates/react-monorepo/files/packages/ui/src/components/ui/date-picker.tsx +76 -0
  573. package/templates/react-monorepo/files/packages/ui/src/components/ui/input.tsx +22 -0
  574. package/templates/react-monorepo/files/packages/ui/src/components/ui/label.tsx +19 -0
  575. package/templates/react-monorepo/files/packages/ui/src/components/ui/modal.tsx +94 -0
  576. package/templates/react-monorepo/files/packages/ui/src/components/ui/popover.tsx +31 -0
  577. package/templates/react-monorepo/files/packages/ui/src/components/ui/progress.tsx +33 -0
  578. package/templates/react-monorepo/files/packages/ui/src/components/ui/search-input.tsx +69 -0
  579. package/templates/react-monorepo/files/packages/ui/src/components/ui/select.tsx +80 -0
  580. package/templates/react-monorepo/files/packages/ui/src/components/ui/skeleton.tsx +12 -0
  581. package/templates/react-monorepo/files/packages/ui/src/components/ui/sonner.tsx +23 -0
  582. package/templates/react-monorepo/files/packages/ui/src/components/ui/spinner.tsx +8 -0
  583. package/templates/react-monorepo/files/packages/ui/src/components/ui/textarea.tsx +22 -0
  584. package/templates/react-monorepo/files/packages/ui/src/index.ts +45 -0
  585. package/templates/react-monorepo/files/packages/ui/src/lib/utils.ts +7 -0
  586. package/templates/react-monorepo/files/packages/ui/src/lib/zod-setup.ts +28 -0
  587. package/templates/react-monorepo/files/packages/ui/src/meta/brand.ts +18 -0
  588. package/templates/react-monorepo/files/packages/ui/src/meta/meta-context.ts +30 -0
  589. package/templates/react-monorepo/files/packages/ui/src/meta/meta-provider.tsx +24 -0
  590. package/templates/react-monorepo/files/packages/ui/src/meta/page-meta.tsx +69 -0
  591. package/templates/react-monorepo/files/packages/ui/src/meta/use-meta-config.ts +11 -0
  592. package/templates/react-monorepo/files/packages/ui/src/styles/globals.css +285 -0
  593. package/templates/react-monorepo/files/packages/ui/src/theme/init-script.ts +23 -0
  594. package/templates/react-monorepo/files/packages/ui/src/theme/theme-colors.ts +14 -0
  595. package/templates/react-monorepo/files/packages/ui/src/theme/theme-context.ts +60 -0
  596. package/templates/react-monorepo/files/packages/ui/src/theme/theme-provider.tsx +101 -0
  597. package/templates/react-monorepo/files/packages/ui/src/theme/theme-toggle.tsx +40 -0
  598. package/templates/react-monorepo/files/packages/ui/src/theme/use-theme.ts +11 -0
  599. package/templates/react-monorepo/files/packages/ui/tsconfig.json +9 -0
  600. package/templates/react-monorepo/files/turbo.json +24 -0
  601. package/templates/react-monorepo/template.json +230 -0
@@ -0,0 +1,57 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ // Pulls this workspace's env from Infisical into the matching .env file.
7
+ // The Infisical path is derived from the package name, e.g.
8
+ // @scope/types -> /frontend/types, landing -> /frontend/landing
9
+ //
10
+ // The project ID comes from the environment rather than being hardcoded: it
11
+ // identifies one organisation's vault, so a value baked in here would follow
12
+ // every copy of this scaffold to projects it has nothing to do with. Put it in
13
+ // your shell profile, or in a committed `.infisical.json`.
14
+ const PROJECT_ID = process.env.INFISICAL_PROJECT_ID;
15
+ const SECRET_ROOT = process.env.INFISICAL_PATH_PREFIX ?? '/frontend';
16
+
17
+ const ENV_FILES = {
18
+ dev: '.env',
19
+ test: '.env.test',
20
+ staging: '.env.staging',
21
+ prod: '.env.production'
22
+ };
23
+
24
+ const normalizeEnv = (raw) => {
25
+ if (['dev', 'development'].includes(raw)) return 'dev';
26
+ if (['test', 'testing'].includes(raw)) return 'test';
27
+ if (['prod', 'production'].includes(raw)) return 'prod';
28
+ if (raw === 'staging') return 'staging';
29
+ throw new Error(`Unknown env '${raw}' (use one of: dev, test, staging, prod)`);
30
+ };
31
+
32
+ const parseEnvArg = () => {
33
+ const args = process.argv.slice(2);
34
+ const flagIndex = args.findIndex((a) => a === '-e' || a === '--env');
35
+ if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1];
36
+ const inline = args.find((a) => a.startsWith('--env='));
37
+ if (inline) return inline.slice('--env='.length);
38
+ return 'development';
39
+ };
40
+
41
+ const __dirname = dirname(fileURLToPath(import.meta.url));
42
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
43
+ const slug = pkg.name.replace(/^@[^/]+\//, '');
44
+ const secretPath = `${SECRET_ROOT}/${slug}`;
45
+
46
+ if (!PROJECT_ID) {
47
+ console.error('INFISICAL_PROJECT_ID is not set — nothing to fetch from.');
48
+ process.exit(1);
49
+ }
50
+
51
+ const env = normalizeEnv(parseEnvArg());
52
+ const envFile = ENV_FILES[env];
53
+
54
+ console.log(`Fetching secrets for '${slug}' (${env}) -> ${envFile}...`);
55
+ execSync(`infisical export --projectId="${PROJECT_ID}" --path="${secretPath}" --env=${env} > ${envFile}`, {
56
+ stdio: 'inherit'
57
+ });
@@ -0,0 +1,20 @@
1
+ # Copy to .env. Vite only exposes variables prefixed VITE_, and inlines them at
2
+ # build time — never put a secret here, it ships to the browser.
3
+
4
+ # Backend base URL. Better Auth lives at ${VITE_APP_API_URL}/auth.
5
+ VITE_APP_API_URL='http://localhost:5000'
6
+
7
+ # Sibling app origins. All four share one session cookie across subdomains, so
8
+ # these must agree with the backend's BETTER_AUTH_COOKIE_DOMAIN and its
9
+ # trustedOrigins list, or login will appear to succeed and then bounce.
10
+ VITE_APP_LANDING='http://localhost:3000'
11
+ VITE_APP_AUTH_HOST='http://localhost:3001'
12
+ VITE_APP_CLIENT_HOST='http://localhost:3002'
13
+ VITE_APP_ADMIN_HOST='http://localhost:3003'
14
+
15
+ # This app's own dev port.
16
+ PORT='3000'
17
+
18
+ # Canonical public URL, used for sitemap/robots/OG tags at build time.
19
+ VITE_APP_SITE_URL='http://localhost:3000'
20
+ VITE_APP_SUPPORT_EMAIL='support@example.com'
@@ -0,0 +1,3 @@
1
+ import config from '@acme/config/eslint';
2
+
3
+ export default config;
@@ -0,0 +1,51 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
7
+ <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
8
+ <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
9
+ <link rel="icon" href="/favicon.ico" sizes="any" />
10
+ <link rel="manifest" href="/site.webmanifest" />
11
+ <meta name="theme-color" content="%THEME_LIGHT%" />
12
+ <!--
13
+ Applies the saved (or system) theme before first paint, so the app never
14
+ flashes light then flips to dark. Mirrors `themeInitScript` in @acme/ui —
15
+ inlined because it must run before any module loads. Keep the two in sync.
16
+ %THEME_LIGHT/DARK% come from THEME_COLORS via the shared vite config.
17
+ -->
18
+ <script>
19
+ (function () {
20
+ try {
21
+ var m = localStorage.getItem('acme-theme');
22
+ var d =
23
+ m === 'dark' || ((m === null || m === 'system') && matchMedia('(prefers-color-scheme: dark)').matches);
24
+ var r = document.documentElement;
25
+ r.classList.toggle('dark', d);
26
+ r.style.colorScheme = d ? 'dark' : 'light';
27
+ var t = document.querySelector('meta[name="theme-color"]');
28
+ if (t) t.setAttribute('content', d ? '%THEME_DARK%' : '%THEME_LIGHT%');
29
+ } catch (e) {}
30
+ })();
31
+ </script>
32
+ <!--
33
+ globals.css only styles `body`, so without this the UA canvas paints white
34
+ for the moment before the stylesheet lands — a white flash on a dark load.
35
+ -->
36
+ <style>
37
+ html {
38
+ background: %THEME_LIGHT%;
39
+ }
40
+ html.dark {
41
+ background: %THEME_DARK%;
42
+ }
43
+ </style>
44
+ <meta name="description" content="Acme Corp." />
45
+ <title>%APP_TITLE%</title>
46
+ </head>
47
+ <body>
48
+ <div id="root"></div>
49
+ <script type="module" src="/src/main.tsx"></script>
50
+ </body>
51
+ </html>
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "landing",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc --noEmit && vite build",
9
+ "preview": "vite preview",
10
+ "lint": "eslint .",
11
+ "typecheck": "tsc --noEmit",
12
+ "secrets": "node .bin/secrets.js"
13
+ },
14
+ "dependencies": {
15
+ "@acme/api": "workspace:*",
16
+ "@acme/auth": "workspace:*",
17
+ "@acme/layouts": "workspace:*",
18
+ "@acme/types": "workspace:*",
19
+ "@acme/ui": "workspace:*",
20
+ "@reduxjs/toolkit": "^2.12.0",
21
+ "lucide-react": "^1.17.0",
22
+ "react": "^19.2.6",
23
+ "react-dom": "^19.2.6",
24
+ "react-redux": "^9.3.0",
25
+ "react-router": "^8.2.0"
26
+ },
27
+ "devDependencies": {
28
+ "@acme/config": "workspace:*",
29
+ "@types/react": "^19.2.14",
30
+ "@types/react-dom": "^19.2.3",
31
+ "vite": "^8.0.12"
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ // The Landing app is driven by the router (see app/router.tsx); this module is
2
+ // intentionally empty and no longer rendered.
3
+ export {};
@@ -0,0 +1,42 @@
1
+ import type { ReactNode } from 'react';
2
+ import { Provider } from 'react-redux';
3
+ import { configureApi } from '@acme/api';
4
+ import { AuthProvider, configureAuth, redirectToLogin } from '@acme/auth';
5
+ import { MetaProvider, ThemeProvider, Toaster, installZodErrorMap } from '@acme/ui';
6
+ import { store } from './store';
7
+
8
+ const env = import.meta.env;
9
+ const apiBaseUrl = env.VITE_APP_API_URL;
10
+ const authAppUrl = env.VITE_APP_AUTH_HOST as string;
11
+
12
+ const trustedOrigins = [env.VITE_APP_LANDING, env.VITE_APP_CLIENT_HOST, env.VITE_APP_ADMIN_HOST, authAppUrl].filter(
13
+ (value): value is string => Boolean(value)
14
+ );
15
+
16
+ // Wire the shared API + auth clients once, before rendering. The landing site is public, so a 401 is not automatically a redirect.
17
+ configureApi({ baseUrl: apiBaseUrl, onUnauthorized: () => redirectToLogin() });
18
+ configureAuth({
19
+ authApiBaseUrl: `${apiBaseUrl}/auth`,
20
+ authAppUrl,
21
+ trustedOrigins,
22
+ defaultRedirect: (env.VITE_APP_LANDING as string | undefined) ?? window.location.origin
23
+ });
24
+ installZodErrorMap();
25
+
26
+ export function Providers({ children }: { children: ReactNode }) {
27
+ return (
28
+ // ThemeProvider above the Redux Provider: it only touches the document
29
+ // (`dark` class, color-scheme, theme-color meta) and must not re-render
30
+ // through the store.
31
+ <ThemeProvider>
32
+ <MetaProvider>
33
+ <Provider store={store}>
34
+ <AuthProvider>
35
+ {children}
36
+ <Toaster />
37
+ </AuthProvider>
38
+ </Provider>
39
+ </MetaProvider>
40
+ </ThemeProvider>
41
+ );
42
+ }
@@ -0,0 +1,21 @@
1
+ import { createBrowserRouter } from 'react-router';
2
+ import { ErrorBoundary, MarketingLayout, NotFound } from '@acme/layouts';
3
+ import { HomeRoute } from '../routes/home';
4
+
5
+ /**
6
+ * The landing site is public — no auth guard. `MarketingLayout` takes `header`
7
+ * and `footer` slots and falls back to the router's <Outlet /> for content.
8
+ * `ErrorBoundary` wraps it rather than being the route's `errorElement`: it is
9
+ * a plain React error boundary taking `children`.
10
+ */
11
+ export const router = createBrowserRouter([
12
+ {
13
+ element: (
14
+ <ErrorBoundary>
15
+ <MarketingLayout />
16
+ </ErrorBoundary>
17
+ ),
18
+ children: [{ index: true, element: <HomeRoute /> }]
19
+ },
20
+ { path: '*', element: <NotFound /> }
21
+ ]);
@@ -0,0 +1,18 @@
1
+ import { makeStore } from '@acme/api';
2
+ import { authReducer } from '@acme/auth';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+
5
+ // `auth` holds the Better Auth session so the header can swap its CTAs for a
6
+ // signed-in visitor. Landing still has no protected routes and no guards — it
7
+ // reads the session purely to render, and every page stays fully public.
8
+ export const store = makeStore({
9
+ reducer: {
10
+ auth: authReducer
11
+ }
12
+ });
13
+
14
+ export type RootState = ReturnType<typeof store.getState>;
15
+ export type AppDispatch = typeof store.dispatch;
16
+
17
+ export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
18
+ export const useAppSelector = useSelector.withTypes<RootState>();
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Every indexable route, with the metadata that describes it.
3
+ *
4
+ * **This is the single source.** `PageSeo` renders per-route tags from it and
5
+ * the build emits `sitemap.xml` from it (see `vite.config.ts`), so the sitemap
6
+ * cannot list a route that does not exist or miss one that does — the classic
7
+ * way a sitemap rots. Add a route here on the same commit that adds it to
8
+ * `app/router.tsx`, and remove it the same way; a sitemap advertising a 404
9
+ * stays invisible until a crawler finds it.
10
+ *
11
+ * Kept free of React imports: `vite.config.ts` imports this directly, and the
12
+ * config is bundled with esbuild.
13
+ */
14
+ export type SeoRoute = {
15
+ /** Path as it appears in the router, leading slash, no trailing slash. */
16
+ path: string;
17
+ /** Page segment only — `MetaProvider` appends the brand suffix. */
18
+ title: string;
19
+ description: string;
20
+ /** Relative priority for the sitemap; the homepage leads. */
21
+ priority: string;
22
+ changefreq: 'daily' | 'weekly' | 'monthly' | 'yearly';
23
+ };
24
+
25
+ export const SEO_ROUTES: SeoRoute[] = [
26
+ {
27
+ path: '/',
28
+ title: 'Home',
29
+ description: 'Replace with the description search results should show.',
30
+ priority: '1.0',
31
+ changefreq: 'weekly'
32
+ }
33
+ ];
34
+
35
+ /**
36
+ * The one origin that may be indexed. Staging and preview builds compare
37
+ * unequal and are served `noindex`, so a preview deploy cannot outrank
38
+ * production for its own content.
39
+ */
40
+ export const PRODUCTION_ORIGIN = 'https://example.com';
41
+
42
+ export const seoRouteFor = (path: string) => SEO_ROUTES.find((route) => route.path === path);
43
+
44
+ /**
45
+ * Absolute URL for a path — canonical, `og:url` and sitemap entries all need one.
46
+ *
47
+ * `origin` is passed in rather than read here so this file stays free of
48
+ * `import.meta.env`: it is imported by `vite.config.ts`, where `import.meta.env`
49
+ * does not exist. App code gets the origin from its env, the build from its own
50
+ * `loadEnv`.
51
+ */
52
+ export const absoluteUrl = (path: string, origin: string) => (path === '/' ? `${origin}/` : `${origin}${path}`);
53
+
54
+ /** Strip a trailing slash so joins don't produce `//about`. */
55
+ export const normalizeOrigin = (origin: string) => origin.replace(/\/$/, '');
56
+
57
+ /*
58
+ * Not included here: **prerendering**. `vite build` emits a single SPA shell,
59
+ * so a crawler that does not execute JavaScript sees an empty `#root` for every
60
+ * route. `robots.txt` and `sitemap.xml` are emitted from this table at build
61
+ * time (see `vite.config.ts`), which is the half that matters for discovery —
62
+ * but if these pages need to rank on their content, add a post-build pass that
63
+ * renders each `SEO_ROUTES` entry to `dist/<path>/index.html`. Drive it from
64
+ * this table, not a second list, or the sitemap and the prerendered set drift.
65
+ */
@@ -0,0 +1,10 @@
1
+ const env = import.meta.env;
2
+
3
+ export const API_URL = env.VITE_APP_API_URL;
4
+ export const AUTH_HOST = env.VITE_APP_AUTH_HOST;
5
+ export const CLIENT_HOST = env.VITE_APP_CLIENT_HOST;
6
+ /** Support inbox shown on /contact. Per-environment, so it is never hardcoded —
7
+ * it must match the backend's SMTP_SUPPORT_EMAIL, which is where the form
8
+ * actually posts. Falsy when the build arg is missing; the UI hides the block
9
+ * rather than rendering `mailto:undefined`. */
10
+ export const SUPPORT_EMAIL = env.VITE_APP_SUPPORT_EMAIL;
@@ -0,0 +1,14 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { RouterProvider } from 'react-router';
4
+ import '@acme/ui/globals.css';
5
+ import { Providers } from './app/providers';
6
+ import { router } from './app/router';
7
+
8
+ createRoot(document.getElementById('root')!).render(
9
+ <StrictMode>
10
+ <Providers>
11
+ <RouterProvider router={router} />
12
+ </Providers>
13
+ </StrictMode>
14
+ );
@@ -0,0 +1,18 @@
1
+ import { PageMeta } from '@acme/ui';
2
+ import { Section, SectionHeading } from '@acme/layouts';
3
+
4
+ export function HomeRoute() {
5
+ return (
6
+ <>
7
+ {/* `title` is the page segment only — MetaProvider appends the brand. */}
8
+ <PageMeta title="Home" />
9
+ <Section>
10
+ <SectionHeading
11
+ eyebrow="Acme Corp"
12
+ title="Replace this with your hero"
13
+ lede="One sentence on what this product does, written for someone who has never heard of it."
14
+ />
15
+ </Section>
16
+ </>
17
+ );
18
+ }
@@ -0,0 +1,15 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="vite-plugin-svgr/client" />
3
+
4
+ interface ImportMetaEnv {
5
+ VITE_APP_API_URL: string;
6
+ VITE_APP_ALLOWED_HOSTS: string;
7
+ VITE_APP_AUTH_HOST: string;
8
+ VITE_APP_CLIENT_HOST: string;
9
+ VITE_APP_ADMIN_HOST: string;
10
+ VITE_APP_SUPPORT_EMAIL: string;
11
+ }
12
+
13
+ interface ImportMeta {
14
+ readonly env: ImportMetaEnv;
15
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "@acme/config/tsconfig/react.json",
3
+ "compilerOptions": {
4
+ "types": ["vite/client"],
5
+ "paths": {
6
+ "@/*": ["./src/*"]
7
+ }
8
+ },
9
+ "include": ["src"]
10
+ }
@@ -0,0 +1,169 @@
1
+ import { defineAppConfig } from '@acme/config/vite';
2
+ import { BRAND } from '@acme/ui/brand';
3
+ import { THEME_COLORS } from '@acme/ui/theme-colors';
4
+ import { loadEnv, type Plugin } from 'vite';
5
+ import { PRODUCTION_ORIGIN, SEO_ROUTES, absoluteUrl, normalizeOrigin } from './src/features/seo/routes';
6
+
7
+ /**
8
+ * Emits `robots.txt` and `sitemap.xml` at build time from `SEO_ROUTES`.
9
+ *
10
+ * Generated rather than committed to `public/` so the sitemap cannot drift from
11
+ * the routes that actually exist. A sitemap advertising a 404, or missing a real
12
+ * page, is the usual failure here and it stays invisible until a crawler finds
13
+ * it. `/roadmap` is absent from the table precisely because its route is
14
+ * currently commented out in `app/router.tsx`.
15
+ *
16
+ * `apply: 'build'` — `public/` isn't written in dev and the dev server has no
17
+ * use for either file.
18
+ */
19
+ function seoFiles(origin: string, indexable: boolean): Plugin {
20
+ return {
21
+ name: 'acme:seo-files',
22
+ apply: 'build',
23
+ generateBundle() {
24
+ // Non-production keeps the same file, inverted: a dev server serving the
25
+ // same copy as production is duplicate content, and it must not advertise a
26
+ // sitemap it doesn't want crawled.
27
+ const robots = (
28
+ indexable
29
+ ? [
30
+ '# Public marketing site — crawling is welcome here.',
31
+ '# The app, auth and admin subdomains are deliberately noindex (MAI-102).',
32
+ 'User-agent: *',
33
+ 'Allow: /',
34
+ ...(origin ? ['', `Sitemap: ${origin}/sitemap.xml`] : []),
35
+ ''
36
+ ]
37
+ : [
38
+ `# Not production (origin: ${origin || 'unset'}). Only ${PRODUCTION_ORIGIN} should be indexed.`,
39
+ '# Paired with the noindex meta tag in index.html — robots.txt alone does not deindex.',
40
+ 'User-agent: *',
41
+ 'Disallow: /',
42
+ ''
43
+ ]
44
+ ).join('\n');
45
+ this.emitFile({ type: 'asset', fileName: 'robots.txt', source: robots });
46
+
47
+ // Every <loc> must be absolute per the sitemap spec, so without an origin
48
+ // emit nothing rather than something invalid. robots.txt above then also
49
+ // omits its Sitemap line, keeping the two consistent.
50
+ if (!origin) {
51
+ this.warn('VITE_APP_SITE_URL is not set — skipping sitemap.xml, which requires absolute URLs.');
52
+ return;
53
+ }
54
+
55
+ const urls = SEO_ROUTES.map(
56
+ (route) =>
57
+ '\t<url>\n' +
58
+ `\t\t<loc>${absoluteUrl(route.path, origin)}</loc>\n` +
59
+ `\t\t<changefreq>${route.changefreq}</changefreq>\n` +
60
+ `\t\t<priority>${route.priority}</priority>\n` +
61
+ '\t</url>'
62
+ ).join('\n');
63
+
64
+ this.emitFile({
65
+ type: 'asset',
66
+ fileName: 'sitemap.xml',
67
+ source:
68
+ '<?xml version="1.0" encoding="UTF-8"?>\n' +
69
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
70
+ `${urls}\n` +
71
+ '</urlset>\n'
72
+ });
73
+ }
74
+ };
75
+ }
76
+
77
+ /**
78
+ * When the security policy expires, as an RFC 9116 `Expires:` field must. A date
79
+ * in the past makes the whole file invalid to the tools that read it, so this
80
+ * needs bumping — along with a review of the policy itself — before it lapses.
81
+ */
82
+ const SECURITY_TXT_EXPIRES = '2027-09-01T00:00:00.000Z';
83
+
84
+ /**
85
+ * Emits `/.well-known/security.txt` (RFC 9116) pointing at the `/security` route.
86
+ *
87
+ * Researchers and automated scanners look for this file, not for a footer link,
88
+ * so without it the policy page is one nobody arrives at. `Contact:` must stay
89
+ * the same address as the policy states in its Sections 1, 8 and 19.
90
+ *
91
+ * Production-only, unlike `robots.txt`: `Canonical:` must be the URL the file is
92
+ * actually served from, so a preview environment publishing one that claims to
93
+ * live on the production origin would be advertising a false record rather than
94
+ * a harmless duplicate. `docker/nginx.conf` needs its `^~ /.well-known/` block
95
+ * for this to be reachable at all — the dotfile deny would otherwise 403 it.
96
+ */
97
+ function securityTxt(origin: string, indexable: boolean, securityEmail: string): Plugin {
98
+ return {
99
+ name: 'acme:security-txt',
100
+ apply: 'build',
101
+ generateBundle() {
102
+ if (!indexable || !origin || !securityEmail) return;
103
+
104
+ this.emitFile({
105
+ type: 'asset',
106
+ fileName: '.well-known/security.txt',
107
+ source: [
108
+ '# Acme Corp — Security & Responsible Disclosure',
109
+ `# Full policy: ${absoluteUrl('/security', origin)}`,
110
+ '',
111
+ `Contact: mailto:${securityEmail}`,
112
+ `Expires: ${SECURITY_TXT_EXPIRES}`,
113
+ `Policy: ${absoluteUrl('/security', origin)}`,
114
+ 'Preferred-Languages: en',
115
+ `Canonical: ${origin}/.well-known/security.txt`,
116
+ ''
117
+ ].join('\n')
118
+ });
119
+ }
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Injects `noindex, nofollow` into `index.html` on every non-production build.
125
+ *
126
+ * The meta tag is the half that actually deindexes — `robots.txt` only asks a
127
+ * crawler not to fetch, and a URL it already knows can still be listed without
128
+ * ever being fetched. Both halves are emitted together, from the same flag.
129
+ *
130
+ * `index.html` is the shell the prerender pass copies for all seven routes, so
131
+ * one tag here covers the whole site.
132
+ */
133
+ function noindexOffProduction(indexable: boolean): Plugin {
134
+ return {
135
+ name: 'acme:noindex-off-production',
136
+ apply: 'build',
137
+ transformIndexHtml() {
138
+ if (indexable) return;
139
+ return [{ tag: 'meta', attrs: { name: 'robots', content: 'noindex, nofollow' }, injectTo: 'head' }];
140
+ }
141
+ };
142
+ }
143
+
144
+ // `loadEnv` rather than `process.env`: VITE_APP_* live in the app's `.env` files
145
+ // (pulled from Infisical), not the shell, so the build would otherwise never see
146
+ // the site URL.
147
+ const env = loadEnv(process.env.NODE_ENV ?? 'production', import.meta.dirname, '');
148
+ const siteOrigin = normalizeOrigin(env.VITE_APP_SITE_URL ?? '');
149
+ // Omitted rather than guessed: a security.txt pointing at an unmonitored
150
+ // address is worse than none at all, so an unset value skips the file.
151
+ const securityEmail = env.VITE_APP_SUPPORT_EMAIL ?? '';
152
+
153
+ // An unset or unrecognised origin counts as non-production — see PRODUCTION_ORIGIN.
154
+ const indexable = siteOrigin === PRODUCTION_ORIGIN;
155
+
156
+ // `themeColors` substitutes %THEME_LIGHT%/%THEME_DARK% into index.html — the
157
+ // pre-paint theme script and the `html` background both need them, and HTML
158
+ // can't import. `appTitle` substitutes %APP_TITLE% for the same reason: the
159
+ // static <title> must match the suffix MetaProvider appends at runtime.
160
+ export default defineAppConfig({
161
+ rootDir: import.meta.dirname,
162
+ themeColors: THEME_COLORS,
163
+ appTitle: BRAND.name,
164
+ plugins: [
165
+ seoFiles(siteOrigin, indexable),
166
+ securityTxt(siteOrigin, indexable, securityEmail),
167
+ noindexOffProduction(indexable)
168
+ ]
169
+ });
@@ -0,0 +1,61 @@
1
+ #!/bin/sh
2
+ # Build + push one frontend app image.
3
+ #
4
+ # ./build.sh <admin|auth|client|landing> [env] [tag]
5
+ #
6
+ # ./build.sh client # uses .env -> :latest
7
+ # ./build.sh client prod # uses .env.production
8
+ # ./build.sh client prod 26_07_26_1
9
+ #
10
+ # The VITE_* URLs are compiled INTO the bundle, so the image is specific to the
11
+ # environment it was built for. That is why the env name is an argument: the same
12
+ # image cannot be promoted from staging to prod. Pull the env file first with
13
+ # yarn workspace <app> secrets -e <env>
14
+ set -eu
15
+
16
+ APP="${1:-}"
17
+ ENV_NAME="${2:-dev}"
18
+ TAG="${3:-latest}"
19
+ REGISTRY="aurostack.dev/acme-corp"
20
+ PLATFORMS="linux/amd64,linux/arm64"
21
+
22
+ case "$APP" in
23
+ admin | auth | client | landing) ;;
24
+ *)
25
+ echo "usage: $0 <admin|auth|client|landing> [dev|staging|prod] [tag]" >&2
26
+ exit 1
27
+ ;;
28
+ esac
29
+
30
+ case "$ENV_NAME" in
31
+ dev) ENV_FILE="apps/$APP/.env" ;;
32
+ test) ENV_FILE="apps/$APP/.env.test" ;;
33
+ staging) ENV_FILE="apps/$APP/.env.staging" ;;
34
+ prod | production) ENV_FILE="apps/$APP/.env.production" ;;
35
+ *) echo "unknown env '$ENV_NAME' (dev|test|staging|prod)" >&2; exit 1 ;;
36
+ esac
37
+
38
+ [ -f "$ENV_FILE" ] || {
39
+ echo "missing $ENV_FILE — run: yarn workspace $APP secrets -e $ENV_NAME" >&2
40
+ exit 1
41
+ }
42
+
43
+ # Read a var out of the env file, tolerating the quoted style these files use.
44
+ read_var() {
45
+ sed -n "s/^$1=['\"]\{0,1\}\([^'\"]*\)['\"]\{0,1\}$/\1/p" "$ENV_FILE" | tail -1
46
+ }
47
+
48
+ BUILD_ARGS="--build-arg APP=$APP"
49
+ for VAR in VITE_APP_API_URL VITE_APP_AUTH_HOST VITE_APP_CLIENT_HOST VITE_APP_ADMIN_HOST VITE_APP_LANDING VITE_APP_SUPPORT_EMAIL; do
50
+ VALUE="$(read_var "$VAR")"
51
+ [ -n "$VALUE" ] && BUILD_ARGS="$BUILD_ARGS --build-arg $VAR=$VALUE"
52
+ done
53
+
54
+ echo "Building $APP for '$ENV_NAME' -> $REGISTRY/web-$APP:$TAG"
55
+ echo " (URLs baked in from $ENV_FILE)"
56
+
57
+ # shellcheck disable=SC2086
58
+ docker buildx build --push --platform "$PLATFORMS" \
59
+ $BUILD_ARGS \
60
+ -t "$REGISTRY/web-$APP:$TAG" \
61
+ .