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,118 @@
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, Schema } from 'effect'
9
+ import { AppValidationError } from '@/application/errors/app-validation-error'
10
+ import { PageRenderer } from '@/application/ports/services/page-renderer'
11
+ import { ServerFactory } from '@/application/ports/services/server-factory'
12
+ import { bootstrapAdmin } from '@/application/use-cases/auth/bootstrap-admin'
13
+ import { AppSchema } from '@/domain/models/app'
14
+ import { Logger } from '@/infrastructure/logging/logger'
15
+ import type { ServerInstance } from '@/application/models/server'
16
+ import type { AuthRepository } from '@/application/ports/repositories/auth-repository'
17
+ import type { App } from '@/domain/models/app'
18
+ import type { Auth } from '@/infrastructure/auth/better-auth'
19
+ import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
20
+ import type { CSSCompilationError } from '@/infrastructure/errors/css-compilation-error'
21
+ import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
22
+ import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
23
+
24
+ /**
25
+ * Server configuration options
26
+ */
27
+ export interface StartOptions {
28
+ /**
29
+ * Port number for the HTTP server
30
+ * @default 3000
31
+ */
32
+ readonly port?: number
33
+
34
+ /**
35
+ * Hostname to bind the server to
36
+ * @default "localhost"
37
+ */
38
+ readonly hostname?: string
39
+
40
+ /**
41
+ * Directory to serve static files from during development
42
+ * Files are served at their relative path (e.g., `publicDir/logos/x.png` → `/logos/x.png`)
43
+ */
44
+ readonly publicDir?: string
45
+ }
46
+
47
+ /**
48
+ * Use case for starting an Sovrium web server
49
+ *
50
+ * This orchestrates the server startup process:
51
+ * 1. Validates the app configuration using Effect Schema
52
+ * 2. Obtains rendering and server creation services via Effect Context
53
+ * 3. Creates and starts the server via injected dependencies
54
+ * 4. Bootstraps admin account if configured via environment variables
55
+ *
56
+ * Dependencies are provided via Effect.provide(AppLayer) at the application boundary.
57
+ *
58
+ * @param app - Application configuration
59
+ * @param options - Server configuration options
60
+ * @returns Effect that yields ServerInstance or errors
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * // In src/index.ts
65
+ * const program = startServer(appConfig, { port: 3000 }).pipe(
66
+ * Effect.provide(AppLayer)
67
+ * )
68
+ * ```
69
+ */
70
+ export const startServer = (
71
+ app: unknown,
72
+ options: StartOptions = {}
73
+ ): Effect.Effect<
74
+ ServerInstance,
75
+ | AppValidationError
76
+ | ServerCreationError
77
+ | CSSCompilationError
78
+ | AuthConfigRequiredForUserFields
79
+ | SchemaInitializationError
80
+ | Error,
81
+ ServerFactory | PageRenderer | Auth | AuthRepository | Logger
82
+ > =>
83
+ Effect.gen(function* () {
84
+ // Validate app configuration using domain model schema
85
+ const validatedApp = yield* Effect.try({
86
+ try: (): App => Schema.decodeUnknownSync(AppSchema)(app),
87
+ catch: (error) => new AppValidationError(error),
88
+ })
89
+
90
+ // Obtain dependencies from Effect Context
91
+ const serverFactory = yield* ServerFactory
92
+ const pageRenderer = yield* PageRenderer
93
+
94
+ // Bootstrap admin account BEFORE starting the server
95
+ // This ensures admin user exists before server signals "ready"
96
+ const logger = yield* Logger
97
+ yield* bootstrapAdmin(validatedApp).pipe(
98
+ Effect.catchAll((error) =>
99
+ // Log bootstrap errors but don't fail server startup
100
+ logger.warn('Admin bootstrap error', error.message)
101
+ )
102
+ )
103
+
104
+ // Create server using injected dependencies
105
+ // Server only starts listening after bootstrap completes
106
+ const serverInstance = yield* serverFactory.create({
107
+ app: validatedApp,
108
+ port: options.port,
109
+ hostname: options.hostname,
110
+ publicDir: options.publicDir,
111
+ renderHomePage: pageRenderer.renderHome,
112
+ renderPage: pageRenderer.renderPage,
113
+ renderNotFoundPage: pageRenderer.renderNotFound,
114
+ renderErrorPage: pageRenderer.renderError,
115
+ })
116
+
117
+ return serverInstance
118
+ })
@@ -0,0 +1,69 @@
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 } from 'effect'
9
+ import type { AppValidationError } from '@/application/errors/app-validation-error'
10
+ import type { CSSCompilationError } from '@/infrastructure/errors/css-compilation-error'
11
+ import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
12
+
13
+ /**
14
+ * Error types that can occur during server startup
15
+ */
16
+ export type ServerStartupError = AppValidationError | ServerCreationError | CSSCompilationError
17
+
18
+ /**
19
+ * Handles server startup errors and logs appropriate messages
20
+ *
21
+ * This utility provides comprehensive error handling for all error types
22
+ * that can occur during server startup, including:
23
+ * - App validation errors (invalid configuration)
24
+ * - Server creation errors (port already in use, etc.)
25
+ * - CSS compilation errors (Tailwind/PostCSS issues)
26
+ *
27
+ * @param error - Error that occurred during server startup
28
+ * @returns Effect that logs error details and exits with code 1
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { Effect } from 'effect'
33
+ * import { start } from '@/index'
34
+ * import { handleStartupError } from '@/application/use-cases/server/startup-error-handler'
35
+ *
36
+ * const program = start(myApp).pipe(
37
+ * Effect.catchAll(handleStartupError)
38
+ * )
39
+ *
40
+ * Effect.runPromise(program)
41
+ * ```
42
+ */
43
+ export const handleStartupError = (error: ServerStartupError): Effect.Effect<never> =>
44
+ Effect.gen(function* () {
45
+ yield* Console.error('Failed to start server:')
46
+
47
+ // Handle specific error types
48
+ if ('_tag' in error) {
49
+ switch (error._tag) {
50
+ case 'AppValidationError':
51
+ yield* Console.error('Invalid app configuration:', error.cause)
52
+ break
53
+ case 'ServerCreationError':
54
+ yield* Console.error('Server creation failed:', error.cause)
55
+ break
56
+ case 'CSSCompilationError':
57
+ yield* Console.error('CSS compilation failed:', error.cause)
58
+ break
59
+ default:
60
+ yield* Console.error('Unknown error:', error)
61
+ }
62
+ } else {
63
+ yield* Console.error('Unknown error:', error)
64
+ }
65
+
66
+ // Exit process with error code
67
+ // eslint-disable-next-line functional/no-expression-statements
68
+ process.exit(1)
69
+ })
@@ -0,0 +1,182 @@
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 type { Page } from '@/domain/models/app'
9
+
10
+ /**
11
+ * Hreflang configuration for multilingual sitemaps
12
+ */
13
+ export interface HreflangConfig {
14
+ /** Maps language codes to full locales (e.g., { en: 'en-US', fr: 'fr-FR' }) */
15
+ readonly localeMap: Readonly<Record<string, string>>
16
+ /** Default language code for x-default hreflang (e.g., 'en') */
17
+ readonly defaultLanguage: string
18
+ }
19
+
20
+ /**
21
+ * Format HTML with Prettier for professional formatting
22
+ * Loads Prettier config and formats HTML using the HTML parser
23
+ */
24
+ export const formatHtmlWithPrettier = async (html: string): Promise<string> => {
25
+ const prettier = await import('prettier')
26
+ const config = await prettier.resolveConfig(process.cwd())
27
+
28
+ return await prettier.format(html, {
29
+ ...config,
30
+ parser: 'html',
31
+ })
32
+ }
33
+
34
+ /**
35
+ * Build the full URL for a page in a specific language
36
+ */
37
+ const buildLanguageUrl = (baseUrl: string, lang: string, pagePath: string): string => {
38
+ const normalizedPath = pagePath === '/' ? '' : pagePath
39
+ return `${baseUrl}/${lang}${normalizedPath}${normalizedPath === '' ? '/' : ''}`
40
+ }
41
+
42
+ /**
43
+ * Generate hreflang <xhtml:link> elements for a single URL entry
44
+ */
45
+ export const generateHreflangLinks = (
46
+ baseUrl: string,
47
+ pagePath: string,
48
+ languages: readonly string[],
49
+ hreflangConfig: HreflangConfig
50
+ ): readonly string[] => {
51
+ const languageLinks = languages.map((lang) => {
52
+ const locale = hreflangConfig.localeMap[lang] ?? lang
53
+ const url = buildLanguageUrl(baseUrl, lang, pagePath)
54
+ return `<xhtml:link rel="alternate" hreflang="${locale}" href="${url}" />`
55
+ })
56
+
57
+ const defaultUrl = buildLanguageUrl(baseUrl, hreflangConfig.defaultLanguage, pagePath)
58
+ const xDefaultLink = `<xhtml:link rel="alternate" hreflang="x-default" href="${defaultUrl}" />`
59
+
60
+ return [...languageLinks, xDefaultLink]
61
+ }
62
+
63
+ /**
64
+ * Build a single <url> entry for the sitemap
65
+ */
66
+ const buildUrlEntry = (
67
+ loc: string,
68
+ lastmod: string,
69
+ page: Page,
70
+ hreflangSection: string
71
+ ): string => {
72
+ const priority = page.meta?.priority ?? 0.5
73
+ const changefreq = page.meta?.changefreq ?? 'monthly'
74
+ return ` <url>
75
+ <loc>${loc}</loc>${hreflangSection}
76
+ <lastmod>${lastmod}</lastmod>
77
+ <priority>${priority.toFixed(1)}</priority>
78
+ <changefreq>${changefreq}</changefreq>
79
+ </url>`
80
+ }
81
+
82
+ /**
83
+ * Generate sitemap.xml content
84
+ */
85
+ export const generateSitemapContent = (
86
+ pages: readonly Page[],
87
+ baseUrl: string,
88
+ _basePath: string = '',
89
+ options?: { readonly languages?: readonly string[]; readonly hreflangConfig?: HreflangConfig }
90
+ ): string => {
91
+ const indexablePages = pages.filter((page) => !page.meta?.noindex && !page.path.startsWith('/_'))
92
+ const lastmod = new Date().toISOString().split('T')[0] ?? ''
93
+ const languages = options?.languages
94
+ const hreflangConfig = options?.hreflangConfig
95
+ const hasHreflang = languages && languages.length > 0 && hreflangConfig !== undefined
96
+
97
+ const entries: readonly string[] =
98
+ languages && languages.length > 0
99
+ ? languages.flatMap((lang) =>
100
+ indexablePages.map((page) => {
101
+ const hreflangLinks = hasHreflang
102
+ ? generateHreflangLinks(baseUrl, page.path, languages, hreflangConfig).map(
103
+ (link) => ` ${link}`
104
+ )
105
+ : []
106
+ const hreflangSection = hreflangLinks.length > 0 ? `\n${hreflangLinks.join('\n')}` : ''
107
+ return buildUrlEntry(
108
+ buildLanguageUrl(baseUrl, lang, page.path),
109
+ lastmod,
110
+ page,
111
+ hreflangSection
112
+ )
113
+ })
114
+ )
115
+ : indexablePages.map((page) => buildUrlEntry(`${baseUrl}${page.path}`, lastmod, page, ''))
116
+
117
+ const xmlnsAttr = hasHreflang
118
+ ? ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"\n xmlns:xhtml="http://www.w3.org/1999/xhtml"'
119
+ : ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"'
120
+
121
+ return `<?xml version="1.0" encoding="UTF-8"?>
122
+ <urlset${xmlnsAttr}>
123
+ ${entries.join('\n')}
124
+ </urlset>`
125
+ }
126
+
127
+ /**
128
+ * Generate robots.txt content
129
+ */
130
+ export const generateRobotsContent = (
131
+ pages: readonly Page[],
132
+ baseUrl: string,
133
+ _basePath: string = '',
134
+ includeSitemap: boolean = false
135
+ ): string => {
136
+ const baseLines = ['User-agent: *', 'Allow: /']
137
+
138
+ // Add Disallow rules for:
139
+ // 1. Pages with noindex or robots directives containing "noindex"
140
+ // 2. Underscore-prefixed pages (admin/internal pages)
141
+ const disallowedPages = pages.filter(
142
+ (page) =>
143
+ page.meta?.noindex === true ||
144
+ (page.meta?.robots && page.meta.robots.includes('noindex')) ||
145
+ page.path.startsWith('/_')
146
+ )
147
+
148
+ const disallowLines = disallowedPages.map((page) => `Disallow: ${page.path}`)
149
+
150
+ const sitemapLine = includeSitemap ? [`Sitemap: ${baseUrl}/sitemap.xml`] : []
151
+ const lines = [...baseLines, ...disallowLines, ...sitemapLine]
152
+
153
+ return lines.join('\n')
154
+ }
155
+
156
+ /**
157
+ * Generate client-side hydration script
158
+ *
159
+ * This minimal script enables React hydration on the client side.
160
+ * For production, this would:
161
+ * - Load React runtime
162
+ * - Re-render components with client-side state
163
+ * - Attach event listeners
164
+ * - Enable interactive features
165
+ *
166
+ * Current implementation: Minimal placeholder for testing
167
+ */
168
+ export const generateClientHydrationScript = (): string => {
169
+ return `/**
170
+ * Sovrium Client-Side Hydration Script
171
+ * Generated by Sovrium Static Site Generator
172
+ */
173
+
174
+ // Minimal hydration script for static sites
175
+ // This enables client-side interactivity after initial SSR
176
+ console.log('Sovrium: Client-side hydration enabled')
177
+
178
+ // Future: Load React runtime and hydrate components
179
+ // Future: Initialize client-side routing
180
+ // Future: Restore interactive state
181
+ `
182
+ }
@@ -0,0 +1,181 @@
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
+ /* eslint-disable max-params, max-lines-per-function -- Complex multi-language generators require explicit dependencies */
9
+
10
+ import { Effect, Console, Schema, type Context } from 'effect'
11
+ import { AppValidationError } from '@/application/errors/app-validation-error'
12
+ import { AppSchema } from '@/domain/models/app'
13
+ import type { CSSCompilationError } from '@/application/ports/services/css-compiler'
14
+ import type { PageRenderer as PageRendererService } from '@/application/ports/services/page-renderer'
15
+ import type { ServerFactory as ServerFactoryService } from '@/application/ports/services/server-factory'
16
+ import type {
17
+ SSGGenerationError,
18
+ StaticSiteGenerator as StaticSiteGeneratorService,
19
+ } from '@/application/ports/services/static-site-generator'
20
+ import type { App } from '@/domain/models/app'
21
+ import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
22
+ import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
23
+ import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
24
+
25
+ // Service types extracted from Context.Tag
26
+ type ServerFactory = Context.Tag.Service<ServerFactoryService>
27
+ type PageRenderer = Context.Tag.Service<PageRendererService>
28
+ type StaticSiteGenerator = Context.Tag.Service<StaticSiteGeneratorService>
29
+
30
+ /**
31
+ * Generate static files for multi-language configuration
32
+ */
33
+ export const generateMultiLanguageFiles = (
34
+ validatedApp: App,
35
+ outputDir: string,
36
+ replaceAppTokens: (app: App, lang: string) => App,
37
+ serverFactory: ServerFactory,
38
+ pageRenderer: PageRenderer,
39
+ staticSiteGenerator: StaticSiteGenerator
40
+ ): Effect.Effect<
41
+ readonly string[],
42
+ | AppValidationError
43
+ | CSSCompilationError
44
+ | ServerCreationError
45
+ | SSGGenerationError
46
+ | AuthConfigRequiredForUserFields
47
+ | SchemaInitializationError
48
+ | Error,
49
+ never
50
+ > =>
51
+ Effect.gen(function* () {
52
+ yield* Console.log(`🌍 Generating multi-language static site...`)
53
+ const supportedLanguages = validatedApp.languages!.supported
54
+
55
+ // Generate files for each language using Effect.forEach
56
+ const langFiles = yield* Effect.forEach(
57
+ supportedLanguages,
58
+ (lang) =>
59
+ Effect.gen(function* () {
60
+ yield* Console.log(`📝 Generating pages for language: ${lang.code}...`)
61
+
62
+ // Replace tokens for this language
63
+ const langApp = replaceAppTokens(validatedApp, lang.code)
64
+
65
+ // Validate the language-specific app
66
+ const validatedLangApp = yield* Effect.try({
67
+ try: (): App => Schema.decodeUnknownSync(AppSchema)(langApp),
68
+ catch: (error) => new AppValidationError(error),
69
+ })
70
+
71
+ // Create server instance for this language
72
+ const serverInstance = yield* serverFactory.create({
73
+ app: validatedLangApp,
74
+ port: 0,
75
+ hostname: 'localhost',
76
+ renderHomePage: pageRenderer.renderHome,
77
+ renderPage: pageRenderer.renderPage,
78
+ renderNotFoundPage: pageRenderer.renderNotFound,
79
+ renderErrorPage: pageRenderer.renderError,
80
+ })
81
+
82
+ yield* serverInstance.stop
83
+
84
+ // Generate static files in language subdirectory
85
+ const langOutputDir = `${outputDir}/${lang.code}`
86
+ // Filter out underscore-prefixed pages (admin/internal pages)
87
+ const pagePaths =
88
+ validatedLangApp.pages
89
+ ?.filter((page) => !page.path.startsWith('/_'))
90
+ .map((page) => page.path) || []
91
+ const ssgResult = yield* staticSiteGenerator.generate(serverInstance.app, {
92
+ outputDir: langOutputDir,
93
+ pagePaths,
94
+ })
95
+
96
+ // Return files with language prefix (normalize paths to be relative)
97
+ return ssgResult.files.map((f) => {
98
+ // toSSG returns relative paths from the outputDir
99
+ // Simply prefix with language code
100
+ return `${lang.code}/${f}`
101
+ })
102
+ }),
103
+ { concurrency: 'unbounded' }
104
+ )
105
+
106
+ // Generate root index.html with default language
107
+ yield* Console.log(`📝 Generating root index.html with default language...`)
108
+ const defaultLang = validatedApp.languages!.default
109
+ const defaultLangApp = replaceAppTokens(validatedApp, defaultLang)
110
+ const validatedDefaultApp = yield* Effect.try({
111
+ try: (): App => Schema.decodeUnknownSync(AppSchema)(defaultLangApp),
112
+ catch: (error) => new AppValidationError(error),
113
+ })
114
+
115
+ const defaultServer = yield* serverFactory.create({
116
+ app: validatedDefaultApp,
117
+ port: 0,
118
+ hostname: 'localhost',
119
+ renderHomePage: pageRenderer.renderHome,
120
+ renderPage: pageRenderer.renderPage,
121
+ renderNotFoundPage: pageRenderer.renderNotFound,
122
+ renderErrorPage: pageRenderer.renderError,
123
+ })
124
+
125
+ yield* defaultServer.stop
126
+
127
+ // Generate only root index.html
128
+ const rootSSGResult = yield* staticSiteGenerator.generate(defaultServer.app, {
129
+ outputDir,
130
+ pagePaths: ['/'],
131
+ })
132
+
133
+ // Combine all files immutably
134
+ return [...langFiles.flat(), ...rootSSGResult.files]
135
+ })
136
+
137
+ /**
138
+ * Generate static files for single-language configuration
139
+ */
140
+ export const generateSingleLanguageFiles = (
141
+ validatedApp: App,
142
+ outputDir: string,
143
+ serverFactory: ServerFactory,
144
+ pageRenderer: PageRenderer,
145
+ staticSiteGenerator: StaticSiteGenerator
146
+ ): Effect.Effect<
147
+ readonly string[],
148
+ | CSSCompilationError
149
+ | ServerCreationError
150
+ | SSGGenerationError
151
+ | AuthConfigRequiredForUserFields
152
+ | SchemaInitializationError
153
+ | Error,
154
+ never
155
+ > =>
156
+ Effect.gen(function* () {
157
+ // No multi-language - generate normally
158
+ yield* Console.log('🏗️ Creating application instance...')
159
+ const serverInstance = yield* serverFactory.create({
160
+ app: validatedApp,
161
+ port: 0,
162
+ hostname: 'localhost',
163
+ renderHomePage: pageRenderer.renderHome,
164
+ renderPage: pageRenderer.renderPage,
165
+ renderNotFoundPage: pageRenderer.renderNotFound,
166
+ renderErrorPage: pageRenderer.renderError,
167
+ })
168
+
169
+ yield* serverInstance.stop
170
+
171
+ // Filter out underscore-prefixed pages (admin/internal pages)
172
+ const pagePaths =
173
+ validatedApp.pages?.filter((page) => !page.path.startsWith('/_')).map((page) => page.path) ||
174
+ []
175
+ yield* Console.log(`📝 Generating static HTML files for ${pagePaths.length} pages...`)
176
+ const ssgResult = yield* staticSiteGenerator.generate(serverInstance.app, {
177
+ outputDir,
178
+ pagePaths,
179
+ })
180
+ return ssgResult.files
181
+ })