sovrium 0.0.2

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 (527) hide show
  1. package/CHANGELOG.md +3497 -0
  2. package/LICENSE.md +147 -0
  3. package/LICENSE_EE.md +297 -0
  4. package/README.md +321 -0
  5. package/drizzle/0000_melted_kabuki.sql +163 -0
  6. package/drizzle/meta/0000_snapshot.json +1216 -0
  7. package/drizzle/meta/_journal.json +13 -0
  8. package/package.json +167 -0
  9. package/schemas/0.0.1/app.openapi.json +70 -0
  10. package/schemas/0.0.1/app.schema.json +7961 -0
  11. package/schemas/0.0.2/app.openapi.json +80 -0
  12. package/schemas/0.0.2/app.schema.json +8829 -0
  13. package/schemas/development/app.openapi.json +70 -0
  14. package/schemas/development/app.schema.json +7456 -0
  15. package/src/application/errors/app-validation-error.ts +14 -0
  16. package/src/application/errors/static-generation-error.ts +16 -0
  17. package/src/application/metadata/favicon-transformer.ts +127 -0
  18. package/src/application/models/server.ts +27 -0
  19. package/src/application/ports/models/user-metadata.ts +36 -0
  20. package/src/application/ports/models/user-session.ts +34 -0
  21. package/src/application/ports/repositories/activity-log-repository.ts +68 -0
  22. package/src/application/ports/repositories/activity-repository.ts +49 -0
  23. package/src/application/ports/repositories/analytics-repository.ts +164 -0
  24. package/src/application/ports/repositories/auth-repository.ts +33 -0
  25. package/src/application/ports/repositories/batch-repository.ts +86 -0
  26. package/src/application/ports/repositories/comment-repository.ts +150 -0
  27. package/src/application/ports/repositories/index.ts +41 -0
  28. package/src/application/ports/repositories/table-repository.ts +139 -0
  29. package/src/application/ports/services/css-compiler.ts +55 -0
  30. package/src/application/ports/services/index.ts +16 -0
  31. package/src/application/ports/services/page-renderer.ts +79 -0
  32. package/src/application/ports/services/server-factory.ts +80 -0
  33. package/src/application/ports/services/static-site-generator.ts +82 -0
  34. package/src/application/use-cases/activity/programs.ts +66 -0
  35. package/src/application/use-cases/analytics/collect-page-view.ts +114 -0
  36. package/src/application/use-cases/analytics/purge-old-data.ts +40 -0
  37. package/src/application/use-cases/analytics/query-campaigns.ts +43 -0
  38. package/src/application/use-cases/analytics/query-devices.ts +36 -0
  39. package/src/application/use-cases/analytics/query-overview.ts +50 -0
  40. package/src/application/use-cases/analytics/query-pages.ts +40 -0
  41. package/src/application/use-cases/analytics/query-referrers.ts +43 -0
  42. package/src/application/use-cases/analytics/ua-parser.ts +89 -0
  43. package/src/application/use-cases/analytics/visitor-hash.ts +77 -0
  44. package/src/application/use-cases/auth/bootstrap-admin.ts +270 -0
  45. package/src/application/use-cases/list-activity-logs.ts +123 -0
  46. package/src/application/use-cases/server/generate-static-helpers.ts +374 -0
  47. package/src/application/use-cases/server/generate-static.ts +287 -0
  48. package/src/application/use-cases/server/start-server.ts +118 -0
  49. package/src/application/use-cases/server/startup-error-handler.ts +69 -0
  50. package/src/application/use-cases/server/static-content-generators.ts +182 -0
  51. package/src/application/use-cases/server/static-language-generators.ts +181 -0
  52. package/src/application/use-cases/server/static-url-rewriter.ts +237 -0
  53. package/src/application/use-cases/server/translation-replacer.ts +164 -0
  54. package/src/application/use-cases/tables/activity-programs.ts +93 -0
  55. package/src/application/use-cases/tables/batch-operations.ts +156 -0
  56. package/src/application/use-cases/tables/comment-programs.ts +436 -0
  57. package/src/application/use-cases/tables/permissions/permissions.ts +25 -0
  58. package/src/application/use-cases/tables/programs.ts +435 -0
  59. package/src/application/use-cases/tables/table-operations.ts +412 -0
  60. package/src/application/use-cases/tables/user-role.ts +52 -0
  61. package/src/application/use-cases/tables/utils/display-formatter.ts +471 -0
  62. package/src/application/use-cases/tables/utils/field-read-filter.ts +189 -0
  63. package/src/application/use-cases/tables/utils/list-helpers.ts +122 -0
  64. package/src/application/use-cases/tables/utils/record-transformer.ts +319 -0
  65. package/src/cli.ts +370 -0
  66. package/src/domain/errors/create-tagged-error.ts +36 -0
  67. package/src/domain/errors/index.ts +78 -0
  68. package/src/domain/models/api/analytics.ts +179 -0
  69. package/src/domain/models/api/auth.ts +231 -0
  70. package/src/domain/models/api/common.ts +60 -0
  71. package/src/domain/models/api/error.ts +89 -0
  72. package/src/domain/models/api/health.ts +38 -0
  73. package/src/domain/models/api/index.ts +42 -0
  74. package/src/domain/models/api/request.ts +132 -0
  75. package/src/domain/models/api/tables.ts +444 -0
  76. package/src/domain/models/app/analytics/index.ts +129 -0
  77. package/src/domain/models/app/auth/config.ts +116 -0
  78. package/src/domain/models/app/auth/index.ts +230 -0
  79. package/src/domain/models/app/auth/methods/email-and-password.ts +67 -0
  80. package/src/domain/models/app/auth/methods/index.ts +11 -0
  81. package/src/domain/models/app/auth/methods/magic-link.ts +54 -0
  82. package/src/domain/models/app/auth/oauth/index.ts +8 -0
  83. package/src/domain/models/app/auth/oauth/providers.ts +105 -0
  84. package/src/domain/models/app/auth/plugins/admin.ts +130 -0
  85. package/src/domain/models/app/auth/plugins/index.ts +74 -0
  86. package/src/domain/models/app/auth/plugins/two-factor.ts +63 -0
  87. package/src/domain/models/app/auth/roles.ts +179 -0
  88. package/src/domain/models/app/auth/strategies.ts +191 -0
  89. package/src/domain/models/app/auth/validation.ts +127 -0
  90. package/src/domain/models/app/common/branded-ids.ts +200 -0
  91. package/src/domain/models/app/common/definitions.ts +187 -0
  92. package/src/domain/models/app/component/common/component-children.ts +119 -0
  93. package/src/domain/models/app/component/common/component-props.ts +89 -0
  94. package/src/domain/models/app/component/common/component-reference.ts +170 -0
  95. package/src/domain/models/app/component/component.ts +81 -0
  96. package/src/domain/models/app/components.ts +65 -0
  97. package/src/domain/models/app/description.ts +83 -0
  98. package/src/domain/models/app/index.ts +258 -0
  99. package/src/domain/models/app/language/language-config.ts +200 -0
  100. package/src/domain/models/app/languages.ts +205 -0
  101. package/src/domain/models/app/name.ts +66 -0
  102. package/src/domain/models/app/page/common/interactions/click-interaction.ts +116 -0
  103. package/src/domain/models/app/page/common/interactions/entrance-animation.ts +84 -0
  104. package/src/domain/models/app/page/common/interactions/hover-interaction.ts +144 -0
  105. package/src/domain/models/app/page/common/interactions/interactions.ts +64 -0
  106. package/src/domain/models/app/page/common/interactions/scroll-interaction.ts +93 -0
  107. package/src/domain/models/app/page/common/responsive.ts +114 -0
  108. package/src/domain/models/app/page/common/url.ts +35 -0
  109. package/src/domain/models/app/page/common/variable-reference.ts +53 -0
  110. package/src/domain/models/app/page/id.ts +44 -0
  111. package/src/domain/models/app/page/index.ts +270 -0
  112. package/src/domain/models/app/page/meta/analytics.ts +248 -0
  113. package/src/domain/models/app/page/meta/custom-elements.ts +180 -0
  114. package/src/domain/models/app/page/meta/dns-prefetch.ts +77 -0
  115. package/src/domain/models/app/page/meta/favicon-set.ts +203 -0
  116. package/src/domain/models/app/page/meta/favicon.ts +50 -0
  117. package/src/domain/models/app/page/meta/favicons-config.ts +73 -0
  118. package/src/domain/models/app/page/meta/index.ts +278 -0
  119. package/src/domain/models/app/page/meta/open-graph.ts +166 -0
  120. package/src/domain/models/app/page/meta/preload.ts +190 -0
  121. package/src/domain/models/app/page/meta/structured-data/article.ts +211 -0
  122. package/src/domain/models/app/page/meta/structured-data/breadcrumb.ts +115 -0
  123. package/src/domain/models/app/page/meta/structured-data/common-fields.ts +201 -0
  124. package/src/domain/models/app/page/meta/structured-data/education-event.ts +256 -0
  125. package/src/domain/models/app/page/meta/structured-data/faq-page.ts +127 -0
  126. package/src/domain/models/app/page/meta/structured-data/index.ts +95 -0
  127. package/src/domain/models/app/page/meta/structured-data/local-business.ts +247 -0
  128. package/src/domain/models/app/page/meta/structured-data/organization.ts +171 -0
  129. package/src/domain/models/app/page/meta/structured-data/person.ts +138 -0
  130. package/src/domain/models/app/page/meta/structured-data/postal-address.ts +106 -0
  131. package/src/domain/models/app/page/meta/structured-data/product.ts +214 -0
  132. package/src/domain/models/app/page/meta/twitter-card.ts +217 -0
  133. package/src/domain/models/app/page/name.ts +38 -0
  134. package/src/domain/models/app/page/path.ts +21 -0
  135. package/src/domain/models/app/page/scripts/external-scripts.ts +163 -0
  136. package/src/domain/models/app/page/scripts/features.ts +135 -0
  137. package/src/domain/models/app/page/scripts/inline-scripts.ts +114 -0
  138. package/src/domain/models/app/page/scripts/scripts.ts +102 -0
  139. package/src/domain/models/app/page/sections.ts +298 -0
  140. package/src/domain/models/app/pages.ts +61 -0
  141. package/src/domain/models/app/permissions/index.ts +61 -0
  142. package/src/domain/models/app/permissions/resource-action.ts +114 -0
  143. package/src/domain/models/app/permissions/roles.ts +120 -0
  144. package/src/domain/models/app/table/check-constraints.ts +105 -0
  145. package/src/domain/models/app/table/cycle-detection.ts +124 -0
  146. package/src/domain/models/app/table/database-identifier.ts +153 -0
  147. package/src/domain/models/app/table/field-name.ts +36 -0
  148. package/src/domain/models/app/table/field-types/advanced/array-field.ts +33 -0
  149. package/src/domain/models/app/table/field-types/advanced/autonumber-field.ts +54 -0
  150. package/src/domain/models/app/table/field-types/advanced/button-field.ts +56 -0
  151. package/src/domain/models/app/table/field-types/advanced/color-field.ts +57 -0
  152. package/src/domain/models/app/table/field-types/advanced/count-field.ts +54 -0
  153. package/src/domain/models/app/table/field-types/advanced/formula-field.ts +58 -0
  154. package/src/domain/models/app/table/field-types/advanced/geolocation-field.ts +49 -0
  155. package/src/domain/models/app/table/field-types/advanced/index.ts +16 -0
  156. package/src/domain/models/app/table/field-types/advanced/json-field.ts +25 -0
  157. package/src/domain/models/app/table/field-types/advanced/unknown-field.ts +85 -0
  158. package/src/domain/models/app/table/field-types/base-field.ts +42 -0
  159. package/src/domain/models/app/table/field-types/date-time/created-at-field.ts +49 -0
  160. package/src/domain/models/app/table/field-types/date-time/date-field.ts +95 -0
  161. package/src/domain/models/app/table/field-types/date-time/deleted-at-field.ts +56 -0
  162. package/src/domain/models/app/table/field-types/date-time/duration-field.ts +73 -0
  163. package/src/domain/models/app/table/field-types/date-time/index.ts +12 -0
  164. package/src/domain/models/app/table/field-types/date-time/updated-at-field.ts +50 -0
  165. package/src/domain/models/app/table/field-types/index.ts +19 -0
  166. package/src/domain/models/app/table/field-types/media/barcode-field.ts +58 -0
  167. package/src/domain/models/app/table/field-types/media/index.ts +10 -0
  168. package/src/domain/models/app/table/field-types/media/multiple-attachments-field.ts +80 -0
  169. package/src/domain/models/app/table/field-types/media/single-attachment-field.ts +81 -0
  170. package/src/domain/models/app/table/field-types/numeric/currency-field.ts +144 -0
  171. package/src/domain/models/app/table/field-types/numeric/decimal-field.ts +113 -0
  172. package/src/domain/models/app/table/field-types/numeric/index.ts +13 -0
  173. package/src/domain/models/app/table/field-types/numeric/integer-field.ts +98 -0
  174. package/src/domain/models/app/table/field-types/numeric/percentage-field.ts +115 -0
  175. package/src/domain/models/app/table/field-types/numeric/progress-field.ts +71 -0
  176. package/src/domain/models/app/table/field-types/numeric/rating-field.ts +74 -0
  177. package/src/domain/models/app/table/field-types/relational/index.ts +10 -0
  178. package/src/domain/models/app/table/field-types/relational/lookup-field.ts +46 -0
  179. package/src/domain/models/app/table/field-types/relational/relationship-field.ts +112 -0
  180. package/src/domain/models/app/table/field-types/relational/rollup-field.ts +58 -0
  181. package/src/domain/models/app/table/field-types/selection/checkbox-field.ts +51 -0
  182. package/src/domain/models/app/table/field-types/selection/index.ts +11 -0
  183. package/src/domain/models/app/table/field-types/selection/multi-select-field.ts +68 -0
  184. package/src/domain/models/app/table/field-types/selection/single-select-field.ts +54 -0
  185. package/src/domain/models/app/table/field-types/selection/status-field.ts +37 -0
  186. package/src/domain/models/app/table/field-types/text/email-field.ts +80 -0
  187. package/src/domain/models/app/table/field-types/text/index.ts +13 -0
  188. package/src/domain/models/app/table/field-types/text/long-text-field.ts +77 -0
  189. package/src/domain/models/app/table/field-types/text/phone-number-field.ts +82 -0
  190. package/src/domain/models/app/table/field-types/text/rich-text-field.ts +66 -0
  191. package/src/domain/models/app/table/field-types/text/single-line-text-field.ts +79 -0
  192. package/src/domain/models/app/table/field-types/text/url-field.ts +81 -0
  193. package/src/domain/models/app/table/field-types/user/created-by-field.ts +50 -0
  194. package/src/domain/models/app/table/field-types/user/deleted-by-field.ts +57 -0
  195. package/src/domain/models/app/table/field-types/user/index.ts +11 -0
  196. package/src/domain/models/app/table/field-types/user/updated-by-field.ts +51 -0
  197. package/src/domain/models/app/table/field-types/user/user-field.ts +52 -0
  198. package/src/domain/models/app/table/field-types/validation-utils.ts +166 -0
  199. package/src/domain/models/app/table/fields.ts +216 -0
  200. package/src/domain/models/app/table/foreign-keys.ts +111 -0
  201. package/src/domain/models/app/table/formula-keywords.ts +326 -0
  202. package/src/domain/models/app/table/id.ts +31 -0
  203. package/src/domain/models/app/table/index.ts +290 -0
  204. package/src/domain/models/app/table/indexes.ts +80 -0
  205. package/src/domain/models/app/table/name.ts +37 -0
  206. package/src/domain/models/app/table/permissions/field-permission.ts +83 -0
  207. package/src/domain/models/app/table/permissions/index.ts +167 -0
  208. package/src/domain/models/app/table/permissions/permission-evaluator.ts +372 -0
  209. package/src/domain/models/app/table/permissions/permission.ts +49 -0
  210. package/src/domain/models/app/table/primary-key.ts +62 -0
  211. package/src/domain/models/app/table/table-formula-validation.ts +168 -0
  212. package/src/domain/models/app/table/table-indexes-validation.ts +38 -0
  213. package/src/domain/models/app/table/table-permissions-validation.ts +77 -0
  214. package/src/domain/models/app/table/table-primary-key-validation.ts +49 -0
  215. package/src/domain/models/app/table/table-views-validation.ts +408 -0
  216. package/src/domain/models/app/table/unique-constraints.ts +79 -0
  217. package/src/domain/models/app/table/views/fields.ts +28 -0
  218. package/src/domain/models/app/table/views/filters.ts +162 -0
  219. package/src/domain/models/app/table/views/group-by.ts +32 -0
  220. package/src/domain/models/app/table/views/id.ts +50 -0
  221. package/src/domain/models/app/table/views/index.ts +177 -0
  222. package/src/domain/models/app/table/views/name.ts +32 -0
  223. package/src/domain/models/app/table/views/permissions.ts +98 -0
  224. package/src/domain/models/app/table/views/sorts.ts +31 -0
  225. package/src/domain/models/app/tables.ts +695 -0
  226. package/src/domain/models/app/theme/animations.ts +208 -0
  227. package/src/domain/models/app/theme/border-radius.ts +58 -0
  228. package/src/domain/models/app/theme/breakpoints.ts +62 -0
  229. package/src/domain/models/app/theme/colors.ts +110 -0
  230. package/src/domain/models/app/theme/fonts.ts +164 -0
  231. package/src/domain/models/app/theme/shadows.ts +61 -0
  232. package/src/domain/models/app/theme/spacing.ts +115 -0
  233. package/src/domain/models/app/theme.ts +66 -0
  234. package/src/domain/models/app/version.ts +87 -0
  235. package/src/domain/models/record-comment.ts +91 -0
  236. package/src/domain/utils/content-parsing.ts +49 -0
  237. package/src/domain/utils/format-detection.ts +69 -0
  238. package/src/domain/utils/index.ts +9 -0
  239. package/src/domain/utils/route-matcher.ts +184 -0
  240. package/src/domain/utils/translation-resolver.ts +170 -0
  241. package/src/index.ts +208 -0
  242. package/src/infrastructure/analytics/tracking-script.ts +48 -0
  243. package/src/infrastructure/auth/better-auth/auth.ts +216 -0
  244. package/src/infrastructure/auth/better-auth/email-handlers.ts +162 -0
  245. package/src/infrastructure/auth/better-auth/index.ts +16 -0
  246. package/src/infrastructure/auth/better-auth/layer.ts +97 -0
  247. package/src/infrastructure/auth/better-auth/plugins/admin.ts +56 -0
  248. package/src/infrastructure/auth/better-auth/plugins/magic-link.ts +31 -0
  249. package/src/infrastructure/auth/better-auth/plugins/two-factor.ts +19 -0
  250. package/src/infrastructure/auth/better-auth/schema.ts +152 -0
  251. package/src/infrastructure/auth/index.ts +27 -0
  252. package/src/infrastructure/css/cache/css-cache-service.ts +130 -0
  253. package/src/infrastructure/css/compiler.ts +210 -0
  254. package/src/infrastructure/css/css-compiler-live.ts +20 -0
  255. package/src/infrastructure/css/index.ts +25 -0
  256. package/src/infrastructure/css/styles/animation-styles-generator.ts +177 -0
  257. package/src/infrastructure/css/styles/click-animations.ts +147 -0
  258. package/src/infrastructure/css/styles/component-layer-generators.ts +147 -0
  259. package/src/infrastructure/css/theme/theme-generators.ts +130 -0
  260. package/src/infrastructure/css/theme/theme-layer-generators.ts +219 -0
  261. package/src/infrastructure/css/theme/theme-token-resolver.ts +76 -0
  262. package/src/infrastructure/database/activity-queries.ts +111 -0
  263. package/src/infrastructure/database/auth/auth-validation.ts +101 -0
  264. package/src/infrastructure/database/drizzle/db-bun.ts +17 -0
  265. package/src/infrastructure/database/drizzle/db.ts +17 -0
  266. package/src/infrastructure/database/drizzle/index.ts +16 -0
  267. package/src/infrastructure/database/drizzle/layer.ts +34 -0
  268. package/src/infrastructure/database/drizzle/migrate.ts +77 -0
  269. package/src/infrastructure/database/drizzle/schema/activity-log.ts +111 -0
  270. package/src/infrastructure/database/drizzle/schema/analytics-page-views.ts +116 -0
  271. package/src/infrastructure/database/drizzle/schema/migration-audit.ts +68 -0
  272. package/src/infrastructure/database/drizzle/schema/record-comments.ts +79 -0
  273. package/src/infrastructure/database/drizzle/schema.ts +12 -0
  274. package/src/infrastructure/database/field-utils.ts +87 -0
  275. package/src/infrastructure/database/filter-operators.ts +136 -0
  276. package/src/infrastructure/database/formula/formula-trigger-generators.ts +114 -0
  277. package/src/infrastructure/database/formula/formula-utils.ts +440 -0
  278. package/src/infrastructure/database/generators/index-generators.ts +152 -0
  279. package/src/infrastructure/database/generators/trigger-generators.ts +154 -0
  280. package/src/infrastructure/database/index.ts +35 -0
  281. package/src/infrastructure/database/lookup/lookup-expression-generators.ts +356 -0
  282. package/src/infrastructure/database/lookup/lookup-expressions.ts +116 -0
  283. package/src/infrastructure/database/lookup/lookup-view-generators.ts +403 -0
  284. package/src/infrastructure/database/lookup/lookup-view-helpers.ts +65 -0
  285. package/src/infrastructure/database/lookup/lookup-view-triggers.ts +121 -0
  286. package/src/infrastructure/database/migration-audit-trail.ts +375 -0
  287. package/src/infrastructure/database/repositories/activity-log-repository-live.ts +99 -0
  288. package/src/infrastructure/database/repositories/activity-repository-live.ts +21 -0
  289. package/src/infrastructure/database/repositories/analytics-repository-live.ts +316 -0
  290. package/src/infrastructure/database/repositories/auth-repository-live.ts +42 -0
  291. package/src/infrastructure/database/repositories/batch-repository-live.ts +29 -0
  292. package/src/infrastructure/database/repositories/comment-repository-live.ts +39 -0
  293. package/src/infrastructure/database/repositories/table-repository-live.ts +38 -0
  294. package/src/infrastructure/database/schema/schema-dependency-sorting.ts +142 -0
  295. package/src/infrastructure/database/schema/schema-initializer.ts +598 -0
  296. package/src/infrastructure/database/schema-migration/column-detection.ts +286 -0
  297. package/src/infrastructure/database/schema-migration/constants.ts +31 -0
  298. package/src/infrastructure/database/schema-migration/constraint-sync.ts +288 -0
  299. package/src/infrastructure/database/schema-migration/index-sync.ts +108 -0
  300. package/src/infrastructure/database/schema-migration/index.ts +66 -0
  301. package/src/infrastructure/database/schema-migration/migration-statements.ts +106 -0
  302. package/src/infrastructure/database/schema-migration/rename-detection.ts +87 -0
  303. package/src/infrastructure/database/schema-migration/table-operations.ts +65 -0
  304. package/src/infrastructure/database/schema-migration/type-utils.ts +98 -0
  305. package/src/infrastructure/database/schema-migration/types.ts +14 -0
  306. package/src/infrastructure/database/schema-migration-helpers.ts +53 -0
  307. package/src/infrastructure/database/session-context.ts +20 -0
  308. package/src/infrastructure/database/sql/sql-check-constraints.ts +252 -0
  309. package/src/infrastructure/database/sql/sql-column-generators.ts +174 -0
  310. package/src/infrastructure/database/sql/sql-execution.ts +245 -0
  311. package/src/infrastructure/database/sql/sql-field-predicates.ts +81 -0
  312. package/src/infrastructure/database/sql/sql-generators.ts +91 -0
  313. package/src/infrastructure/database/sql/sql-junction-tables.ts +79 -0
  314. package/src/infrastructure/database/sql/sql-key-constraints.ts +210 -0
  315. package/src/infrastructure/database/sql/sql-type-mappings.ts +106 -0
  316. package/src/infrastructure/database/sql/sql-utils.ts +53 -0
  317. package/src/infrastructure/database/table-live-layers.ts +30 -0
  318. package/src/infrastructure/database/table-operations/column-generators.ts +82 -0
  319. package/src/infrastructure/database/table-operations/create-table-sql.ts +81 -0
  320. package/src/infrastructure/database/table-operations/index.ts +55 -0
  321. package/src/infrastructure/database/table-operations/migration-utils.ts +157 -0
  322. package/src/infrastructure/database/table-operations/table-effects.ts +234 -0
  323. package/src/infrastructure/database/table-operations/table-features.ts +96 -0
  324. package/src/infrastructure/database/table-operations/type-compatibility.ts +58 -0
  325. package/src/infrastructure/database/table-operations.ts +47 -0
  326. package/src/infrastructure/database/table-queries/batch/batch-create.ts +80 -0
  327. package/src/infrastructure/database/table-queries/batch/batch-delete.ts +212 -0
  328. package/src/infrastructure/database/table-queries/batch/batch-helpers.ts +124 -0
  329. package/src/infrastructure/database/table-queries/batch/batch-restore.ts +161 -0
  330. package/src/infrastructure/database/table-queries/batch/batch-update.ts +146 -0
  331. package/src/infrastructure/database/table-queries/batch/batch-upsert.ts +357 -0
  332. package/src/infrastructure/database/table-queries/batch/batch.ts +14 -0
  333. package/src/infrastructure/database/table-queries/crud/crud-read.ts +351 -0
  334. package/src/infrastructure/database/table-queries/crud/crud-write.ts +399 -0
  335. package/src/infrastructure/database/table-queries/crud/crud.ts +16 -0
  336. package/src/infrastructure/database/table-queries/index.ts +11 -0
  337. package/src/infrastructure/database/table-queries/mutation-helpers/authorship-helpers.ts +152 -0
  338. package/src/infrastructure/database/table-queries/mutation-helpers/create-record-helpers.ts +90 -0
  339. package/src/infrastructure/database/table-queries/mutation-helpers/delete-helpers.ts +163 -0
  340. package/src/infrastructure/database/table-queries/mutation-helpers/record-fetch-helpers.ts +79 -0
  341. package/src/infrastructure/database/table-queries/mutation-helpers/update-helpers.ts +74 -0
  342. package/src/infrastructure/database/table-queries/query-helpers/activity-log-helpers.ts +53 -0
  343. package/src/infrastructure/database/table-queries/query-helpers/activity-queries.ts +106 -0
  344. package/src/infrastructure/database/table-queries/query-helpers/aggregation-helpers.ts +314 -0
  345. package/src/infrastructure/database/table-queries/query-helpers/comment-queries.ts +414 -0
  346. package/src/infrastructure/database/table-queries/query-helpers/record-validation-queries.ts +126 -0
  347. package/src/infrastructure/database/table-queries/query-helpers/trash-helpers.ts +58 -0
  348. package/src/infrastructure/database/table-queries/shared/error-handling.ts +47 -0
  349. package/src/infrastructure/database/table-queries/shared/typed-execute.ts +27 -0
  350. package/src/infrastructure/database/table-queries/shared/user-join-helpers.ts +38 -0
  351. package/src/infrastructure/database/table-queries/shared/validation.ts +39 -0
  352. package/src/infrastructure/database/views/view-generators.ts +258 -0
  353. package/src/infrastructure/devtools/devtools-layer.ts +43 -0
  354. package/src/infrastructure/devtools/index.ts +8 -0
  355. package/src/infrastructure/email/email-config.ts +103 -0
  356. package/src/infrastructure/email/email-service.ts +152 -0
  357. package/src/infrastructure/email/index.ts +107 -0
  358. package/src/infrastructure/email/nodemailer.ts +125 -0
  359. package/src/infrastructure/email/templates.ts +244 -0
  360. package/src/infrastructure/errors/auth-config-required-error.ts +21 -0
  361. package/src/infrastructure/errors/auth-error.ts +16 -0
  362. package/src/infrastructure/errors/css-compilation-error.ts +14 -0
  363. package/src/infrastructure/errors/index.ts +26 -0
  364. package/src/infrastructure/errors/schema-initialization-error.ts +19 -0
  365. package/src/infrastructure/errors/server-creation-error.ts +14 -0
  366. package/src/infrastructure/filesystem/copy-directory.ts +136 -0
  367. package/src/infrastructure/layers/app-layer.ts +61 -0
  368. package/src/infrastructure/layers/page-renderer-layer.ts +41 -0
  369. package/src/infrastructure/logging/index.ts +8 -0
  370. package/src/infrastructure/logging/logger.ts +204 -0
  371. package/src/infrastructure/schema/file-loader.ts +53 -0
  372. package/src/infrastructure/schema/index.ts +15 -0
  373. package/src/infrastructure/schema/remote-loader.ts +48 -0
  374. package/src/infrastructure/server/index.ts +26 -0
  375. package/src/infrastructure/server/language-detection.ts +87 -0
  376. package/src/infrastructure/server/lifecycle.ts +67 -0
  377. package/src/infrastructure/server/route-setup/api-routes.ts +310 -0
  378. package/src/infrastructure/server/route-setup/auth-route-utils.ts +399 -0
  379. package/src/infrastructure/server/route-setup/auth-routes.ts +245 -0
  380. package/src/infrastructure/server/route-setup/openapi-routes.ts +45 -0
  381. package/src/infrastructure/server/route-setup/openapi-schema.ts +120 -0
  382. package/src/infrastructure/server/route-setup/page-routes.ts +219 -0
  383. package/src/infrastructure/server/route-setup/static-assets.ts +191 -0
  384. package/src/infrastructure/server/server-factory-live.ts +45 -0
  385. package/src/infrastructure/server/server.ts +275 -0
  386. package/src/infrastructure/server/ssg-adapter.ts +196 -0
  387. package/src/infrastructure/server/static-site-generator-live.ts +20 -0
  388. package/src/infrastructure/utils/accept-language-parser.ts +106 -0
  389. package/src/infrastructure/utils/glob-matcher.ts +50 -0
  390. package/src/presentation/api/client.ts +114 -0
  391. package/src/presentation/api/middleware/auth.ts +233 -0
  392. package/src/presentation/api/middleware/table.ts +155 -0
  393. package/src/presentation/api/middleware/validation.ts +88 -0
  394. package/src/presentation/api/routes/activity/get-activity-by-id-handler.ts +77 -0
  395. package/src/presentation/api/routes/activity/index.ts +28 -0
  396. package/src/presentation/api/routes/activity.ts +339 -0
  397. package/src/presentation/api/routes/analytics.ts +328 -0
  398. package/src/presentation/api/routes/auth.ts +169 -0
  399. package/src/presentation/api/routes/index.ts +11 -0
  400. package/src/presentation/api/routes/tables/activity-handlers.ts +57 -0
  401. package/src/presentation/api/routes/tables/batch-permission-helpers.ts +163 -0
  402. package/src/presentation/api/routes/tables/batch-routes.ts +355 -0
  403. package/src/presentation/api/routes/tables/comment-handlers.ts +377 -0
  404. package/src/presentation/api/routes/tables/create-record-helpers.ts +179 -0
  405. package/src/presentation/api/routes/tables/effect-runner.ts +58 -0
  406. package/src/presentation/api/routes/tables/error-handlers.ts +53 -0
  407. package/src/presentation/api/routes/tables/field-permission-validation.ts +167 -0
  408. package/src/presentation/api/routes/tables/filter-parser.ts +75 -0
  409. package/src/presentation/api/routes/tables/formula-parser.ts +118 -0
  410. package/src/presentation/api/routes/tables/index.ts +113 -0
  411. package/src/presentation/api/routes/tables/list-records-filter.ts +54 -0
  412. package/src/presentation/api/routes/tables/param-parsers.ts +59 -0
  413. package/src/presentation/api/routes/tables/record-handlers.ts +484 -0
  414. package/src/presentation/api/routes/tables/record-routes.ts +53 -0
  415. package/src/presentation/api/routes/tables/record-update-handler.ts +200 -0
  416. package/src/presentation/api/routes/tables/sort-validation.ts +85 -0
  417. package/src/presentation/api/routes/tables/table-routes.ts +76 -0
  418. package/src/presentation/api/routes/tables/timezone-validation.ts +41 -0
  419. package/src/presentation/api/routes/tables/upsert-helpers.ts +471 -0
  420. package/src/presentation/api/routes/tables/utils.ts +159 -0
  421. package/src/presentation/api/routes/tables/view-routes.ts +51 -0
  422. package/src/presentation/api/routes/tables.ts +9 -0
  423. package/src/presentation/api/utils/context-helpers.ts +43 -0
  424. package/src/presentation/api/utils/error-sanitizer.ts +235 -0
  425. package/src/presentation/api/utils/field-permission-validator.ts +53 -0
  426. package/src/presentation/api/utils/filter-field-validator.ts +90 -0
  427. package/src/presentation/api/utils/index.ts +13 -0
  428. package/src/presentation/api/utils/run-effect.ts +94 -0
  429. package/src/presentation/api/utils/validate-request.ts +89 -0
  430. package/src/presentation/api/validation/index.ts +29 -0
  431. package/src/presentation/api/validation/rules/field-rules.ts +158 -0
  432. package/src/presentation/api/validation/rules/record-rules.ts +73 -0
  433. package/src/presentation/cli/index.ts +19 -0
  434. package/src/presentation/cli/schema-loader.ts +172 -0
  435. package/src/presentation/hooks/use-breakpoint.ts +155 -0
  436. package/src/presentation/rendering/render-error-pages.tsx +60 -0
  437. package/src/presentation/rendering/render-homepage.tsx +137 -0
  438. package/src/presentation/scripts/script-renderers.ts +112 -0
  439. package/src/presentation/styling/animation-composer.ts +117 -0
  440. package/src/presentation/styling/index.ts +13 -0
  441. package/src/presentation/styling/parse-style.ts +243 -0
  442. package/src/presentation/styling/style-utils.ts +50 -0
  443. package/src/presentation/styling/theme-colors.ts +53 -0
  444. package/src/presentation/translations/component-utils.ts +54 -0
  445. package/src/presentation/translations/index.ts +16 -0
  446. package/src/presentation/translations/translation-resolver.ts +22 -0
  447. package/src/presentation/ui/languages/language-switcher.tsx +119 -0
  448. package/src/presentation/ui/metadata/analytics-builders.tsx +174 -0
  449. package/src/presentation/ui/metadata/analytics-head.tsx +39 -0
  450. package/src/presentation/ui/metadata/custom-elements-builders.tsx +157 -0
  451. package/src/presentation/ui/metadata/extract-component-meta.ts +108 -0
  452. package/src/presentation/ui/metadata/head-elements.tsx +164 -0
  453. package/src/presentation/ui/metadata/index.tsx +35 -0
  454. package/src/presentation/ui/metadata/meta-utils.tsx +42 -0
  455. package/src/presentation/ui/metadata/open-graph-meta.tsx +57 -0
  456. package/src/presentation/ui/metadata/structured-data-from-component.tsx +134 -0
  457. package/src/presentation/ui/metadata/structured-data.tsx +88 -0
  458. package/src/presentation/ui/metadata/twitter-card-meta.tsx +80 -0
  459. package/src/presentation/ui/pages/DefaultHomePage.tsx +43 -0
  460. package/src/presentation/ui/pages/DefaultPageConfigs.ts +220 -0
  461. package/src/presentation/ui/pages/DynamicPage.tsx +307 -0
  462. package/src/presentation/ui/pages/ErrorPage.tsx +25 -0
  463. package/src/presentation/ui/pages/NotFoundPage.tsx +25 -0
  464. package/src/presentation/ui/pages/PageBodyScripts.tsx +242 -0
  465. package/src/presentation/ui/pages/PageBodyStyles.ts +52 -0
  466. package/src/presentation/ui/pages/PageHead.tsx +380 -0
  467. package/src/presentation/ui/pages/PageLangResolver.ts +58 -0
  468. package/src/presentation/ui/pages/PageMain.tsx +58 -0
  469. package/src/presentation/ui/pages/PageMetadata.ts +168 -0
  470. package/src/presentation/ui/pages/PageMetadataI18n.ts +169 -0
  471. package/src/presentation/ui/pages/PageScripts.ts +78 -0
  472. package/src/presentation/ui/pages/SectionRenderer.tsx +67 -0
  473. package/src/presentation/ui/pages/SectionSpacing.tsx +131 -0
  474. package/src/presentation/ui/sections/component-renderer.tsx +426 -0
  475. package/src/presentation/ui/sections/component-renderer.types.ts +33 -0
  476. package/src/presentation/ui/sections/components/component-reference-handler.tsx +74 -0
  477. package/src/presentation/ui/sections/components/component-resolution.ts +65 -0
  478. package/src/presentation/ui/sections/components/index.ts +9 -0
  479. package/src/presentation/ui/sections/hero.tsx +394 -0
  480. package/src/presentation/ui/sections/props/component-builder.ts +183 -0
  481. package/src/presentation/ui/sections/props/element-props.ts +179 -0
  482. package/src/presentation/ui/sections/props/index.ts +9 -0
  483. package/src/presentation/ui/sections/props/prop-conversion.ts +171 -0
  484. package/src/presentation/ui/sections/props/props-builder-config.ts +42 -0
  485. package/src/presentation/ui/sections/props/props-builder.ts +296 -0
  486. package/src/presentation/ui/sections/renderers/element-renderers/html-element-renderer.tsx +124 -0
  487. package/src/presentation/ui/sections/renderers/element-renderers/index.ts +59 -0
  488. package/src/presentation/ui/sections/renderers/element-renderers/interactive-renderers.tsx +231 -0
  489. package/src/presentation/ui/sections/renderers/element-renderers/media-renderers.tsx +102 -0
  490. package/src/presentation/ui/sections/renderers/element-renderers/text-content-renderers.tsx +42 -0
  491. package/src/presentation/ui/sections/renderers/element-renderers.ts +53 -0
  492. package/src/presentation/ui/sections/renderers/html-element-helpers.ts +100 -0
  493. package/src/presentation/ui/sections/renderers/specialized-renderers.tsx +212 -0
  494. package/src/presentation/ui/sections/rendering/component-dispatch-config.ts +31 -0
  495. package/src/presentation/ui/sections/rendering/component-registry/index.ts +39 -0
  496. package/src/presentation/ui/sections/rendering/component-registry/interactive-components.ts +54 -0
  497. package/src/presentation/ui/sections/rendering/component-registry/media-components.ts +36 -0
  498. package/src/presentation/ui/sections/rendering/component-registry/special-components.tsx +153 -0
  499. package/src/presentation/ui/sections/rendering/component-registry/structural-components.ts +215 -0
  500. package/src/presentation/ui/sections/rendering/component-registry/text-components.ts +57 -0
  501. package/src/presentation/ui/sections/rendering/component-registry-helpers.tsx +29 -0
  502. package/src/presentation/ui/sections/rendering/component-registry.tsx +21 -0
  503. package/src/presentation/ui/sections/rendering/component-type-dispatcher.tsx +33 -0
  504. package/src/presentation/ui/sections/rendering/index.ts +9 -0
  505. package/src/presentation/ui/sections/responsive/responsive-children-builder.tsx +96 -0
  506. package/src/presentation/ui/sections/responsive/responsive-content-builder.tsx +95 -0
  507. package/src/presentation/ui/sections/responsive/responsive-props-merger.ts +195 -0
  508. package/src/presentation/ui/sections/responsive/responsive-resolver.ts +213 -0
  509. package/src/presentation/ui/sections/styling/animation-composer-wrapper.ts +65 -0
  510. package/src/presentation/ui/sections/styling/class-builders.ts +45 -0
  511. package/src/presentation/ui/sections/styling/color-resolver.ts +43 -0
  512. package/src/presentation/ui/sections/styling/hover-interaction-handler.ts +107 -0
  513. package/src/presentation/ui/sections/styling/index.ts +9 -0
  514. package/src/presentation/ui/sections/styling/interaction-props-builder.ts +55 -0
  515. package/src/presentation/ui/sections/styling/shadow-resolver.ts +83 -0
  516. package/src/presentation/ui/sections/styling/spacing-resolver.ts +104 -0
  517. package/src/presentation/ui/sections/styling/style-processor.ts +170 -0
  518. package/src/presentation/ui/sections/styling/theme-tokens.ts +184 -0
  519. package/src/presentation/ui/sections/translations/i18n-content-resolver.ts +198 -0
  520. package/src/presentation/ui/sections/translations/index.ts +9 -0
  521. package/src/presentation/ui/sections/translations/translation-handler.ts +143 -0
  522. package/src/presentation/ui/sections/translations/variable-substitution.ts +225 -0
  523. package/src/presentation/ui/sections/utils/time-parser.ts +82 -0
  524. package/src/presentation/utils/link-attributes.ts +50 -0
  525. package/src/presentation/utils/string-utils.ts +58 -0
  526. package/src/presentation/utils/styles.ts +50 -0
  527. package/tsconfig.json +46 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import fs from 'node:fs/promises'
