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,120 @@
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 { OpenAPIHono, createRoute } from '@hono/zod-openapi'
9
+ import { healthResponseSchema } from '@/domain/models/api/health'
10
+
11
+ /**
12
+ * OpenAPI Schema Generator
13
+ *
14
+ * This file creates a parallel OpenAPI schema using OpenAPIHono.
15
+ * **Important**: This is separate from the runtime API routes.
16
+ *
17
+ * Located in Infrastructure layer because schema generation is an
18
+ * infrastructure concern (documentation/tooling), not presentation logic.
19
+ *
20
+ * **Why Separate?**
21
+ * - Runtime routes use regular Hono (for RPC compatibility with `:id` syntax)
22
+ * - OpenAPI schema uses OpenAPIHono (for documentation with `{id}` syntax)
23
+ * - Both share the same Zod schemas for consistency
24
+ *
25
+ * **Usage**:
26
+ * 1. Runtime: Server uses regular Hono routes from api-routes.ts
27
+ * 2. Docs: Server exposes this schema at `/api/openapi.json` and `/api/scalar`
28
+ * 3. Export: Script exports this schema to `schemas/0.0.1/app.openapi.json`
29
+ */
30
+
31
+ /**
32
+ * Create OpenAPI Hono app with all routes
33
+ *
34
+ * This function defines all API routes using OpenAPI syntax for documentation.
35
+ * The routes here are "dummy" implementations - they're only used to generate
36
+ * the OpenAPI schema. The real implementations are in api-routes.ts.
37
+ */
38
+ const createOpenApiApp = () => {
39
+ const app = new OpenAPIHono()
40
+
41
+ // Define health check route with OpenAPI annotations
42
+ const healthRoute = createRoute({
43
+ method: 'get',
44
+ path: '/api/health',
45
+ summary: 'Health check endpoint',
46
+ description:
47
+ 'Returns server health status. Used by monitoring tools and E2E tests to verify server is running.',
48
+ operationId: 'healthCheck',
49
+ tags: ['infrastructure'],
50
+ responses: {
51
+ 200: {
52
+ content: {
53
+ 'application/json': {
54
+ schema: healthResponseSchema,
55
+ },
56
+ },
57
+ description: 'Server is healthy',
58
+ },
59
+ },
60
+ })
61
+
62
+ // Mount route with dummy handler (only for schema generation)
63
+
64
+ app.openapi(healthRoute, (c) => {
65
+ return c.json({
66
+ status: 'ok',
67
+ timestamp: new Date().toISOString(),
68
+ app: {
69
+ name: 'Sovrium',
70
+ },
71
+ })
72
+ })
73
+
74
+ // Future routes will be added here:
75
+ // app.openapi(listTablesRoute, ...)
76
+ // app.openapi(getTableRoute, ...)
77
+
78
+ return app
79
+ }
80
+
81
+ /**
82
+ * Get OpenAPI document as JSON
83
+ *
84
+ * This function generates the complete OpenAPI specification document.
85
+ * It's used by:
86
+ * - `/api/openapi.json` endpoint (runtime documentation)
87
+ * - `/api/scalar` endpoint (Scalar UI)
88
+ * - `scripts/export-openapi.ts` (export to schemas/ folder)
89
+ *
90
+ * @returns OpenAPI 3.1.0 specification document
91
+ */
92
+ export const getOpenAPIDocument = () => {
93
+ const app = createOpenApiApp()
94
+
95
+ return app.getOpenAPIDocument({
96
+ openapi: '3.1.0',
97
+ info: {
98
+ title: 'Sovrium API',
99
+ version: '0.0.1',
100
+ description:
101
+ 'REST API specification for Sovrium application.\n\n' +
102
+ '**Generated Schema**: This schema is automatically generated from the runtime implementation. ' +
103
+ 'It reflects the currently implemented endpoints and their schemas.\n\n' +
104
+ '**Design Specs**: Hand-written OpenAPI specs in `docs/specifications/app/` define the complete API design. ' +
105
+ 'Comparing this generated schema with the design specs shows implementation progress.',
106
+ },
107
+ servers: [
108
+ {
109
+ url: 'http://localhost:3000',
110
+ description: 'Development server',
111
+ },
112
+ ],
113
+ tags: [
114
+ {
115
+ name: 'infrastructure',
116
+ description: 'Infrastructure endpoints (health, metrics)',
117
+ },
118
+ ],
119
+ })
120
+ }
@@ -0,0 +1,219 @@
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 { Console, Effect } from 'effect'
9
+ import { type Context, type Hono } from 'hono'
10
+ import {
11
+ detectLanguageIfEnabled,
12
+ validateLanguageSubdirectory,
13
+ } from '@/infrastructure/server/language-detection'
14
+ import type { App } from '@/domain/models/app'
15
+
16
+ /**
17
+ * Hono app configuration for route setup
18
+ */
19
+ export interface HonoAppConfig {
20
+ readonly app: App
21
+ readonly publicDir?: string
22
+ readonly renderHomePage: (app: App, detectedLanguage?: string) => string
23
+ readonly renderPage: (app: App, path: string, detectedLanguage?: string) => string | undefined
24
+ readonly renderNotFoundPage: (app?: App, detectedLanguage?: string) => string
25
+ readonly renderErrorPage: (app?: App, detectedLanguage?: string) => string
26
+ }
27
+
28
+ /**
29
+ * Setup homepage route
30
+ *
31
+ * Handles:
32
+ * - No languages configured: Serve default
33
+ * - Browser detection disabled: Serve default
34
+ * - Browser detection enabled: Detect and redirect if needed
35
+ *
36
+ * @param honoApp - Hono application instance
37
+ * @param config - Route configuration
38
+ * @returns Hono app with homepage route configured
39
+ */
40
+ export function setupHomepageRoute(honoApp: Readonly<Hono>, config: HonoAppConfig): Readonly<Hono> {
41
+ const { app, renderHomePage, renderErrorPage } = config
42
+
43
+ return honoApp.get('/', (c) => {
44
+ try {
45
+ // If no languages configured, render with default (en-US)
46
+ if (!app.languages) {
47
+ const html = renderHomePage(app, undefined)
48
+ return c.html(html)
49
+ }
50
+
51
+ // If browser detection disabled, always serve default language at /
52
+ if (app.languages.detectBrowser === false) {
53
+ const html = renderHomePage(app, undefined)
54
+ return c.html(html)
55
+ }
56
+
57
+ // Browser detection enabled - detect language from Accept-Language header
58
+ const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
59
+ const targetLanguage = detectedLanguage || app.languages.default
60
+
61
+ // Only redirect if detected language is different from default
62
+ if (targetLanguage !== app.languages.default) {
63
+ return c.redirect(`/${targetLanguage}/`, 302)
64
+ }
65
+
66
+ // Same as default - serve at / (no redirect, cacheable)
67
+ const html = renderHomePage(app, undefined)
68
+ return c.html(html)
69
+ } catch (error) {
70
+ Effect.runSync(Console.error('Error rendering homepage:', error))
71
+ return c.html(renderErrorPage(app), 500)
72
+ }
73
+ })
74
+ }
75
+
76
+ /**
77
+ * Handle /:lang/ route (homepage in specific language)
78
+ */
79
+ function handleLanguageHomepageRoute(config: HonoAppConfig) {
80
+ const { app, renderHomePage, renderPage, renderNotFoundPage, renderErrorPage } = config
81
+ return (c: Readonly<Context>) => {
82
+ try {
83
+ const { path } = c.req
84
+ const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
85
+ const exactPageMatch = renderPage(app, path, detectedLanguage)
86
+ if (exactPageMatch) {
87
+ return c.html(exactPageMatch)
88
+ }
89
+ const urlLanguage = validateLanguageSubdirectory(app, path)
90
+ if (!urlLanguage) {
91
+ const detectedLang = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
92
+ return c.html(renderNotFoundPage(app, detectedLang), 404)
93
+ }
94
+ const html = renderHomePage(app, urlLanguage)
95
+ return c.html(html)
96
+ } catch (error) {
97
+ Effect.runSync(Console.error('Error rendering homepage:', error))
98
+ const detectedLang = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
99
+ return c.html(renderErrorPage(app, detectedLang), 500)
100
+ }
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Handle /:lang/* route (pages in specific language)
106
+ */
107
+ function handleLanguagePageRoute(config: HonoAppConfig) {
108
+ const { app, renderPage, renderNotFoundPage, renderErrorPage } = config
109
+ return (c: Readonly<Context>) => {
110
+ const { path } = c.req
111
+ const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
112
+ try {
113
+ const exactPageMatch = renderPage(app, path, detectedLanguage)
114
+ if (exactPageMatch) {
115
+ return c.html(exactPageMatch)
116
+ }
117
+ const urlLanguage = validateLanguageSubdirectory(app, path)
118
+ if (!urlLanguage) {
119
+ return c.html(renderNotFoundPage(app, detectedLanguage), 404)
120
+ }
121
+ const pathWithoutLang = path.replace(`/${urlLanguage}`, '') || '/'
122
+ const html = renderPage(app, pathWithoutLang, urlLanguage)
123
+ if (!html) {
124
+ return c.html(renderNotFoundPage(app, urlLanguage), 404)
125
+ }
126
+ return c.html(html)
127
+ } catch (error) {
128
+ Effect.runSync(Console.error('Error rendering page:', error))
129
+ return c.html(renderErrorPage(app, detectedLanguage), 500)
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Setup language subdirectory routes
136
+ *
137
+ * Handles:
138
+ * - GET /:lang/ - Homepage in specific language
139
+ * - GET /:lang/* - Pages in specific language
140
+ *
141
+ * @param honoApp - Hono application instance
142
+ * @param config - Route configuration
143
+ * @returns Hono app with language routes configured
144
+ */
145
+ export function setupLanguageRoutes(
146
+ honoApp: Readonly<Hono>,
147
+ config: HonoAppConfig
148
+ ): Readonly<Hono> {
149
+ return honoApp
150
+ .get('/:lang/', handleLanguageHomepageRoute(config))
151
+ .get('/:lang/*', handleLanguagePageRoute(config))
152
+ }
153
+
154
+ /**
155
+ * Setup dynamic page routes
156
+ *
157
+ * Catches all other routes and attempts to render them as pages
158
+ *
159
+ * @param honoApp - Hono application instance
160
+ * @param config - Route configuration
161
+ * @returns Hono app with dynamic page routes configured
162
+ */
163
+ export function setupDynamicPageRoutes(
164
+ honoApp: Readonly<Hono>,
165
+ config: HonoAppConfig
166
+ ): Readonly<Hono> {
167
+ const { app, renderPage, renderNotFoundPage } = config
168
+
169
+ return honoApp.get('*', (c) => {
170
+ const { path } = c.req
171
+ const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
172
+ const html = renderPage(app, path, detectedLanguage)
173
+ if (!html) {
174
+ return c.html(renderNotFoundPage(app, detectedLanguage), 404)
175
+ }
176
+ return c.html(html)
177
+ })
178
+ }
179
+
180
+ /**
181
+ * Setup test error route
182
+ *
183
+ * Only available in non-production environments
184
+ *
185
+ * @param honoApp - Hono application instance
186
+ * @param config - Route configuration
187
+ * @returns Hono app with test error route configured
188
+ */
189
+ export function setupTestErrorRoute(
190
+ honoApp: Readonly<Hono>,
191
+ config: HonoAppConfig
192
+ ): Readonly<Hono> {
193
+ const { app, renderNotFoundPage } = config
194
+
195
+ return honoApp.get('/test/error', (c) => {
196
+ if (process.env.NODE_ENV === 'production') {
197
+ const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
198
+ return c.html(renderNotFoundPage(app, detectedLanguage), 404)
199
+ }
200
+ // eslint-disable-next-line functional/no-throw-statements
201
+ throw new Error('Test error')
202
+ })
203
+ }
204
+
205
+ /**
206
+ * Setup page routes (homepage, language subdirectories, dynamic pages)
207
+ *
208
+ * Mounts all page-related routes in correct order
209
+ *
210
+ * @param honoApp - Hono application instance
211
+ * @param config - Route configuration
212
+ * @returns Hono app with all page routes configured
213
+ */
214
+ export function setupPageRoutes(honoApp: Readonly<Hono>, config: HonoAppConfig): Readonly<Hono> {
215
+ return setupDynamicPageRoutes(
216
+ setupLanguageRoutes(setupTestErrorRoute(setupHomepageRoute(honoApp, config), config), config),
217
+ config
218
+ )
219
+ }
@@ -0,0 +1,191 @@
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 { Console, Effect } from 'effect'
9
+ import { type Context, type Hono } from 'hono'
10
+ import { generateTrackingScript } from '@/infrastructure/analytics/tracking-script'
11
+ import { compileCSS } from '@/infrastructure/css/compiler'
12
+ import type { App } from '@/domain/models/app'
13
+
14
+ /**
15
+ * Cache duration for static assets (CSS, JS) in seconds (1 hour)
16
+ */
17
+ const STATIC_ASSET_CACHE_DURATION_SECONDS = 3600
18
+
19
+ /**
20
+ * Setup CSS compilation route
21
+ *
22
+ * Serves dynamically compiled CSS with theme tokens at /assets/output.css
23
+ *
24
+ * @param honoApp - Hono application instance
25
+ * @param app - Application configuration
26
+ * @returns Hono app with CSS route configured
27
+ */
28
+ export function setupCSSRoute(honoApp: Readonly<Hono>, app: App): Readonly<Hono> {
29
+ return honoApp.get('/assets/output.css', async (c) => {
30
+ try {
31
+ const result = await Effect.runPromise(
32
+ compileCSS(app).pipe(Effect.tap(() => Console.log('CSS compiled successfully')))
33
+ )
34
+
35
+ return c.text(result.css, 200, {
36
+ 'Content-Type': 'text/css',
37
+ 'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
38
+ })
39
+ } catch (error) {
40
+ // Log error - intentional side effect for error tracking
41
+ // eslint-disable-next-line functional/no-expression-statements
42
+ await Effect.runPromise(Console.error('CSS compilation failed:', error))
43
+ return c.text('/* CSS compilation failed */', 500, {
44
+ 'Content-Type': 'text/css',
45
+ })
46
+ }
47
+ })
48
+ }
49
+
50
+ /**
51
+ * Create handler for serving JavaScript file
52
+ *
53
+ * @param scriptName - Display name for error logging
54
+ * @param scriptPath - File path to JavaScript file
55
+ * @returns Hono route handler function
56
+ */
57
+ export function createJavaScriptHandler(scriptName: string, scriptPath: string) {
58
+ return async (c: Readonly<Context>) => {
59
+ try {
60
+ const file = Bun.file(scriptPath)
61
+ const content = await file.text()
62
+
63
+ return c.text(content, 200, {
64
+ 'Content-Type': 'application/javascript',
65
+ 'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
66
+ })
67
+ } catch (error) {
68
+ // eslint-disable-next-line functional/no-expression-statements
69
+ await Effect.runPromise(Console.error(`Failed to load ${scriptName}:`, error))
70
+ return c.text(`/* ${scriptName} failed to load */`, 500, {
71
+ 'Content-Type': 'application/javascript',
72
+ })
73
+ }
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Setup built-in analytics tracking script route
79
+ *
80
+ * Serves dynamically generated analytics tracking script at /assets/analytics.js
81
+ * Template variables are replaced at serve time with app-specific values.
82
+ * Only serves the script when built-in analytics is enabled.
83
+ *
84
+ * @param honoApp - Hono application instance
85
+ * @param app - Application configuration
86
+ * @returns Hono app with analytics script route configured
87
+ */
88
+ export function setupAnalyticsScriptRoute(honoApp: Readonly<Hono>, app: App): Readonly<Hono> {
89
+ const analyticsEnabled = app.analytics !== undefined && app.analytics !== false
90
+
91
+ if (!analyticsEnabled) return honoApp
92
+
93
+ const respectDoNotTrack =
94
+ typeof app.analytics === 'object' ? app.analytics.respectDoNotTrack !== false : true
95
+ const scriptContent = generateTrackingScript(
96
+ '/api/analytics/collect',
97
+ app.name,
98
+ respectDoNotTrack
99
+ )
100
+
101
+ return honoApp.get('/assets/analytics.js', (c) => {
102
+ return c.text(scriptContent, 200, {
103
+ 'Content-Type': 'application/javascript',
104
+ 'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
105
+ })
106
+ })
107
+ }
108
+
109
+ /**
110
+ * Setup JavaScript asset routes
111
+ *
112
+ * Serves client-side JavaScript files at /assets/*.js
113
+ *
114
+ * @param honoApp - Hono application instance
115
+ * @returns Hono app with JavaScript routes configured
116
+ */
117
+ export function setupJavaScriptRoutes(honoApp: Readonly<Hono>): Readonly<Hono> {
118
+ return honoApp
119
+ .get(
120
+ '/assets/language-switcher.js',
121
+ createJavaScriptHandler(
122
+ 'language-switcher.js',
123
+ './src/presentation/scripts/client/language-switcher.js'
124
+ )
125
+ )
126
+ .get(
127
+ '/assets/banner-dismiss.js',
128
+ createJavaScriptHandler(
129
+ 'banner-dismiss.js',
130
+ './src/presentation/scripts/client/banner-dismiss.js'
131
+ )
132
+ )
133
+ .get(
134
+ '/assets/scroll-animation.js',
135
+ createJavaScriptHandler(
136
+ 'scroll-animation.js',
137
+ './src/presentation/scripts/client/scroll-animation.js'
138
+ )
139
+ )
140
+ }
141
+
142
+ /**
143
+ * Setup public directory file serving for development
144
+ *
145
+ * Serves files from a local directory at their relative path.
146
+ * e.g., `publicDir/logos/escp.png` is served at `/logos/escp.png`
147
+ *
148
+ * @param honoApp - Hono application instance
149
+ * @param publicDir - Directory path to serve files from
150
+ * @returns Hono app with public dir route configured
151
+ */
152
+ export function setupPublicDirRoute(honoApp: Readonly<Hono>, publicDir: string): Readonly<Hono> {
153
+ return honoApp.get('/*', async (c, next) => {
154
+ const { path } = c.req
155
+ const filePath = `${publicDir}${path}`
156
+ const file = Bun.file(filePath)
157
+
158
+ if (await file.exists()) {
159
+ return new Response(file, {
160
+ headers: {
161
+ 'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
162
+ },
163
+ })
164
+ }
165
+
166
+ // eslint-disable-next-line functional/no-expression-statements
167
+ await next()
168
+ })
169
+ }
170
+
171
+ /**
172
+ * Setup static asset routes (CSS, JavaScript, and optional public directory)
173
+ *
174
+ * Mounts CSS, JavaScript, and optionally public directory asset routes
175
+ *
176
+ * @param honoApp - Hono application instance
177
+ * @param app - Application configuration
178
+ * @param publicDir - Optional directory to serve static files from
179
+ * @returns Hono app with static asset routes configured
180
+ */
181
+ export function setupStaticAssets(
182
+ honoApp: Readonly<Hono>,
183
+ app: App,
184
+ publicDir?: string
185
+ ): Readonly<Hono> {
186
+ const withAssets = setupAnalyticsScriptRoute(
187
+ setupJavaScriptRoutes(setupCSSRoute(honoApp, app)),
188
+ app
189
+ )
190
+ return publicDir ? setupPublicDirRoute(withAssets, publicDir) : withAssets
191
+ }
@@ -0,0 +1,45 @@
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, Layer } from 'effect'
9
+ import { ServerFactory } from '@/application/ports/services/server-factory'
10
+ import { createServer } from './server'
11
+
12
+ /**
13
+ * Live implementation of ServerFactory using Bun.serve
14
+ *
15
+ * This Layer provides the production server creation logic,
16
+ * wrapping the infrastructure createServer function in an
17
+ * Effect Context service.
18
+ *
19
+ * The implementation uses Layer.effect because createServer
20
+ * returns an Effect (async operations with error handling).
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Provide ServerFactoryLive to use cases
25
+ * const program = startServer(appConfig).pipe(
26
+ * Effect.provide(ServerFactoryLive)
27
+ * )
28
+ * ```
29
+ */
30
+ export const ServerFactoryLive = Layer.effect(
31
+ ServerFactory,
32
+ Effect.sync(() => ({
33
+ create: (config) =>
34
+ createServer({
35
+ app: config.app,
36
+ port: config.port,
37
+ hostname: config.hostname,
38
+ publicDir: config.publicDir,
39
+ renderHomePage: config.renderHomePage,
40
+ renderPage: config.renderPage,
41
+ renderNotFoundPage: config.renderNotFoundPage,
42
+ renderErrorPage: config.renderErrorPage,
43
+ }),
44
+ }))
45
+ )