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,55 @@
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 { buildHoverData } from './hover-interaction-handler'
9
+ import type { Interactions } from '@/domain/models/app/page/common/interactions/interactions'
10
+
11
+ /**
12
+ * Merges hover attributes into element props
13
+ *
14
+ * @param elementProps - Base element props
15
+ * @param hoverData - Hover data with attributes
16
+ * @returns Element props with hover attributes merged
17
+ */
18
+ function mergeHoverAttributes(
19
+ elementProps: Record<string, unknown>,
20
+ hoverData: { readonly attributes: Record<string, string> } | undefined
21
+ ): Record<string, unknown> {
22
+ return hoverData ? { ...elementProps, ...hoverData.attributes } : elementProps
23
+ }
24
+
25
+ /**
26
+ * Builds interaction props with hover data merged into element props
27
+ *
28
+ * @param interactions - Component interactions configuration
29
+ * @param uniqueId - Unique ID for hover data
30
+ * @param elementProps - Base element props
31
+ * @param elementPropsWithSpacing - Base element props with spacing
32
+ * @returns Element props with hover attributes and hover data for style injection
33
+ */
34
+ export function buildInteractionProps(
35
+ interactions: Interactions | undefined,
36
+ uniqueId: string,
37
+ elementProps: Record<string, unknown>,
38
+ elementPropsWithSpacing: Record<string, unknown>
39
+ ): {
40
+ readonly finalElementProps: Record<string, unknown>
41
+ readonly finalElementPropsWithSpacing: Record<string, unknown>
42
+ readonly hoverData:
43
+ | { readonly attributes: Record<string, string>; readonly styleContent: string }
44
+ | undefined
45
+ } {
46
+ const hoverData = buildHoverData(interactions?.hover, uniqueId)
47
+ const finalElementProps = mergeHoverAttributes(elementProps, hoverData)
48
+ const finalElementPropsWithSpacing = mergeHoverAttributes(elementPropsWithSpacing, hoverData)
49
+
50
+ return {
51
+ finalElementProps,
52
+ finalElementPropsWithSpacing,
53
+ hoverData,
54
+ }
55
+ }
@@ -0,0 +1,83 @@
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
+ * Standard shadow size names
13
+ */
14
+ const STANDARD_SHADOWS = ['sm', 'md', 'lg', 'xl', '2xl', 'inner', 'none'] as const
15
+
16
+ /**
17
+ * Shadow mapping for component types
18
+ */
19
+ const COMPONENT_SHADOW_MAP: Record<string, readonly string[]> = {
20
+ 'list-item': ['sm'],
21
+ dropdown: ['lg'],
22
+ modal: ['xl'],
23
+ input: ['inner'],
24
+ button: ['brand', 'md'],
25
+ card: [], // Card uses custom logic
26
+ }
27
+
28
+ /**
29
+ * Find first available custom shadow (non-standard)
30
+ */
31
+ function findCustomShadow(shadows: Theme['shadows']): string | undefined {
32
+ if (!shadows) return undefined
33
+ return Object.keys(shadows).find((name) => !STANDARD_SHADOWS.includes(name as never))
34
+ }
35
+
36
+ /**
37
+ * Get shadow value for component type
38
+ */
39
+ function getShadowForType(type: Component['type'], shadows: Theme['shadows']): string | undefined {
40
+ if (!shadows) return undefined
41
+
42
+ // Special handling for card: custom shadows first, then md
43
+ if (type === 'card') {
44
+ const customShadow = findCustomShadow(shadows)
45
+ if (customShadow) {
46
+ return `var(--shadow-${customShadow})`
47
+ }
48
+ return shadows.md ? 'var(--shadow-md)' : undefined
49
+ }
50
+
51
+ // Standard component shadow resolution
52
+ const shadowPriority = COMPONENT_SHADOW_MAP[type]
53
+ if (!shadowPriority) {
54
+ return undefined
55
+ }
56
+
57
+ const foundShadow = shadowPriority.find((shadowName) =>
58
+ Boolean(shadows[shadowName as keyof typeof shadows])
59
+ )
60
+
61
+ return foundShadow ? `var(--shadow-${foundShadow})` : undefined
62
+ }
63
+
64
+ /**
65
+ * Apply theme shadows to component types based on conventions
66
+ * - Card components use available shadow tokens (md, neumorphic, etc.)
67
+ * - Modal components use xl shadow
68
+ * - Input components use inner shadow
69
+ * - Button components use md shadow (or custom like brand)
70
+ * - List-item components use sm shadow (lowest elevation)
71
+ * - Dropdown components use lg shadow (higher than card, lower than modal)
72
+ */
73
+ export function getComponentShadow(
74
+ type: Component['type'],
75
+ theme?: Theme
76
+ ): Record<string, unknown> | undefined {
77
+ if (!theme?.shadows) {
78
+ return undefined
79
+ }
80
+
81
+ const shadowValue = getShadowForType(type, theme.shadows)
82
+ return shadowValue ? { boxShadow: shadowValue } : undefined
83
+ }
@@ -0,0 +1,104 @@
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 { isCssValue } from '@/presentation/styling/style-utils'
9
+ import { getSectionColorStyle } from './color-resolver'
10
+ import type { Component } from '@/domain/models/app/page/sections'
11
+ import type { Theme } from '@/domain/models/app/theme'
12
+
13
+ /**
14
+ * Component types that should receive section spacing
15
+ */
16
+ const SECTION_TYPES = new Set(['section', 'header', 'footer', 'hero'])
17
+
18
+ /**
19
+ * Apply theme spacing to section elements when spacing.section is a CSS value
20
+ */
21
+ export function getSectionSpacingStyle(
22
+ type: Component['type'],
23
+ theme?: Theme
24
+ ): Record<string, unknown> | undefined {
25
+ const sectionSpacing = SECTION_TYPES.has(type) && theme?.spacing?.section
26
+ return sectionSpacing && isCssValue(sectionSpacing) ? { padding: sectionSpacing } : undefined
27
+ }
28
+
29
+ /**
30
+ * Apply theme spacing to container elements when spacing.container is a CSS value
31
+ */
32
+ export function getContainerSpacingStyle(
33
+ type: Component['type'],
34
+ theme?: Theme
35
+ ): Record<string, unknown> | undefined {
36
+ const containerSpacing = type === 'container' && theme?.spacing?.container
37
+ return containerSpacing && isCssValue(containerSpacing)
38
+ ? { maxWidth: containerSpacing, margin: '0 auto' }
39
+ : undefined
40
+ }
41
+
42
+ /**
43
+ * Apply theme spacing to flex elements when spacing.gap is a CSS value
44
+ */
45
+ export function getFlexSpacingStyle(
46
+ type: Component['type'],
47
+ theme?: Theme
48
+ ): Record<string, unknown> | undefined {
49
+ const flexSpacing = type === 'flex' && theme?.spacing?.gap
50
+ return flexSpacing && isCssValue(flexSpacing) ? { display: 'flex', gap: flexSpacing } : undefined
51
+ }
52
+
53
+ /**
54
+ * Apply all spacing and color styles in order: color → section → container → flex
55
+ */
56
+ export function applySpacingStyles(
57
+ type: Component['type'],
58
+ baseProps: Record<string, unknown>,
59
+ theme?: Theme
60
+ ): Record<string, unknown> {
61
+ const colorStyle = getSectionColorStyle(type, theme)
62
+ const propsWithColor = colorStyle
63
+ ? {
64
+ ...baseProps,
65
+ style: {
66
+ ...(baseProps.style as Record<string, unknown> | undefined),
67
+ ...colorStyle,
68
+ },
69
+ }
70
+ : baseProps
71
+
72
+ const sectionSpacingStyle = getSectionSpacingStyle(type, theme)
73
+ const propsWithSection = sectionSpacingStyle
74
+ ? {
75
+ ...propsWithColor,
76
+ style: {
77
+ ...(propsWithColor.style as Record<string, unknown> | undefined),
78
+ ...sectionSpacingStyle,
79
+ },
80
+ }
81
+ : propsWithColor
82
+
83
+ const containerSpacingStyle = getContainerSpacingStyle(type, theme)
84
+ const propsWithContainer = containerSpacingStyle
85
+ ? {
86
+ ...propsWithSection,
87
+ style: {
88
+ ...(propsWithSection.style as Record<string, unknown> | undefined),
89
+ ...containerSpacingStyle,
90
+ },
91
+ }
92
+ : propsWithSection
93
+
94
+ const flexSpacingStyle = getFlexSpacingStyle(type, theme)
95
+ return flexSpacingStyle
96
+ ? {
97
+ ...propsWithContainer,
98
+ style: {
99
+ ...(propsWithContainer.style as Record<string, unknown> | undefined),
100
+ ...flexSpacingStyle,
101
+ },
102
+ }
103
+ : propsWithContainer
104
+ }
@@ -0,0 +1,170 @@
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 {
9
+ isCssProperty,
10
+ normalizeStyleAnimations,
11
+ parseStyle,
12
+ } from '@/presentation/styling/parse-style'
13
+ import { applyComponentAnimations } from './animation-composer-wrapper'
14
+ import { buildFlexClasses, buildGridClasses } from './class-builders'
15
+ import { getComponentShadow } from './shadow-resolver'
16
+ import type { Interactions } from '@/domain/models/app/page/common/interactions/interactions'
17
+ import type { Component } from '@/domain/models/app/page/sections'
18
+ import type { Theme } from '@/domain/models/app/theme'
19
+
20
+ /**
21
+ * Extract CSS properties from props object
22
+ * Separates CSS properties (e.g., maxWidth, backgroundColor) from other props
23
+ *
24
+ * @param props - Props object that may contain CSS properties
25
+ * @returns Object with cssProps and remainingProps
26
+ */
27
+ export function extractCssProperties(props: Record<string, unknown> | undefined): {
28
+ readonly cssProps: Record<string, unknown>
29
+ readonly remainingProps: Record<string, unknown>
30
+ } {
31
+ if (!props) {
32
+ return { cssProps: {}, remainingProps: {} }
33
+ }
34
+
35
+ // Use reduce for immutable accumulation
36
+ return Object.entries(props).reduce<{
37
+ readonly cssProps: Record<string, unknown>
38
+ readonly remainingProps: Record<string, unknown>
39
+ }>(
40
+ (acc, [key, value]) => {
41
+ if (isCssProperty(key)) {
42
+ return {
43
+ ...acc,
44
+ cssProps: { ...acc.cssProps, [key]: value },
45
+ }
46
+ }
47
+ return {
48
+ ...acc,
49
+ remainingProps: { ...acc.remainingProps, [key]: value },
50
+ }
51
+ },
52
+ { cssProps: {}, remainingProps: {} }
53
+ )
54
+ }
55
+
56
+ /**
57
+ * Parse and normalize style object
58
+ * Extracts CSS properties from the root of the props object and merges them with the style property
59
+ */
60
+ export function parseComponentStyle(
61
+ styleValue: unknown,
62
+ props: Record<string, unknown> | undefined
63
+ ): Record<string, unknown> | undefined {
64
+ // Parse the explicit style property
65
+ const explicitStyle = styleValue
66
+ ? normalizeStyleAnimations(
67
+ typeof styleValue === 'string'
68
+ ? parseStyle(styleValue)
69
+ : (styleValue as Record<string, unknown>)
70
+ )
71
+ : undefined
72
+
73
+ // Extract CSS properties from props (excluding the style property itself)
74
+ const { cssProps } = extractCssProperties(props)
75
+
76
+ // Remove the style property from cssProps if it exists (already handled above)
77
+ const { style: _style, ...cssPropsWithoutStyle } = cssProps
78
+
79
+ // Merge CSS properties with explicit style
80
+ const mergedStyle = {
81
+ ...cssPropsWithoutStyle,
82
+ ...explicitStyle,
83
+ }
84
+
85
+ return Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined
86
+ }
87
+
88
+ /**
89
+ * Maps component types to their corresponding CSS class names in @layer components.
90
+ * These classes are automatically added to the element when rendering.
91
+ *
92
+ * Most types map directly (e.g. 'card' -> 'card'), but 'button' maps to 'btn'
93
+ * because the CSS components layer uses `.btn` (not a `button` type selector)
94
+ * to avoid applying default button styles to all `<button>` elements globally.
95
+ */
96
+ const COMPONENT_TYPE_CLASS_MAP: Partial<Record<string, string>> = {
97
+ card: 'card',
98
+ badge: 'badge',
99
+ btn: 'btn',
100
+ button: 'btn',
101
+ }
102
+
103
+ /**
104
+ * Build entrance animation class from interactions
105
+ *
106
+ * @param interactions - Component interactions
107
+ * @returns Animation class or undefined
108
+ */
109
+ function buildEntranceAnimationClass(interactions: Interactions | undefined): string | undefined {
110
+ if (!interactions?.entrance?.animation) return undefined
111
+
112
+ return `animate-${interactions.entrance.animation}`
113
+ }
114
+
115
+ /**
116
+ * Configuration for building final className
117
+ */
118
+ type BuildClassNameConfig = {
119
+ readonly type: Component['type']
120
+ readonly className: unknown
121
+ readonly substitutedProps: Record<string, unknown> | undefined
122
+ readonly interactions: Interactions | undefined
123
+ }
124
+
125
+ /**
126
+ * Build final className based on component type
127
+ */
128
+ export function buildFinalClassName(config: BuildClassNameConfig): string | undefined {
129
+ const { type, className, substitutedProps, interactions } = config
130
+
131
+ // Build classes array immutably
132
+ const typeClass = COMPONENT_TYPE_CLASS_MAP[type]
133
+ const flexClass = type === 'flex' ? buildFlexClasses(substitutedProps) : undefined
134
+ const gridClass = type === 'grid' ? buildGridClasses(substitutedProps) : undefined
135
+ const customClass = className as string | undefined
136
+ const entranceClass = buildEntranceAnimationClass(interactions)
137
+ // Don't add scroll animation class to initial className - it will be added by scroll-animation.js
138
+ const scrollClass = undefined
139
+
140
+ const classes = [typeClass, flexClass, gridClass, customClass, entranceClass, scrollClass]
141
+ .filter(Boolean)
142
+ .join(' ')
143
+ return classes || undefined
144
+ }
145
+
146
+ /**
147
+ * Apply shadow to style based on component type
148
+ */
149
+ export function applyComponentShadow(
150
+ type: Component['type'],
151
+ style: Record<string, unknown> | undefined,
152
+ theme: Theme | undefined
153
+ ): Record<string, unknown> | undefined {
154
+ const componentShadow = getComponentShadow(type, theme)
155
+ return componentShadow ? { ...style, ...componentShadow } : style
156
+ }
157
+
158
+ /**
159
+ * Process style with animations and shadows
160
+ */
161
+ export function processComponentStyle(
162
+ type: Component['type'],
163
+ styleValue: unknown,
164
+ theme: Theme | undefined,
165
+ props?: Record<string, unknown> | undefined
166
+ ): Record<string, unknown> | undefined {
167
+ const baseStyle = parseComponentStyle(styleValue, props)
168
+ const styleWithAnimations = applyComponentAnimations(type, baseStyle, theme)
169
+ return applyComponentShadow(type, styleWithAnimations, theme)
170
+ }
@@ -0,0 +1,184 @@
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 { Theme } from '@/domain/models/app/theme'
9
+
10
+ /**
11
+ * Substitutes theme tokens in a value
12
+ *
13
+ * Replaces `$theme.category.key` patterns with actual theme values.
14
+ * Supports multiple tokens in a single string.
15
+ *
16
+ * @param value - Value that may contain theme tokens
17
+ * @param theme - Theme configuration
18
+ * @returns Value with theme tokens replaced
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const theme = {
23
+ * colors: { primary: '#007bff' },
24
+ * spacing: { section: 'py-16', container: 'px-4' }
25
+ * }
26
+ * substituteThemeTokens('$theme.colors.primary', theme)
27
+ * // '#007bff'
28
+ *
29
+ * substituteThemeTokens('$theme.spacing.section $theme.spacing.container', theme)
30
+ * // 'py-16 px-4'
31
+ *
32
+ * substituteThemeTokens('static', theme)
33
+ * // 'static'
34
+ *
35
+ * substituteThemeTokens(123, theme)
36
+ * // 123
37
+ * ```
38
+ */
39
+ export function substituteThemeTokens(value: unknown, theme?: Theme): unknown {
40
+ if (typeof value !== 'string') {
41
+ return value
42
+ }
43
+
44
+ if (!theme || !value.includes('$theme.')) {
45
+ return value
46
+ }
47
+
48
+ // Handle multiple theme tokens in a single string
49
+ // Example: "$theme.spacing.section $theme.spacing.container" → "py-16 px-4"
50
+ // Supports color names with numbers like gray-100, primary-500, etc.
51
+ return value.replace(/\$theme\.[a-z]+(\.[a-z0-9-]+)+/g, (match) => {
52
+ // Extract the path: $theme.colors.primary → ['colors', 'primary']
53
+ const path = match.slice(7).split('.')
54
+
55
+ // Navigate through the theme object using functional reduce
56
+ const result = path.reduce<unknown>((acc, key) => {
57
+ if (acc && typeof acc === 'object' && key in acc) {
58
+ return (acc as Record<string, unknown>)[key]
59
+ }
60
+ // Return a sentinel to indicate path not found
61
+ return undefined
62
+ }, theme as unknown)
63
+
64
+ // If path navigation failed, return original token
65
+ return result !== undefined ? String(result) : match
66
+ })
67
+ }
68
+
69
+ /**
70
+ * Resolve shorthand theme token reference
71
+ *
72
+ * Handles tokens in format: $category.key (e.g., $easing.smooth, $colors.primary)
73
+ * without the `theme.` prefix.
74
+ *
75
+ * @param category - Theme category (colors, easing, spacing, etc.)
76
+ * @param tokenName - Token key within category
77
+ * @param theme - Theme configuration
78
+ * @returns Resolved token value or original token string if not found
79
+ */
80
+ function resolveShorthandToken(category: string, tokenName: string, theme?: Theme): string {
81
+ if (!theme) return `$${category}.${tokenName}`
82
+
83
+ const themeCategory = theme[category as keyof Theme]
84
+ if (!themeCategory || typeof themeCategory !== 'object') {
85
+ return `$${category}.${tokenName}`
86
+ }
87
+
88
+ // Handle nested animations category (easing, duration, keyframes)
89
+ if (category === 'easing' && theme.animations) {
90
+ const animations = theme.animations as Record<string, unknown>
91
+ const easingTokens = animations.easing as Record<string, unknown> | undefined
92
+ if (easingTokens && typeof easingTokens === 'object') {
93
+ const value = easingTokens[tokenName]
94
+ return value !== undefined ? String(value) : `$${category}.${tokenName}`
95
+ }
96
+ }
97
+
98
+ const value = (themeCategory as Record<string, unknown>)[tokenName]
99
+ return value !== undefined ? String(value) : `$${category}.${tokenName}`
100
+ }
101
+
102
+ /**
103
+ * Resolve shorthand theme tokens in string
104
+ *
105
+ * Replaces tokens in format: $category.key (e.g., $easing.smooth, $colors.primary)
106
+ * Supports multiple tokens in a single string.
107
+ *
108
+ * @param value - String that may contain shorthand theme tokens
109
+ * @param theme - Theme configuration
110
+ * @returns String with shorthand tokens replaced
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const theme = {
115
+ * colors: { primary: '#007bff' },
116
+ * animations: { easing: { smooth: 'cubic-bezier(0.4, 0, 0.2, 1)' } }
117
+ * }
118
+ * resolveShorthandThemeTokens('colorPulse 2s $easing.smooth infinite', theme)
119
+ * // 'colorPulse 2s cubic-bezier(0.4, 0, 0.2, 1) infinite'
120
+ * ```
121
+ */
122
+ function resolveShorthandThemeTokens(value: unknown, theme?: Theme): unknown {
123
+ if (typeof value !== 'string') {
124
+ return value
125
+ }
126
+
127
+ if (!theme || !value.includes('$')) {
128
+ return value
129
+ }
130
+
131
+ // Replace shorthand tokens: $category.key (without theme. prefix)
132
+ return value.replace(/\$(\w+)\.(\w+)/g, (_match, category, tokenName) =>
133
+ resolveShorthandToken(category, tokenName, theme)
134
+ )
135
+ }
136
+
137
+ /**
138
+ * Substitutes theme tokens in props recursively
139
+ *
140
+ * Walks through props object and replaces all theme token strings with actual theme values.
141
+ * Handles nested objects (e.g., style props) recursively.
142
+ * Supports both full syntax ($theme.colors.primary) and shorthand ($colors.primary, $easing.smooth).
143
+ *
144
+ * @param props - Component props that may contain theme tokens
145
+ * @param theme - Theme configuration
146
+ * @returns Props with theme tokens replaced
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const theme = { colors: { primary: '#007bff', secondary: '#6c757d' } }
151
+ * const props = {
152
+ * color: '$theme.colors.primary',
153
+ * style: { backgroundColor: '$theme.colors.secondary' }
154
+ * }
155
+ * substitutePropsThemeTokens(props, theme)
156
+ * // {
157
+ * // color: '#007bff',
158
+ * // style: { backgroundColor: '#6c757d' }
159
+ * // }
160
+ * ```
161
+ */
162
+ export function substitutePropsThemeTokens(
163
+ props: Record<string, unknown> | undefined,
164
+ theme?: Theme
165
+ ): Record<string, unknown> | undefined {
166
+ if (!props || !theme) {
167
+ return props
168
+ }
169
+
170
+ // Use functional Object.entries + reduce for immutable transformation
171
+ return Object.entries(props).reduce<Record<string, unknown>>((acc, [key, value]) => {
172
+ if (typeof value === 'string') {
173
+ // Apply both full syntax and shorthand token resolution
174
+ const fullSyntaxResolved = substituteThemeTokens(value, theme)
175
+ const shorthandResolved = resolveShorthandThemeTokens(fullSyntaxResolved, theme)
176
+ return { ...acc, [key]: shorthandResolved }
177
+ } else if (value && typeof value === 'object' && !Array.isArray(value)) {
178
+ // Recursively handle nested objects (like style props)
179
+ return { ...acc, [key]: substitutePropsThemeTokens(value as Record<string, unknown>, theme) }
180
+ } else {
181
+ return { ...acc, [key]: value }
182
+ }
183
+ }, {})
184
+ }