9
+ import path from 'node:path'
10
+ import { Effect, Console } from 'effect'
11
+ import { StaticGenerationError } from '@/application/errors/static-generation-error'
12
+ import { copyDirectory } from '@/infrastructure/filesystem/copy-directory'
13
+ import {
14
+ formatHtmlWithPrettier,
15
+ generateClientHydrationScript,
16
+ generateRobotsContent,
17
+ generateSitemapContent,
18
+ type HreflangConfig,
19
+ } from './static-content-generators'
20
+ import {
21
+ injectHydrationScript,
22
+ isGitHubPagesUrl,
23
+ rewriteBasePathInHtml,
24
+ } from './static-url-rewriter'
25
+ import * as translationReplacer from './translation-replacer'
26
+ import type { GenerateStaticOptions } from './generate-static'
27
+ import type { App } from '@/domain/models/app'
28
+
29
+ // Re-export static modules for callers that previously used the import helpers
30
+ export { fs, path, translationReplacer }
31
+
32
+ /**
33
+ * Minimal filesystem interface for static generation
34
+ *
35
+ * Compatible with Node.js fs/promises, Bun's filesystem APIs, and test mocks.
36
+ * Only includes methods actually used by static generation functions.
37
+ */
38
+ export interface FileSystemLike {
39
+ readonly mkdir: (
40
+ path: string,
41
+ options?: { readonly recursive?: boolean }
42
+ ) => Promise<string | undefined>
43
+ readonly writeFile: (path: string, data: string, encoding?: BufferEncoding) => Promise<void>
44
+ readonly readFile: (path: string, encoding: BufferEncoding) => Promise<string>
45
+ }
46
+
47
+ /**
48
+ * Minimal path module interface for static generation
49
+ *
50
+ * Compatible with Node.js path module, Bun's path APIs, and test mocks.
51
+ */
52
+ export interface PathModuleLike {
53
+ readonly join: (...paths: readonly string[]) => string
54
+ }
55
+
56
+ /**
57
+ * Write CSS file to output directory
58
+ *
59
+ * @param outputDir - Output directory path
60
+ * @param css - Compiled CSS content
61
+ * @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
62
+ */
63
+ export function writeCssFile(outputDir: string, css: string, fs: FileSystemLike) {
64
+ return Effect.gen(function* () {
65
+ yield* Console.log('🎨 Writing compiled CSS...')
66
+
67
+ yield* Effect.tryPromise({
68
+ try: () => fs.mkdir(`${outputDir}/assets`, { recursive: true }),
69
+ catch: (error) =>
70
+ new StaticGenerationError({
71
+ message: `Failed to create assets directory`,
72
+ cause: error,
73
+ }),
74
+ })
75
+
76
+ yield* Effect.tryPromise({
77
+ try: () => fs.writeFile(`${outputDir}/assets/output.css`, css, 'utf-8'),
78
+ catch: (error) =>
79
+ new StaticGenerationError({
80
+ message: 'Failed to write CSS file',
81
+ cause: error,
82
+ }),
83
+ })
84
+
85
+ return 'assets/output.css'
86
+ })
87
+ }
88
+
89
+ /**
90
+ * Generate client-side hydration script if enabled
91
+ *
92
+ * @param outputDir - Output directory path
93
+ * @param enabled - Whether hydration is enabled
94
+ * @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
95
+ */
96
+ export function generateHydrationFiles(outputDir: string, enabled: boolean, fs: FileSystemLike) {
97
+ return Effect.if(enabled, {
98
+ onTrue: () =>
99
+ Effect.gen(function* () {
100
+ yield* Console.log('💧 Generating client-side hydration script...')
101
+ const clientJS = generateClientHydrationScript()
102
+ yield* Effect.tryPromise({
103
+ try: () => fs.writeFile(`${outputDir}/assets/client.js`, clientJS, 'utf-8'),
104
+ catch: (error) =>
105
+ new StaticGenerationError({
106
+ message: 'Failed to write client.js',
107
+ cause: error,
108
+ }),
109
+ })
110
+ return ['assets/client.js'] as const
111
+ }),
112
+ onFalse: () => Effect.succeed([] as readonly string[]),
113
+ })
114
+ }
115
+
116
+ /**
117
+ * Copy static assets from public directory if provided
118
+ */
119
+ export function copyPublicAssets(publicDir: string | undefined, outputDir: string) {
120
+ return Effect.if(publicDir !== undefined, {
121
+ onTrue: () =>
122
+ Effect.gen(function* () {
123
+ yield* Console.log(`📁 Copying assets from ${publicDir}...`)
124
+ return yield* copyDirectory(publicDir!, outputDir)
125
+ }),
126
+ onFalse: () => Effect.succeed([] as readonly string[]),
127
+ })
128
+ }
129
+
130
+ /**
131
+ * Format HTML files with Prettier
132
+ *
133
+ * @param generatedFiles - List of generated file paths
134
+ * @param outputDir - Output directory path
135
+ * @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
136
+ * @param path - Path module (Node.js path or Bun's equivalent)
137
+ */
138
+ export function formatHtmlFiles(
139
+ generatedFiles: readonly string[],
140
+ outputDir: string,
141
+ fs: FileSystemLike,
142
+ path: PathModuleLike
143
+ ) {
144
+ return Effect.gen(function* () {
145
+ yield* Console.log('📝 Formatting HTML files with Prettier...')
146
+
147
+ yield* Effect.forEach(
148
+ generatedFiles.filter((f) => f.endsWith('.html') && !f.endsWith('.js.html')),
149
+ (file) =>
150
+ Effect.gen(function* () {
151
+ const filePath = file.startsWith('/') ? file : path.join(outputDir, file)
152
+ const content = yield* Effect.tryPromise({
153
+ try: () => fs.readFile(filePath, 'utf-8') as Promise<string>,
154
+ catch: (error) =>
155
+ new StaticGenerationError({
156
+ message: `Failed to read HTML file for formatting: ${file}`,
157
+ cause: error,
158
+ }),
159
+ })
160
+ const formatted = yield* Effect.tryPromise({
161
+ try: () => formatHtmlWithPrettier(content),
162
+ catch: (error) =>
163
+ new StaticGenerationError({
164
+ message: `Failed to format HTML with Prettier: ${file}`,
165
+ cause: error,
166
+ }),
167
+ })
168
+ yield* Effect.tryPromise({
169
+ try: () => fs.writeFile(filePath, formatted, 'utf-8'),
170
+ catch: (error) =>
171
+ new StaticGenerationError({
172
+ message: `Failed to write formatted HTML file: ${file}`,
173
+ cause: error,
174
+ }),
175
+ })
176
+ }),
177
+ { concurrency: 'unbounded' }
178
+ )
179
+ })
180
+ }
181
+
182
+ /**
183
+ * Apply optimizations to generated HTML files
184
+ *
185
+ * @param config - Configuration object
186
+ * @param config.generatedFiles - List of generated file paths
187
+ * @param config.outputDir - Output directory path
188
+ * @param config.options - Static generation options
189
+ * @param config.fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
190
+ * @param config.path - Path module (Node.js path or Bun's equivalent)
191
+ */
192
+ export function applyHtmlOptimizations(config: {
193
+ readonly generatedFiles: readonly string[]
194
+ readonly outputDir: string
195
+ readonly options: GenerateStaticOptions
196
+ readonly fs: FileSystemLike
197
+ readonly path: PathModuleLike
198
+ }) {
199
+ return Effect.gen(function* () {
200
+ // Step 1: Apply base path rewriting if basePath is configured
201
+ yield* Effect.if(config.options.basePath !== undefined && config.options.basePath !== '', {
202
+ onTrue: () =>
203
+ rewriteBasePathInHtml(
204
+ config.generatedFiles,
205
+ config.outputDir,
206
+ config.options.basePath!,
207
+ config.options.baseUrl,
208
+ config.fs
209
+ ),
210
+ onFalse: () => Effect.void,
211
+ })
212
+
213
+ // Step 2: Inject hydration script into HTML if enabled
214
+ yield* Effect.if(config.options.hydration ?? false, {
215
+ onTrue: () =>
216
+ injectHydrationScript(
217
+ config.generatedFiles,
218
+ config.outputDir,
219
+ config.options.basePath || '',
220
+ config.fs,
221
+ config.path
222
+ ),
223
+ onFalse: () => Effect.void,
224
+ })
225
+ })
226
+ }
227
+
228
+ /**
229
+ * Build HreflangConfig from app languages when multi-language mode is active
230
+ */
231
+ const buildHreflangConfig = (
232
+ app: App,
233
+ options: GenerateStaticOptions
234
+ ): HreflangConfig | undefined => {
235
+ if (!app.languages || !options.languages) return undefined
236
+ return {
237
+ localeMap: Object.fromEntries(
238
+ app.languages.supported.map((lang) => [lang.code, lang.locale ?? lang.code])
239
+ ),
240
+ defaultLanguage: options.defaultLanguage ?? app.languages.default,
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Generate sitemap.xml if enabled
246
+ */
247
+ export function generateSitemapFile(
248
+ app: App,
249
+ outputDir: string,
250
+ options: GenerateStaticOptions,
251
+ fs: FileSystemLike
252
+ ) {
253
+ return Effect.if(options.generateSitemap ?? false, {
254
+ onTrue: () =>
255
+ Effect.gen(function* () {
256
+ yield* Console.log('🗺️ Generating sitemap.xml...')
257
+ const pages = app.pages || []
258
+ const languages = app.languages && options.languages ? options.languages : undefined
259
+ const hreflangConfig = buildHreflangConfig(app, options)
260
+
261
+ const sitemap = generateSitemapContent(
262
+ pages,
263
+ options.baseUrl || 'https://example.com',
264
+ options.basePath || '',
265
+ languages || hreflangConfig ? { languages, hreflangConfig } : undefined
266
+ )
267
+ yield* Effect.tryPromise({
268
+ try: () => fs.writeFile(`${outputDir}/sitemap.xml`, sitemap, 'utf-8'),
269
+ catch: (error) =>
270
+ new StaticGenerationError({
271
+ message: 'Failed to write sitemap.xml',
272
+ cause: error,
273
+ }),
274
+ })
275
+ return ['sitemap.xml'] as const
276
+ }),
277
+ onFalse: () => Effect.succeed([] as readonly string[]),
278
+ })
279
+ }
280
+
281
+ /**
282
+ * Generate robots.txt if enabled
283
+ *
284
+ * @param app - Application configuration
285
+ * @param outputDir - Output directory path
286
+ * @param options - Static generation options
287
+ * @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
288
+ */
289
+ export function generateRobotsFile(
290
+ app: App,
291
+ outputDir: string,
292
+ options: GenerateStaticOptions,
293
+ fs: FileSystemLike
294
+ ) {
295
+ return Effect.if(options.generateRobotsTxt ?? false, {
296
+ onTrue: () =>
297
+ Effect.gen(function* () {
298
+ yield* Console.log('🤖 Generating robots.txt...')
299
+ const pages = app.pages || []
300
+ const basePath = options.basePath || ''
301
+ const robots = generateRobotsContent(
302
+ pages,
303
+ options.baseUrl || 'https://example.com',
304
+ basePath,
305
+ options.generateSitemap
306
+ )
307
+ yield* Effect.tryPromise({
308
+ try: () => fs.writeFile(`${outputDir}/robots.txt`, robots, 'utf-8'),
309
+ catch: (error) =>
310
+ new StaticGenerationError({
311
+ message: 'Failed to write robots.txt',
312
+ cause: error,
313
+ }),
314
+ })
315
+ return ['robots.txt'] as const
316
+ }),
317
+ onFalse: () => Effect.succeed([] as readonly string[]),
318
+ })
319
+ }
320
+
321
+ /**
322
+ * Generate GitHub Pages specific files
323
+ */
324
+ export function generateGitHubPagesFiles(
325
+ outputDir: string,
326
+ options: GenerateStaticOptions,
327
+ fs: FileSystemLike
328
+ ) {
329
+ return Effect.gen(function* () {
330
+ // Create .nojekyll file
331
+ const nojekyllFiles = yield* Effect.if(options.deployment === 'github-pages', {
332
+ onTrue: () =>
333
+ Effect.gen(function* () {
334
+ yield* Console.log('📄 Creating .nojekyll file for GitHub Pages...')
335
+ yield* Effect.tryPromise({
336
+ try: () => fs.writeFile(`${outputDir}/.nojekyll`, '', 'utf-8'),
337
+ catch: (error) =>
338
+ new StaticGenerationError({
339
+ message: 'Failed to write .nojekyll',
340
+ cause: error,
341
+ }),
342
+ })
343
+ return ['.nojekyll'] as const
344
+ }),
345
+ onFalse: () => Effect.succeed([] as readonly string[]),
346
+ })
347
+
348
+ // Generate CNAME file for custom domains
349
+ const cnameFiles = yield* Effect.if(
350
+ options.deployment === 'github-pages' &&
351
+ options.baseUrl !== undefined &&
352
+ !isGitHubPagesUrl(options.baseUrl),
353
+ {
354
+ onTrue: () =>
355
+ Effect.gen(function* () {
356
+ const domain = new URL(options.baseUrl!).hostname
357
+ yield* Console.log(`📄 Creating CNAME file for custom domain: ${domain}...`)
358
+ yield* Effect.tryPromise({
359
+ try: () => fs.writeFile(`${outputDir}/CNAME`, domain, 'utf-8'),
360
+ catch: (error) =>
361
+ new StaticGenerationError({
362
+ message: 'Failed to write CNAME',
363
+ cause: error,
364
+ }),
365
+ })
366
+ return ['CNAME'] as const
367
+ }),
368
+ onFalse: () => Effect.succeed([] as readonly string[]),
369
+ }
370
+ )
371
+
372
+ return [...nojekyllFiles, ...cnameFiles] as readonly string[]
373
+ })
374
+ }
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { Effect, Console, Schema, type Context } from 'effect'
9
+ import { AppValidationError } from '@/application/errors/app-validation-error'
10
+ import {
11
+ CSSCompiler as CSSCompilerService,
12
+ type CSSCompilationError,
13
+ } from '@/application/ports/services/css-compiler'
14
+ import { PageRenderer as PageRendererService } from '@/application/ports/services/page-renderer'
15
+ import { ServerFactory as ServerFactoryService } from '@/application/ports/services/server-factory'
16
+ import {
17
+ StaticSiteGenerator as StaticSiteGeneratorService,
18
+ type SSGGenerationError,
19
+ } from '@/application/ports/services/static-site-generator'
20
+ import { AppSchema } from '@/domain/models/app'
21
+ import {
22
+ fs,
23
+ path,
24
+ translationReplacer,
25
+ writeCssFile,
26
+ generateHydrationFiles,
27
+ copyPublicAssets,
28
+ formatHtmlFiles,
29
+ applyHtmlOptimizations,
30
+ generateSitemapFile,
31
+ generateRobotsFile,
32
+ generateGitHubPagesFiles,
33
+ type FileSystemLike,
34
+ } from './generate-static-helpers'
35
+ import {
36
+ generateMultiLanguageFiles,
37
+ generateSingleLanguageFiles,
38
+ } from './static-language-generators'
39
+ import type { StaticGenerationError } from '@/application/errors/static-generation-error'
40
+ import type { App } from '@/domain/models/app'
41
+ import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
42
+ import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
43
+ import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
44
+ import type { FileCopyError } from '@/infrastructure/filesystem/copy-directory'
45
+
46
+ /**
47
+ * Options for static site generation
48
+ */
49
+ export interface GenerateStaticOptions {
50
+ readonly outputDir?: string // default: './static'
51
+ readonly baseUrl?: string
52
+ readonly basePath?: string
53
+ readonly deployment?: 'github-pages' | 'generic'
54
+ readonly languages?: readonly string[]
55
+ readonly defaultLanguage?: string
56
+ readonly generateSitemap?: boolean
57
+ readonly generateRobotsTxt?: boolean
58
+ readonly hydration?: boolean
59
+ readonly generateManifest?: boolean
60
+ readonly bundleOptimization?: 'split' | 'none'
61
+ readonly publicDir?: string // Directory containing static assets to copy
62
+ }
63
+
64
+ /**
65
+ * Result of static site generation
66
+ */
67
+ export interface GenerateStaticResult {
68
+ readonly outputDir: string
69
+ readonly files: readonly string[]
70
+ }
71
+
72
+ /**
73
+ * Validate app schema handling multi-language apps
74
+ */
75
+ function validateAppSchema(app: unknown): Effect.Effect<App, AppValidationError, never> {
76
+ const rawApp = app as Record<string, unknown>
77
+ const hasLanguages = rawApp.languages !== undefined
78
+
79
+ return hasLanguages && rawApp.pages
80
+ ? Effect.gen(function* () {
81
+ const appWithoutPages = { ...rawApp, pages: undefined }
82
+ const baseApp = yield* Effect.try({
83
+ try: (): App => Schema.decodeUnknownSync(AppSchema)(appWithoutPages),
84
+ catch: (error) => new AppValidationError(error),
85
+ })
86
+ return { ...baseApp, pages: rawApp.pages as App['pages'] }
87
+ })
88
+ : Effect.gen(function* () {
89
+ yield* Console.log('🔍 Validating app schema...')
90
+ return yield* Effect.try({
91
+ try: (): App => Schema.decodeUnknownSync(AppSchema)(app),
92
+ catch: (error) => new AppValidationError(error),
93
+ })
94
+ })
95
+ }
96
+
97
+ /**
98
+ * Get required services from Effect context
99
+ */
100
+ function getServicesFromContext() {
101
+ return Effect.gen(function* () {
102
+ return {
103
+ serverFactory: yield* ServerFactoryService,
104
+ pageRenderer: yield* PageRendererService,
105
+ cssCompiler: yield* CSSCompilerService,
106
+ staticSiteGenerator: yield* StaticSiteGeneratorService,
107
+ }
108
+ })
109
+ }
110
+
111
+ /**
112
+ * Generate HTML files for single or multi-language apps
113
+ */
114
+ function generateHtmlFiles(
115
+ app: App,
116
+ outputDir: string,
117
+ replaceAppTokens: (app: App, lang: string) => App,
118
+ serverFactory: Context.Tag.Service<ServerFactoryService>,
119
+ pageRenderer: Context.Tag.Service<PageRendererService>,
120
+ staticSiteGenerator: Context.Tag.Service<StaticSiteGeneratorService>
121
+ ) {
122
+ return app.languages && app.pages
123
+ ? generateMultiLanguageFiles(
124
+ app,
125
+ outputDir,
126
+ replaceAppTokens,
127
+ serverFactory,
128
+ pageRenderer,
129
+ staticSiteGenerator
130
+ )
131
+ : generateSingleLanguageFiles(app, outputDir, serverFactory, pageRenderer, staticSiteGenerator)
132
+ }
133
+
134
+ /**
135
+ * Generate and write CSS file
136
+ */
137
+ function generateCssFile(
138
+ outputDir: string,
139
+ app: App,
140
+ cssCompiler: Context.Tag.Service<CSSCompilerService>,
141
+ fs: FileSystemLike
142
+ ) {
143
+ return Effect.gen(function* () {
144
+ yield* Console.log('🎨 Getting compiled CSS...')
145
+ const { css } = yield* cssCompiler.compile(app)
146
+ return yield* writeCssFile(outputDir, css, fs)
147
+ })
148
+ }
149
+
150
+ /**
151
+ * Optimize HTML files with formatting and transformations
152
+ *
153
+ * @param generatedFiles - List of generated file paths
154
+ * @param outputDir - Output directory path
155
+ * @param options - Static generation options
156
+ * @param fsModule - Filesystem module (Node.js fs/promises or Bun's equivalent)
157
+ */
158
+ function optimizeHtmlFiles(
159
+ generatedFiles: readonly string[],
160
+ outputDir: string,
161
+ options: GenerateStaticOptions,
162
+ fsModule: FileSystemLike
163
+ ) {
164
+ return Effect.gen(function* () {
165
+ yield* formatHtmlFiles(generatedFiles, outputDir, fsModule, path)
166
+ yield* applyHtmlOptimizations({
167
+ generatedFiles,
168
+ outputDir,
169
+ options,
170
+ fs: fsModule,
171
+ path,
172
+ })
173
+ })
174
+ }
175
+
176
+ /**
177
+ * Generate all supporting files (sitemap, robots.txt, GitHub Pages files)
178
+ */
179
+ function generateSupportingFiles(
180
+ app: App,
181
+ outputDir: string,
182
+ options: GenerateStaticOptions,
183
+ fs: FileSystemLike
184
+ ) {
185
+ return Effect.gen(function* () {
186
+ const sitemapFiles = yield* generateSitemapFile(app, outputDir, options, fs)
187
+ const robotsFiles = yield* generateRobotsFile(app, outputDir, options, fs)
188
+ const githubFiles = yield* generateGitHubPagesFiles(outputDir, options, fs)
189
+
190
+ return [...sitemapFiles, ...robotsFiles, ...githubFiles] as readonly string[]
191
+ })
192
+ }
193
+
194
+ /**
195
+ * Generate static site from app configuration
196
+ *
197
+ * This use case:
198
+ * 1. Validates the app schema
199
+ * 2. Creates a Hono app instance
200
+ * 3. Generates static HTML files
201
+ * 4. Creates supporting files (sitemap, robots.txt, etc.)
202
+ *
203
+ * @param app - The app configuration (unknown type, will be validated)
204
+ * @param options - Static generation options
205
+ * @returns Effect with output directory and generated files
206
+ */
207
+ export const generateStatic = (
208
+ app: unknown,
209
+ options: GenerateStaticOptions = {}
210
+ ): Effect.Effect<
211
+ GenerateStaticResult,
212
+ | AppValidationError
213
+ | StaticGenerationError
214
+ | SSGGenerationError
215
+ | CSSCompilationError
216
+ | ServerCreationError
217
+ | FileCopyError
218
+ | AuthConfigRequiredForUserFields
219
+ | SchemaInitializationError
220
+ | Error,
221
+ ServerFactoryService | PageRendererService | CSSCompilerService | StaticSiteGeneratorService
222
+ > => {
223
+ const program = Effect.gen(function* () {
224
+ // Step 1: Dependencies are statically imported
225
+ const { replaceAppTokens } = translationReplacer
226
+
227
+ // Step 2: Validate app schema
228
+ const validatedApp = yield* validateAppSchema(app)
229
+
230
+ // Step 3: Get services and initialize
231
+ const services = yield* getServicesFromContext()
232
+ const outputDir = options.outputDir || './static'
233
+
234
+ // Step 4: Generate HTML files
235
+ const htmlFiles = yield* generateHtmlFiles(
236
+ validatedApp,
237
+ outputDir,
238
+ replaceAppTokens,
239
+ services.serverFactory,
240
+ services.pageRenderer,
241
+ services.staticSiteGenerator
242
+ )
243
+
244
+ // Step 5: Generate CSS and assets
245
+ const cssFile = yield* generateCssFile(outputDir, validatedApp, services.cssCompiler, fs)
246
+ const hydrationFiles = yield* generateHydrationFiles(outputDir, options.hydration ?? false, fs)
247
+ const assetFiles = yield* copyPublicAssets(options.publicDir, outputDir)
248
+
249
+ // Collect all generated files
250
+ const generatedFiles = [
251
+ ...htmlFiles,
252
+ cssFile,
253
+ ...hydrationFiles,
254
+ ...assetFiles,
255
+ ] as readonly string[]
256
+
257
+ // Step 6: Optimize HTML files
258
+ yield* optimizeHtmlFiles(generatedFiles, outputDir, options, fs)
259
+
260
+ // Step 7: Generate supporting files
261
+ const supportingFiles = yield* generateSupportingFiles(validatedApp, outputDir, options, fs)
262
+
263
+ // Combine all files immutably
264
+ const allFiles = [...generatedFiles, ...supportingFiles] as readonly string[]
265
+
266
+ yield* Console.log(`✅ Generated ${allFiles.length} files to ${outputDir}`)
267
+
268
+ return {
269
+ outputDir,
270
+ files: allFiles,
271
+ }
272
+ })
273
+
274
+ return program as Effect.Effect<
275
+ GenerateStaticResult,
276
+ | AppValidationError
277
+ | StaticGenerationError
278
+ | SSGGenerationError
279
+ | CSSCompilationError
280
+ | ServerCreationError
281
+ | FileCopyError
282
+ | AuthConfigRequiredForUserFields
283
+ | SchemaInitializationError
284
+ | Error,
285
+ ServerFactoryService | PageRendererService | CSSCompilerService | StaticSiteGeneratorService
286
+ >
287
+ }