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,195 @@
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 { applyResponsiveOverrides, buildResponsiveClasses } from './responsive-resolver'
9
+ import type { Responsive, VariantOverrides } from '@/domain/models/app/page/common/responsive'
10
+ import type { Breakpoint } from '@/presentation/hooks/use-breakpoint'
11
+
12
+ /**
13
+ * Result of merging responsive props
14
+ */
15
+ export interface MergedResponsiveProps {
16
+ readonly mergedProps: Record<string, unknown> | undefined
17
+ readonly mergedChildren: ReadonlyArray<unknown> | undefined
18
+ readonly mergedContent: string | Record<string, unknown> | undefined
19
+ readonly visibilityClasses: string | undefined
20
+ }
21
+
22
+ /**
23
+ * Configuration for merging responsive props
24
+ */
25
+ export interface MergeResponsivePropsConfig {
26
+ readonly responsive: Responsive | undefined
27
+ readonly componentProps: Record<string, unknown> | undefined
28
+ readonly children: ReadonlyArray<unknown> | undefined
29
+ readonly content: string | Record<string, unknown> | undefined
30
+ readonly currentBreakpoint: Breakpoint
31
+ }
32
+
33
+ /**
34
+ * Remove className from props object
35
+ */
36
+ function removeClassNameFromProps(
37
+ props: Record<string, unknown> | undefined
38
+ ): Record<string, unknown> | undefined {
39
+ if (!props) return undefined
40
+
41
+ return Object.entries(props)
42
+ .filter(([key]) => key !== 'className')
43
+ .reduce<Record<string, unknown>>((acc, [key, value]) => ({ ...acc, [key]: value }), {})
44
+ }
45
+
46
+ /**
47
+ * Check if responsive config has content overrides
48
+ */
49
+ function hasContentOverrides(responsive: Responsive | undefined): boolean {
50
+ return responsive
51
+ ? Object.values(responsive).some(
52
+ (override) => (override as VariantOverrides).content !== undefined
53
+ )
54
+ : false
55
+ }
56
+
57
+ /**
58
+ * Check if responsive config has children overrides
59
+ */
60
+ function hasChildrenOverrides(responsive: Responsive | undefined): boolean {
61
+ return responsive
62
+ ? Object.values(responsive).some(
63
+ (override) => (override as VariantOverrides).children !== undefined
64
+ )
65
+ : false
66
+ }
67
+
68
+ /**
69
+ * Build visibility classes from responsive configuration
70
+ */
71
+ function buildVisibilityClasses(responsive: Responsive | undefined): string | undefined {
72
+ if (!responsive) return undefined
73
+
74
+ const visibilityConfig = (Object.entries(responsive) as [string, VariantOverrides][])
75
+ .filter(([, overrides]) => overrides.visible !== undefined)
76
+ .reduce<Record<string, boolean>>((acc, [bp, overrides]) => {
77
+ return { ...acc, [bp]: overrides.visible! }
78
+ }, {})
79
+
80
+ // For mobile:false + lg:true pattern, use max-lg:hidden
81
+ if (visibilityConfig.mobile === false && visibilityConfig.lg === true) {
82
+ return 'max-lg:hidden'
83
+ }
84
+
85
+ // For mobile:true + lg:false pattern, use lg:hidden
86
+ if (visibilityConfig.mobile === true && visibilityConfig.lg === false) {
87
+ return 'lg:hidden'
88
+ }
89
+
90
+ // Default fallback: build individual responsive classes
91
+ return Object.entries(visibilityConfig)
92
+ .map(([bp, isVisible]) => {
93
+ if (bp === 'mobile') {
94
+ return isVisible ? '' : 'max-sm:hidden'
95
+ }
96
+ return isVisible ? `${bp}:inline` : `${bp}:hidden`
97
+ })
98
+ .filter(Boolean)
99
+ .join(' ')
100
+ }
101
+
102
+ /**
103
+ * Merges responsive overrides with component props (config object signature)
104
+ */
105
+ export function mergeResponsiveProps(config: MergeResponsivePropsConfig): MergedResponsiveProps
106
+
107
+ /**
108
+ * Merges responsive overrides with component props (individual parameters signature)
109
+ */
110
+ // eslint-disable-next-line max-params -- Function overload signature
111
+ export function mergeResponsiveProps(
112
+ responsive: Responsive | undefined,
113
+ componentProps: Record<string, unknown> | undefined,
114
+ children: ReadonlyArray<unknown> | undefined,
115
+ content: string | Record<string, unknown> | undefined,
116
+ currentBreakpoint: Breakpoint
117
+ ): MergedResponsiveProps
118
+
119
+ /**
120
+ * Implementation
121
+ */
122
+ // eslint-disable-next-line max-params, max-lines-per-function, complexity -- Implementation handles both signatures
123
+ export function mergeResponsiveProps(
124
+ configOrResponsive: MergeResponsivePropsConfig | Responsive | undefined,
125
+ componentProps?: Record<string, unknown>,
126
+ children?: ReadonlyArray<unknown>,
127
+ content?: string | Record<string, unknown>,
128
+ currentBreakpoint?: Breakpoint
129
+ ): MergedResponsiveProps {
130
+ // Support both config object and individual parameters
131
+ const config: MergeResponsivePropsConfig =
132
+ configOrResponsive &&
133
+ typeof configOrResponsive === 'object' &&
134
+ 'responsive' in configOrResponsive
135
+ ? configOrResponsive
136
+ : {
137
+ responsive: configOrResponsive as Responsive | undefined,
138
+ componentProps: componentProps!,
139
+ children: children!,
140
+ content: content!,
141
+ currentBreakpoint: currentBreakpoint!,
142
+ }
143
+
144
+ const {
145
+ responsive,
146
+ componentProps: props,
147
+ children: childrenProp,
148
+ content: contentProp,
149
+ currentBreakpoint: breakpoint,
150
+ } = config
151
+
152
+ // Apply responsive overrides for current breakpoint (used for SSR initial render)
153
+ const responsiveOverrides = applyResponsiveOverrides(responsive, breakpoint)
154
+
155
+ // Build CSS-based responsive classes (works without JavaScript via Tailwind media queries)
156
+ const baseClassName = props?.className as string | undefined
157
+ const responsiveClassName = buildResponsiveClasses(responsive, baseClassName)
158
+
159
+ // Merge responsive overrides with base component values
160
+ // For className, use CSS-based responsive classes instead of JS-based overrides
161
+ const mergedPropsWithoutClassName = removeClassNameFromProps(
162
+ responsiveOverrides?.props ? { ...props, ...responsiveOverrides.props } : props
163
+ )
164
+
165
+ const mergedProps: Record<string, unknown> | undefined = responsiveClassName
166
+ ? { ...mergedPropsWithoutClassName, className: responsiveClassName }
167
+ : mergedPropsWithoutClassName
168
+
169
+ const mergedChildren = responsiveOverrides?.children ?? childrenProp
170
+ const mergedContent = responsiveOverrides?.content ?? contentProp
171
+
172
+ // Build CSS classes for responsive visibility using Tailwind breakpoint utilities
173
+ // This works without JavaScript by using CSS media queries
174
+ // Skip visibility classes when content/children overrides exist (handled by variant builders)
175
+ const shouldBuildVisibility =
176
+ responsive && !hasContentOverrides(responsive) && !hasChildrenOverrides(responsive)
177
+
178
+ const visibilityClasses = shouldBuildVisibility ? buildVisibilityClasses(responsive) : undefined
179
+
180
+ const mergedPropsWithVisibility = visibilityClasses
181
+ ? {
182
+ ...mergedProps,
183
+ className: mergedProps?.className
184
+ ? `${mergedProps.className} ${visibilityClasses}`
185
+ : visibilityClasses,
186
+ }
187
+ : mergedProps
188
+
189
+ return {
190
+ mergedProps: mergedPropsWithVisibility,
191
+ mergedChildren,
192
+ mergedContent,
193
+ visibilityClasses,
194
+ }
195
+ }
@@ -0,0 +1,213 @@
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 { Responsive, VariantOverrides } from '@/domain/models/app/page/common/responsive'
9
+ import type { Breakpoint } from '@/presentation/hooks/use-breakpoint'
10
+
11
+ /**
12
+ * Breakpoint order for progressive enhancement (mobile-first)
13
+ * Shared constant used across all responsive rendering logic
14
+ */
15
+ export const BREAKPOINT_ORDER: readonly Breakpoint[] = [
16
+ 'mobile',
17
+ 'sm',
18
+ 'md',
19
+ 'lg',
20
+ 'xl',
21
+ '2xl',
22
+ ] as const
23
+
24
+ /**
25
+ * Map breakpoints to Tailwind responsive prefixes
26
+ */
27
+ const BREAKPOINT_PREFIX: Record<Breakpoint, string> = {
28
+ mobile: '', // Mobile is base (no prefix)
29
+ sm: 'sm:',
30
+ md: 'md:',
31
+ lg: 'lg:',
32
+ xl: 'xl:',
33
+ '2xl': '2xl:',
34
+ } as const
35
+
36
+ /**
37
+ * Gets active breakpoints up to and including current breakpoint
38
+ *
39
+ * @param currentBreakpoint - Current viewport breakpoint
40
+ * @returns Array of active breakpoints in order
41
+ */
42
+ function getActiveBreakpoints(currentBreakpoint: Breakpoint): readonly Breakpoint[] {
43
+ const currentIndex = BREAKPOINT_ORDER.indexOf(currentBreakpoint)
44
+ return BREAKPOINT_ORDER.slice(0, currentIndex + 1)
45
+ }
46
+
47
+ /**
48
+ * Merges className strings
49
+ *
50
+ * Override replaces base (no concatenation)
51
+ *
52
+ * @param base - Base className
53
+ * @param override - Override className
54
+ * @returns Override className if present, else base
55
+ */
56
+ function mergeClassNames(
57
+ base: string | undefined,
58
+ override: string | undefined
59
+ ): string | undefined {
60
+ return override ?? base
61
+ }
62
+
63
+ /**
64
+ * Props value type from VariantOverrides
65
+ */
66
+ type PropsValue = string | number | boolean | readonly unknown[] | { readonly [x: string]: unknown }
67
+
68
+ /**
69
+ * Props record type from VariantOverrides
70
+ */
71
+ type PropsRecord = { readonly [x: string]: PropsValue }
72
+
73
+ /**
74
+ * Merges props objects, handling className specially
75
+ *
76
+ * @param base - Base props
77
+ * @param override - Override props
78
+ * @returns Merged props
79
+ */
80
+ function mergeProps(
81
+ base: PropsRecord | undefined,
82
+ override: PropsRecord | undefined
83
+ ): PropsRecord | undefined {
84
+ if (!base && !override) return undefined
85
+ if (!base) return override
86
+ if (!override) return base
87
+
88
+ // Use reduce for functional approach
89
+ const overrideEntries = Object.entries(override).reduce<Record<string, PropsValue>>(
90
+ (acc, [key, value]) => {
91
+ if (key === 'className') {
92
+ const mergedClassName = mergeClassNames(
93
+ base.className as string | undefined,
94
+ value as string
95
+ )
96
+ return mergedClassName !== undefined ? { ...acc, className: mergedClassName } : acc
97
+ }
98
+ return { ...acc, [key]: value }
99
+ },
100
+ {}
101
+ )
102
+
103
+ return { ...base, ...overrideEntries }
104
+ }
105
+
106
+ /**
107
+ * Applies responsive overrides for current breakpoint
108
+ *
109
+ * Uses mobile-first approach: applies base values, then progressively
110
+ * overrides with larger breakpoint values up to current breakpoint.
111
+ *
112
+ * @param responsive - Responsive configuration
113
+ * @param currentBreakpoint - Current viewport breakpoint
114
+ * @returns Merged overrides for current breakpoint
115
+ */
116
+ export function applyResponsiveOverrides(
117
+ responsive: Responsive | undefined,
118
+ currentBreakpoint: Breakpoint
119
+ ): VariantOverrides | undefined {
120
+ if (!responsive) return undefined
121
+
122
+ const activeBreakpoints = getActiveBreakpoints(currentBreakpoint)
123
+
124
+ // Use reduce for functional approach
125
+ const result = activeBreakpoints.reduce<VariantOverrides>((acc, bp) => {
126
+ const overrides = responsive[bp]
127
+ if (!overrides) return acc
128
+
129
+ // Build updated object functionally without let/mutations
130
+ const withProps = overrides.props
131
+ ? { ...acc, props: mergeProps(acc.props, overrides.props) }
132
+ : acc
133
+
134
+ const withContent =
135
+ overrides.content !== undefined ? { ...withProps, content: overrides.content } : withProps
136
+
137
+ const withVisible =
138
+ overrides.visible !== undefined ? { ...withContent, visible: overrides.visible } : withContent
139
+
140
+ const withChildren =
141
+ overrides.children !== undefined
142
+ ? { ...withVisible, children: overrides.children }
143
+ : withVisible
144
+
145
+ return withChildren
146
+ }, {})
147
+
148
+ return Object.keys(result).length > 0 ? result : undefined
149
+ }
150
+
151
+ /**
152
+ * Builds responsive CSS classes from responsive configuration
153
+ *
154
+ * Converts responsive className overrides into Tailwind responsive prefixes.
155
+ * Uses mobile-first approach: base className from props, then breakpoint-prefixed overrides.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * buildResponsiveClasses(
160
+ * {
161
+ * mobile: { props: { className: 'text-sm' } },
162
+ * md: { props: { className: 'p-8 max-w-4xl' } }
163
+ * },
164
+ * 'p-4' // Base className from props
165
+ * )
166
+ * // Returns: 'text-sm md:p-8 md:max-w-4xl'
167
+ * // Note: mobile override replaces base, md classes prefixed
168
+ * ```
169
+ *
170
+ * @param responsive - Responsive configuration
171
+ * @param baseClassName - Base className from component props
172
+ * @returns Combined CSS classes with responsive prefixes
173
+ */
174
+ export function buildResponsiveClasses(
175
+ responsive: Responsive | undefined,
176
+ baseClassName: string | undefined
177
+ ): string | undefined {
178
+ if (!responsive) return baseClassName
179
+
180
+ // Extract className from each breakpoint's props
181
+ const classNamesByBreakpoint = BREAKPOINT_ORDER.reduce<Record<string, string>>((acc, bp) => {
182
+ const overrides = responsive[bp]
183
+ const className = overrides?.props?.className as string | undefined
184
+ return className ? { ...acc, [bp]: className } : acc
185
+ }, {})
186
+
187
+ // If no responsive classNames, return base
188
+ if (Object.keys(classNamesByBreakpoint).length === 0) return baseClassName
189
+
190
+ // Determine base classes (mobile override takes precedence over props.className)
191
+ const mobileClassName = classNamesByBreakpoint.mobile
192
+ const effectiveBase = mobileClassName ?? baseClassName
193
+
194
+ // Build responsive classes for breakpoints larger than mobile
195
+ const responsiveClasses = BREAKPOINT_ORDER.filter((bp) => bp !== 'mobile')
196
+ .map((bp) => {
197
+ const className = classNamesByBreakpoint[bp]
198
+ if (!className) return undefined
199
+
200
+ const prefix = BREAKPOINT_PREFIX[bp]
201
+ // Prefix each class with breakpoint
202
+ return className
203
+ .split(' ')
204
+ .filter(Boolean)
205
+ .map((cls) => `${prefix}${cls}`)
206
+ .join(' ')
207
+ })
208
+ .filter(Boolean)
209
+ .join(' ')
210
+
211
+ // Combine base with responsive classes
212
+ return [effectiveBase, responsiveClasses].filter(Boolean).join(' ').trim() || undefined
213
+ }
@@ -0,0 +1,65 @@
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 { composeAnimation } from '@/presentation/styling/animation-composer'
9
+ import type { Component } from '@/domain/models/app/page/sections'
10
+ import type { Theme } from '@/domain/models/app/theme'
11
+
12
+ /**
13
+ * Apply all component-specific animations functionally using composition
14
+ * Compose fadeOut animation for toast components
15
+ * Compose scaleUp animation for card components with scroll trigger
16
+ * Compose float animation for fab components (continuous floating effect)
17
+ */
18
+ export function applyComponentAnimations(
19
+ type: Component['type'],
20
+ baseStyle: Record<string, unknown> | undefined,
21
+ theme?: Theme
22
+ ): Record<string, unknown> | undefined {
23
+ const styleWithFadeOut =
24
+ type === 'toast'
25
+ ? composeAnimation({
26
+ baseStyle,
27
+ animationName: 'fadeOut',
28
+ theme,
29
+ defaultDuration: '300ms',
30
+ defaultEasing: 'ease-out',
31
+ })
32
+ : baseStyle
33
+
34
+ const styleWithScaleUp =
35
+ type === 'card'
36
+ ? composeAnimation({
37
+ baseStyle: styleWithFadeOut,
38
+ animationName: 'scaleUp',
39
+ theme,
40
+ defaultDuration: '500ms',
41
+ defaultEasing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
42
+ options: {
43
+ animationPlayState: 'paused',
44
+ animationFillMode: 'forwards',
45
+ opacity: 0,
46
+ },
47
+ })
48
+ : styleWithFadeOut
49
+
50
+ const finalStyle =
51
+ type === 'fab'
52
+ ? composeAnimation({
53
+ baseStyle: styleWithScaleUp,
54
+ animationName: 'float',
55
+ theme,
56
+ defaultDuration: '3s',
57
+ defaultEasing: 'ease-in-out',
58
+ options: {
59
+ infinite: true,
60
+ },
61
+ })
62
+ : styleWithScaleUp
63
+
64
+ return finalStyle
65
+ }
@@ -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
+ /**
9
+ * Build flex-specific classes based on props
10
+ */
11
+ export function buildFlexClasses(props?: Record<string, unknown>): string {
12
+ const baseClasses = ['flex']
13
+ const alignmentClass =
14
+ props?.align === 'start'
15
+ ? 'items-start'
16
+ : props?.align === 'center'
17
+ ? 'items-center'
18
+ : props?.align === 'end'
19
+ ? 'items-end'
20
+ : undefined
21
+ const gapClass = typeof props?.gap === 'number' ? `gap-${props.gap}` : undefined
22
+
23
+ return [...baseClasses, alignmentClass, gapClass].filter(Boolean).join(' ')
24
+ }
25
+
26
+ /**
27
+ * Build grid-specific classes based on columns prop with responsive breakpoints
28
+ */
29
+ export function buildGridClasses(props?: Record<string, unknown>): string | undefined {
30
+ const baseClasses = ['grid']
31
+
32
+ // Get base column count (default to 1 for mobile-first)
33
+ const baseColumns = typeof props?.columns === 'number' ? props.columns : 1
34
+ const baseClass = `grid-cols-${baseColumns}`
35
+
36
+ // Build responsive classes from responsive property
37
+ const responsive = props?.responsive as Record<string, unknown> | undefined
38
+ const mdColumns = typeof responsive?.md === 'number' ? responsive.md : undefined
39
+ const lgColumns = typeof responsive?.lg === 'number' ? responsive.lg : undefined
40
+
41
+ const mdClass = mdColumns ? `md:grid-cols-${mdColumns}` : undefined
42
+ const lgClass = lgColumns ? `lg:grid-cols-${lgColumns}` : undefined
43
+
44
+ return [...baseClasses, baseClass, mdClass, lgClass].filter(Boolean).join(' ')
45
+ }
@@ -0,0 +1,43 @@
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 { Component } from '@/domain/models/app/page/sections'
9
+ import type { Theme } from '@/domain/models/app/theme'
10
+
11
+ /**
12
+ * Component types and their corresponding theme color mapping
13
+ */
14
+ const COMPONENT_COLOR_MAP: Record<string, keyof NonNullable<Theme['colors']>> = {
15
+ header: 'primary',
16
+ footer: 'secondary',
17
+ hero: 'background',
18
+ }
19
+
20
+ /**
21
+ * Apply theme colors to section elements automatically
22
+ *
23
+ * Maps component types to theme colors:
24
+ * - header → theme.colors.primary
25
+ * - footer → theme.colors.secondary
26
+ * - hero → theme.colors.background
27
+ *
28
+ * @param type - Component type
29
+ * @param theme - Theme configuration
30
+ * @returns Style object with background color or undefined
31
+ */
32
+ export function getSectionColorStyle(
33
+ type: Component['type'],
34
+ theme?: Theme
35
+ ): Record<string, unknown> | undefined {
36
+ if (!theme?.colors) return undefined
37
+
38
+ const colorKey = COMPONENT_COLOR_MAP[type]
39
+ if (!colorKey) return undefined
40
+
41
+ const color = theme.colors[colorKey]
42
+ return color ? { backgroundColor: color } : undefined
43
+ }
@@ -0,0 +1,107 @@
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 { HoverInteraction } from '@/domain/models/app/page/common/interactions/hover-interaction'
9
+
10
+ /**
11
+ * Maps hover interaction properties to CSS property names
12
+ *
13
+ * @param hover - Hover interaction configuration
14
+ * @returns Array of CSS property names
15
+ */
16
+ function getAnimatableProperties(hover: HoverInteraction): ReadonlyArray<string> {
17
+ return [
18
+ (hover.scale !== undefined || hover.transform) && 'transform',
19
+ hover.opacity !== undefined && 'opacity',
20
+ hover.backgroundColor && 'background-color',
21
+ hover.color && 'color',
22
+ hover.borderColor && 'border-color',
23
+ hover.shadow && 'box-shadow',
24
+ ].filter((prop): prop is string => Boolean(prop))
25
+ }
26
+
27
+ /**
28
+ * Build CSS transition styles for base element state
29
+ *
30
+ * Generates transition property for smooth hover animations.
31
+ * Applied to the base element to define which properties should animate.
32
+ * Uses explicit transition properties (transitionProperty, transitionDuration, transitionTimingFunction)
33
+ * in camelCase for React style objects.
34
+ *
35
+ * @param hover - Hover interaction configuration
36
+ * @returns Transition style object or undefined
37
+ */
38
+ export function buildHoverTransitionStyles(
39
+ hover: HoverInteraction | undefined
40
+ ): Record<string, string> | undefined {
41
+ if (!hover) return undefined
42
+
43
+ const duration = hover.duration ?? '200ms'
44
+ const easing = hover.easing ?? 'ease-out'
45
+ const transitionProps = getAnimatableProperties(hover)
46
+
47
+ if (transitionProps.length === 0) return undefined
48
+
49
+ return {
50
+ transitionProperty: transitionProps.join(', '),
51
+ transitionDuration: duration,
52
+ transitionTimingFunction: easing,
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Converts scale number to transform string
58
+ *
59
+ * @param scale - Scale factor (e.g., 1.05)
60
+ * @returns CSS transform string (e.g., 'scale(1.05)')
61
+ */
62
+ function scaleToTransform(scale: number): string {
63
+ return `scale(${scale})`
64
+ }
65
+
66
+ /**
67
+ * Build hover effect data for component
68
+ *
69
+ * Returns data attributes and style tag content for hover interactions.
70
+ * Uses a unique identifier to scope hover styles to specific elements.
71
+ *
72
+ * @param hover - Hover interaction configuration
73
+ * @param uniqueId - Unique identifier for the element
74
+ * @returns Hover data object with attributes and styles
75
+ */
76
+ export function buildHoverData(
77
+ hover: HoverInteraction | undefined,
78
+ uniqueId: string
79
+ ):
80
+ | {
81
+ readonly attributes: Record<string, string>
82
+ readonly styleContent: string
83
+ }
84
+ | undefined {
85
+ if (!hover) return undefined
86
+
87
+ // Convert scale to transform if present (scale takes priority over transform)
88
+ const transformValue = hover.scale !== undefined ? scaleToTransform(hover.scale) : hover.transform
89
+
90
+ // Build hover rules list (immutable)
91
+ // Use !important to override inline styles from props.style
92
+ const hoverRules = [
93
+ transformValue && `transform: ${transformValue} !important`,
94
+ hover.opacity !== undefined && `opacity: ${hover.opacity} !important`,
95
+ hover.backgroundColor && `background-color: ${hover.backgroundColor} !important`,
96
+ hover.color && `color: ${hover.color} !important`,
97
+ hover.borderColor && `border-color: ${hover.borderColor} !important`,
98
+ hover.shadow && `box-shadow: ${hover.shadow} !important`,
99
+ ].filter((rule): rule is string => Boolean(rule))
100
+
101
+ if (hoverRules.length === 0) return undefined
102
+
103
+ return {
104
+ attributes: { 'data-hover-id': uniqueId },
105
+ styleContent: `[data-hover-id="${uniqueId}"]:hover { ${hoverRules.join('; ')} }`,
106
+ }
107
+ }
@@ -0,0 +1,9 @@
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
+ // Barrel export for component styling utilities
9
+ // Files will be added during migration