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,147 @@
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 { generateClickAnimationCSS } from '@/infrastructure/css/styles/click-animations'
9
+ import type { Theme } from '@/domain/models/app/theme'
10
+
11
+ /**
12
+ * Build button classes with optional primary colors
13
+ *
14
+ * @param hasPrimaryColor - Whether theme defines primary color
15
+ * @param hasPrimaryHoverColor - Whether theme defines primary hover color
16
+ * @returns Array of CSS class names for button elements
17
+ */
18
+ export function buildButtonClasses(
19
+ hasPrimaryColor: boolean,
20
+ hasPrimaryHoverColor: boolean
21
+ ): readonly string[] {
22
+ const baseClasses = [
23
+ 'inline-flex',
24
+ 'items-center',
25
+ 'justify-center',
26
+ 'rounded-md',
27
+ 'px-4',
28
+ 'py-2',
29
+ 'font-medium',
30
+ 'transition-colors',
31
+ ]
32
+
33
+ if (hasPrimaryColor && hasPrimaryHoverColor) {
34
+ return [...baseClasses, 'bg-primary', 'text-white', 'hover:bg-primary-hover']
35
+ }
36
+ if (hasPrimaryColor) {
37
+ return [...baseClasses, 'bg-primary', 'text-white']
38
+ }
39
+ return [...baseClasses, 'bg-blue-600', 'text-white', 'hover:bg-blue-700']
40
+ }
41
+
42
+ /**
43
+ * Build button primary utility classes
44
+ *
45
+ * @param hasPrimaryColor - Whether theme defines primary color
46
+ * @param hasPrimaryHoverColor - Whether theme defines primary hover color
47
+ * @returns CSS class string for primary button variant
48
+ */
49
+ export function buildButtonPrimaryClasses(
50
+ hasPrimaryColor: boolean,
51
+ hasPrimaryHoverColor: boolean
52
+ ): string {
53
+ if (hasPrimaryColor && hasPrimaryHoverColor) {
54
+ return 'bg-primary text-white hover:bg-primary-hover'
55
+ }
56
+ if (hasPrimaryColor) {
57
+ return 'bg-primary text-white'
58
+ }
59
+ return 'bg-blue-600 text-white hover:bg-blue-700'
60
+ }
61
+
62
+ /**
63
+ * Build badge border-radius based on theme configuration
64
+ * Uses theme.borderRadius.full if defined, otherwise falls back to rounded-full
65
+ *
66
+ * @param theme - Optional theme configuration
67
+ * @returns CSS rule for badge border-radius
68
+ */
69
+ export function buildBadgeBorderRadius(theme?: Theme): string {
70
+ const hasFullRadius = Boolean(theme?.borderRadius?.full)
71
+ return hasFullRadius ? 'border-radius: var(--radius-full);' : '@apply rounded-full;'
72
+ }
73
+
74
+ /**
75
+ * Generate components layer styles with theme color applications
76
+ * Applies theme colors to component classes and button elements
77
+ *
78
+ * @param theme - Optional theme configuration
79
+ * @returns CSS @layer components rule as string
80
+ *
81
+ * @example
82
+ * generateComponentsLayer(theme)
83
+ * // => '@layer components { .container-page { ... } .card { ... } ... }'
84
+ */
85
+ export function generateComponentsLayer(theme?: Theme): string {
86
+ const hasPrimaryColor = Boolean(theme?.colors?.primary)
87
+ const hasPrimaryHoverColor = Boolean(theme?.colors?.['primary-hover'])
88
+
89
+ const btnClasses = buildButtonClasses(hasPrimaryColor, hasPrimaryHoverColor)
90
+ const btnPrimaryClasses = buildButtonPrimaryClasses(hasPrimaryColor, hasPrimaryHoverColor)
91
+ const badgeBorderRadius = buildBadgeBorderRadius(theme)
92
+
93
+ return `@layer components {
94
+ .container-page {
95
+ @apply mx-auto max-w-4xl px-4 py-8;
96
+ }
97
+
98
+ .card {
99
+ @apply rounded-lg border border-gray-200 bg-white p-6 shadow-sm;
100
+ }
101
+
102
+ .badge {
103
+ @apply border border-gray-200 bg-white px-2 py-1 text-xs font-medium;
104
+ ${badgeBorderRadius}
105
+ }
106
+
107
+ .btn {
108
+ @apply ${btnClasses.join(' ')};
109
+ }
110
+
111
+ .btn-primary {
112
+ @apply ${btnPrimaryClasses};
113
+ }
114
+ }`
115
+ }
116
+
117
+ /**
118
+ * Generate utilities layer styles
119
+ * Combines static utilities with click interaction animations
120
+ *
121
+ * @returns CSS @layer utilities rule as string
122
+ *
123
+ * @example
124
+ * generateUtilitiesLayer()
125
+ * // => '@layer utilities { .text-balance { ... } ... }'
126
+ */
127
+ export function generateUtilitiesLayer(): string {
128
+ const clickAnimations = generateClickAnimationCSS()
129
+
130
+ return `@layer utilities {
131
+ .text-balance {
132
+ text-wrap: balance;
133
+ }
134
+
135
+ /* Safelist: Ensure critical utility classes are always included */
136
+ .text-center {
137
+ text-align: center;
138
+ }
139
+
140
+ /* Override Tailwind v4's multi-layer shadow system for shadow-none */
141
+ .shadow-none {
142
+ box-shadow: none !important;
143
+ }
144
+
145
+ ${clickAnimations}
146
+ }`
147
+ }
@@ -0,0 +1,130 @@
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 { BorderRadiusConfig } from '@/domain/models/app/theme/border-radius'
9
+ import type { BreakpointsConfig } from '@/domain/models/app/theme/breakpoints'
10
+ import type { ColorsConfig } from '@/domain/models/app/theme/colors'
11
+ import type { FontsConfig } from '@/domain/models/app/theme/fonts'
12
+ import type { ShadowsConfig } from '@/domain/models/app/theme/shadows'
13
+ import type { SpacingConfig } from '@/domain/models/app/theme/spacing'
14
+
15
+ /**
16
+ * Generate Tailwind @theme colors from domain color config
17
+ * Uses hex format directly - Tailwind v4 handles color format conversion
18
+ */
19
+ export function generateThemeColors(colors?: ColorsConfig): string {
20
+ if (!colors || Object.keys(colors).length === 0) return ''
21
+
22
+ const colorEntries = Object.entries(colors).map(([name, value]) => {
23
+ return ` --color-${name}: ${value};`
24
+ })
25
+
26
+ return colorEntries.join('\n')
27
+ }
28
+
29
+ /**
30
+ * Generate Tailwind @theme font families from domain font config
31
+ */
32
+ export function generateThemeFonts(fonts?: FontsConfig): string {
33
+ if (!fonts || Object.keys(fonts).length === 0) return ''
34
+
35
+ const fontEntries = Object.entries(fonts).flatMap(([category, config]) => {
36
+ // Type assertion needed because Record values are unknown in TypeScript
37
+ const fontConfig = config as {
38
+ family: string
39
+ fallback?: string
40
+ style?: string
41
+ transform?: string
42
+ letterSpacing?: string
43
+ }
44
+ const fontStack = fontConfig.fallback
45
+ ? `${fontConfig.family}, ${fontConfig.fallback}`
46
+ : fontConfig.family
47
+
48
+ const baseEntry = ` --font-${category}: ${fontStack};`
49
+
50
+ // Build entries array immutably
51
+ const styleEntry =
52
+ fontConfig.style && fontConfig.style !== 'normal'
53
+ ? ` --font-${category}-style: ${fontConfig.style};`
54
+ : undefined
55
+
56
+ const transformEntry =
57
+ fontConfig.transform && fontConfig.transform !== 'none'
58
+ ? ` --font-${category}-transform: ${fontConfig.transform};`
59
+ : undefined
60
+
61
+ const letterSpacingEntry = fontConfig.letterSpacing
62
+ ? ` --font-${category}-letter-spacing: ${fontConfig.letterSpacing};`
63
+ : undefined
64
+
65
+ return [baseEntry, styleEntry, transformEntry, letterSpacingEntry].filter(
66
+ (entry): entry is string => entry !== undefined
67
+ )
68
+ })
69
+
70
+ return fontEntries.join('\n')
71
+ }
72
+
73
+ /**
74
+ * Generate Tailwind @theme spacing from domain spacing config
75
+ * Only includes raw CSS values (rem, px, em), not Tailwind classes
76
+ */
77
+ export function generateThemeSpacing(spacing?: SpacingConfig): string {
78
+ if (!spacing || Object.keys(spacing).length === 0) return ''
79
+
80
+ const spacingEntries = Object.entries(spacing)
81
+ .filter(([_, value]) => {
82
+ // Only include raw CSS values (not Tailwind classes)
83
+ return /^[0-9.]+(?:rem|px|em|%)$/.test(value as string)
84
+ })
85
+ .map(([name, value]) => ` --spacing-${name}: ${value};`)
86
+
87
+ return spacingEntries.join('\n')
88
+ }
89
+
90
+ /**
91
+ * Generate Tailwind @theme shadows from domain shadow config
92
+ */
93
+ export function generateThemeShadows(shadows?: ShadowsConfig): string {
94
+ if (!shadows || Object.keys(shadows).length === 0) return ''
95
+
96
+ const shadowEntries = Object.entries(shadows).map(([name, value]) => {
97
+ // Preserve original shadow values as-is
98
+ // The .shadow-none utility class override handles the actual rendering
99
+ return ` --shadow-${name}: ${value};`
100
+ })
101
+
102
+ return shadowEntries.join('\n')
103
+ }
104
+
105
+ /**
106
+ * Generate Tailwind @theme border radius from domain border radius config
107
+ */
108
+ export function generateThemeBorderRadius(borderRadius?: BorderRadiusConfig): string {
109
+ if (!borderRadius || Object.keys(borderRadius).length === 0) return ''
110
+
111
+ const radiusEntries = Object.entries(borderRadius).map(([name, value]) => {
112
+ const key = name === 'DEFAULT' ? 'radius' : `radius-${name}`
113
+ return ` --${key}: ${value};`
114
+ })
115
+
116
+ return radiusEntries.join('\n')
117
+ }
118
+
119
+ /**
120
+ * Generate Tailwind @theme breakpoints from domain breakpoints config
121
+ */
122
+ export function generateThemeBreakpoints(breakpoints?: BreakpointsConfig): string {
123
+ if (!breakpoints || Object.keys(breakpoints).length === 0) return ''
124
+
125
+ const breakpointEntries = Object.entries(breakpoints).map(
126
+ ([name, value]) => ` --breakpoint-${name}: ${value};`
127
+ )
128
+
129
+ return breakpointEntries.join('\n')
130
+ }
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import type { Theme } from '@/domain/models/app/theme'
9
+
10
+ /**
11
+ * Theme color flags extracted from theme configuration
12
+ */
13
+ export interface ThemeColorFlags {
14
+ readonly hasTextColor: boolean
15
+ readonly hasPrimaryColor: boolean
16
+ readonly hasPrimaryHoverColor: boolean
17
+ }
18
+
19
+ /**
20
+ * Theme font flags extracted from theme configuration
21
+ */
22
+ export interface ThemeFontFlags {
23
+ readonly hasTitleFont: boolean
24
+ readonly hasBodyFont: boolean
25
+ }
26
+
27
+ /**
28
+ * Title font configuration type
29
+ */
30
+ export interface TitleFontConfig {
31
+ readonly style?: string
32
+ readonly transform?: string
33
+ readonly letterSpacing?: string
34
+ }
35
+
36
+ /**
37
+ * Extract color availability flags from theme
38
+ * Returns flags indicating which colors are defined in the theme
39
+ *
40
+ * @param theme - Optional theme configuration
41
+ * @returns Object with color availability flags
42
+ */
43
+ export function extractThemeColorFlags(theme?: Theme): ThemeColorFlags {
44
+ return {
45
+ hasTextColor: Boolean(theme?.colors?.text),
46
+ hasPrimaryColor: Boolean(theme?.colors?.primary),
47
+ hasPrimaryHoverColor: Boolean(theme?.colors?.['primary-hover']),
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Extract font availability flags from theme
53
+ * Returns flags indicating which fonts are defined in the theme
54
+ *
55
+ * @param theme - Optional theme configuration
56
+ * @returns Object with font availability flags
57
+ */
58
+ export function extractThemeFontFlags(theme?: Theme): ThemeFontFlags {
59
+ return {
60
+ hasTitleFont: Boolean(theme?.fonts?.title),
61
+ hasBodyFont: Boolean(theme?.fonts?.body),
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Extract title font properties from theme fonts config
67
+ * Returns undefined if no title font is configured
68
+ *
69
+ * @param theme - Optional theme configuration
70
+ * @returns Title font configuration or undefined
71
+ */
72
+ export function extractTitleFontProperties(theme?: Theme): TitleFontConfig | undefined {
73
+ if (!theme?.fonts?.title || typeof theme.fonts.title !== 'object') {
74
+ return undefined
75
+ }
76
+
77
+ return theme.fonts.title as TitleFontConfig
78
+ }
79
+
80
+ /**
81
+ * Build body classes with optional text color and font
82
+ *
83
+ * @param hasTextColor - Whether theme defines text color
84
+ * @param hasBodyFont - Whether theme defines body font
85
+ * @returns Array of CSS class names for body element
86
+ */
87
+ export function buildBodyClasses(hasTextColor: boolean, hasBodyFont: boolean): readonly string[] {
88
+ const fontClass = hasBodyFont ? 'font-body' : 'font-sans'
89
+ return hasTextColor ? [fontClass, 'antialiased', 'text-text'] : [fontClass, 'antialiased']
90
+ }
91
+
92
+ /**
93
+ * Build heading classes with optional text color and font
94
+ *
95
+ * @param hasTextColor - Whether theme defines text color
96
+ * @param hasTitleFont - Whether theme defines title font
97
+ * @returns Array of CSS class names for heading elements
98
+ */
99
+ export function buildHeadingClasses(
100
+ hasTextColor: boolean,
101
+ hasTitleFont: boolean
102
+ ): readonly string[] {
103
+ const fontClass = hasTitleFont ? 'font-title' : 'font-sans'
104
+ const baseClasses = hasTextColor
105
+ ? [fontClass, 'font-semibold', 'tracking-tight', 'text-text']
106
+ : [fontClass, 'font-semibold', 'tracking-tight']
107
+ return baseClasses
108
+ }
109
+
110
+ /**
111
+ * Build link classes with optional primary colors
112
+ *
113
+ * @param hasPrimaryColor - Whether theme defines primary color
114
+ * @param hasPrimaryHoverColor - Whether theme defines primary hover color
115
+ * @returns Array of CSS class names for link elements
116
+ */
117
+ export function buildLinkClasses(
118
+ hasPrimaryColor: boolean,
119
+ hasPrimaryHoverColor: boolean
120
+ ): readonly string[] {
121
+ if (hasPrimaryColor && hasPrimaryHoverColor) {
122
+ return ['transition-colors', 'text-primary', 'hover:text-primary-hover']
123
+ }
124
+ if (hasPrimaryColor) {
125
+ return ['transition-colors', 'text-primary']
126
+ }
127
+ return ['transition-colors', 'text-blue-600', 'hover:text-blue-700']
128
+ }
129
+
130
+ /**
131
+ * Build CSS property strings for heading styles
132
+ * Returns array of CSS properties based on title font configuration
133
+ *
134
+ * @param titleFont - Optional title font configuration
135
+ * @returns Array of CSS property strings
136
+ */
137
+ export function buildHeadingStyleProperties(titleFont?: TitleFontConfig): readonly string[] {
138
+ if (!titleFont) return []
139
+
140
+ const styleProperty =
141
+ titleFont.style && titleFont.style !== 'normal'
142
+ ? `font-style: var(--font-title-style);`
143
+ : undefined
144
+
145
+ const transformProperty =
146
+ titleFont.transform && titleFont.transform !== 'none'
147
+ ? `text-transform: var(--font-title-transform);`
148
+ : undefined
149
+
150
+ const letterSpacingProperty = titleFont.letterSpacing
151
+ ? `letter-spacing: var(--font-title-letter-spacing);`
152
+ : undefined
153
+
154
+ return [styleProperty, transformProperty, letterSpacingProperty].filter(
155
+ (prop): prop is string => prop !== undefined
156
+ )
157
+ }
158
+
159
+ /**
160
+ * Generate heading CSS with base classes and optional style properties
161
+ * Combines heading classes with additional CSS properties
162
+ *
163
+ * @param headingClasses - Array of CSS class names
164
+ * @param styleProps - Array of CSS property strings
165
+ * @returns Complete CSS rule for headings
166
+ */
167
+ export function generateHeadingStyles(
168
+ headingClasses: readonly string[],
169
+ styleProps: readonly string[]
170
+ ): string {
171
+ const baseStyles = `@apply ${headingClasses.join(' ')};`
172
+ if (styleProps.length === 0) return baseStyles
173
+
174
+ return `${baseStyles}
175
+ ${styleProps.join('\n ')}`
176
+ }
177
+
178
+ /**
179
+ * Generate base layer styles with theme color and font applications
180
+ * Applies theme colors and fonts to base HTML elements if theme defines those tokens
181
+ *
182
+ * @param theme - Optional theme configuration
183
+ * @returns CSS @layer base rule as string
184
+ *
185
+ * @example
186
+ * generateBaseLayer(theme)
187
+ * // => '@layer base { body { ... } h1, h2, ... { ... } a { ... } }'
188
+ */
189
+ export function generateBaseLayer(theme?: Theme): string {
190
+ const colorFlags = extractThemeColorFlags(theme)
191
+ const fontFlags = extractThemeFontFlags(theme)
192
+
193
+ const bodyClasses = buildBodyClasses(colorFlags.hasTextColor, fontFlags.hasBodyFont)
194
+ const headingClasses = buildHeadingClasses(colorFlags.hasTextColor, fontFlags.hasTitleFont)
195
+ const linkClasses = buildLinkClasses(colorFlags.hasPrimaryColor, colorFlags.hasPrimaryHoverColor)
196
+
197
+ const titleFont = extractTitleFontProperties(theme)
198
+ const headingStyleProps = buildHeadingStyleProperties(titleFont)
199
+ const headingStyles = generateHeadingStyles(headingClasses, headingStyleProps)
200
+
201
+ return `@layer base {
202
+ body {
203
+ @apply ${bodyClasses.join(' ')};
204
+ }
205
+
206
+ h1,
207
+ h2,
208
+ h3,
209
+ h4,
210
+ h5,
211
+ h6 {
212
+ ${headingStyles}
213
+ }
214
+
215
+ a {
216
+ @apply ${linkClasses.join(' ')};
217
+ }
218
+ }`
219
+ }
@@ -0,0 +1,76 @@
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
+ * Resolve color token reference
12
+ *
13
+ * @param tokenName - Name of the color token (e.g., 'primary', 'text')
14
+ * @param theme - Optional theme configuration
15
+ * @returns Resolved color value or undefined if token not found
16
+ *
17
+ * @example
18
+ * resolveColorToken('primary', theme) // => '#ff5733'
19
+ * resolveColorToken('unknown', theme) // => undefined
20
+ */
21
+ export function resolveColorToken(tokenName: string, theme?: Theme): string | undefined {
22
+ if (!theme?.colors || !(tokenName in theme.colors)) return undefined
23
+ const colorValue = theme.colors[tokenName]
24
+ return colorValue ? String(colorValue) : undefined
25
+ }
26
+
27
+ /**
28
+ * Resolve easing token reference
29
+ *
30
+ * @param tokenName - Name of the easing token (e.g., 'smooth', 'bounce')
31
+ * @param theme - Optional theme configuration
32
+ * @returns Resolved easing value or undefined if token not found
33
+ *
34
+ * @example
35
+ * resolveEasingToken('smooth', theme) // => 'cubic-bezier(0.4, 0, 0.2, 1)'
36
+ * resolveEasingToken('unknown', theme) // => undefined
37
+ */
38
+ export function resolveEasingToken(tokenName: string, theme?: Theme): string | undefined {
39
+ if (!theme?.animations) return undefined
40
+ const animations = theme.animations as Record<string, unknown>
41
+ const easingTokens = animations.easing as Record<string, unknown> | undefined
42
+ if (!easingTokens || typeof easingTokens !== 'object' || !(tokenName in easingTokens))
43
+ return undefined
44
+ const easingValue = easingTokens[tokenName]
45
+ return easingValue ? String(easingValue) : undefined
46
+ }
47
+
48
+ /**
49
+ * Resolve token references in a value
50
+ * Supports: $colors.primary, $easing.smooth, etc.
51
+ *
52
+ * @param value - Value to resolve (can be string with token reference or any other type)
53
+ * @param theme - Optional theme configuration
54
+ * @returns Resolved value as string
55
+ *
56
+ * @example
57
+ * resolveTokenReference('$colors.primary', theme) // => '#ff5733'
58
+ * resolveTokenReference('$easing.smooth', theme) // => 'cubic-bezier(0.4, 0, 0.2, 1)'
59
+ * resolveTokenReference('plain-value', theme) // => 'plain-value'
60
+ * resolveTokenReference(42, theme) // => '42'
61
+ */
62
+ export function resolveTokenReference(value: unknown, theme?: Theme): string {
63
+ if (typeof value !== 'string') return String(value)
64
+
65
+ const tokenMatch = value.match(/^\$(\w+)\.(\w+)$/)
66
+ if (!tokenMatch) return value
67
+
68
+ const [, category, tokenName] = tokenMatch
69
+ if (!category || !tokenName) return value
70
+
71
+ return (
72
+ (category === 'colors' ? resolveColorToken(tokenName, theme) : undefined) ??
73
+ (category === 'easing' ? resolveEasingToken(tokenName, theme) : undefined) ??
74
+ value
75
+ )
76
+ }
@@ -0,0 +1,111 @@
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 { eq } from 'drizzle-orm'
9
+ import { Effect } from 'effect'
10
+ import { Database, activityLogs, users } from '@/infrastructure/database'
11
+
12
+ /**
13
+ * Activity log with user metadata
14
+ */
15
+ export interface ActivityLogWithUser {
16
+ readonly id: string
17
+ readonly userId: string
18
+ readonly action: string
19
+ readonly tableName: string
20
+ readonly recordId: number
21
+ readonly changes: Record<string, unknown> | null
22
+ readonly createdAt: Date
23
+ readonly user: {
24
+ readonly id: string
25
+ readonly name: string
26
+ readonly email: string
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Database error for activity queries
32
+ */
33
+ export class ActivityDatabaseError {
34
+ readonly _tag = 'ActivityDatabaseError'
35
+ constructor(readonly cause: unknown) {}
36
+ }
37
+
38
+ /**
39
+ * Activity not found error
40
+ */
41
+ export class ActivityNotFoundError {
42
+ readonly _tag = 'ActivityNotFoundError'
43
+ constructor(readonly activityId: string) {}
44
+ }
45
+
46
+ /**
47
+ * Get activity log by ID with user metadata
48
+ *
49
+ * Fetches activity log details with a JOIN to the users table to include
50
+ * user information (name, email).
51
+ *
52
+ * @param activityId - Activity log ID (UUID string or numeric string)
53
+ * @returns Effect program that resolves to activity with user metadata or fails with error
54
+ */
55
+ export const getActivityById = (activityId: string) =>
56
+ Effect.gen(function* () {
57
+ const db = yield* Database
58
+
59
+ const result = yield* Effect.tryPromise({
60
+ try: () =>
61
+ db
62
+ .select({
63
+ id: activityLogs.id,
64
+ userId: activityLogs.userId,
65
+ action: activityLogs.action,
66
+ tableName: activityLogs.tableName,
67
+ recordId: activityLogs.recordId,
68
+ changes: activityLogs.changes,
69
+ createdAt: activityLogs.createdAt,
70
+ userName: users.name,
71
+ userEmail: users.email,
72
+ userIdJoined: users.id,
73
+ })
74
+ .from(activityLogs)
75
+ .leftJoin(users, eq(activityLogs.userId, users.id))
76
+ .where(eq(activityLogs.id, activityId))
77
+ .limit(1),
78
+ catch: (error) => new ActivityDatabaseError(error),
79
+ })
80
+
81
+ if (result.length === 0 || !result[0]) {
82
+ return yield* Effect.fail(new ActivityNotFoundError(activityId))
83
+ }
84
+
85
+ const row = result[0]
86
+
87
+ // Parse recordId as integer (stored as text in DB)
88
+ const recordIdInt = parseInt(row.recordId, 10)
89
+ const recordId = isNaN(recordIdInt) ? 0 : recordIdInt
90
+
91
+ // Changes is already JSONB (parsed by Drizzle), cast to expected type
92
+ // eslint-disable-next-line unicorn/no-null -- Null is intentional for JSONB columns with no data
93
+ const changes = (row.changes as Record<string, unknown> | null) ?? null
94
+
95
+ const activity: ActivityLogWithUser = {
96
+ id: row.id,
97
+ userId: row.userId ?? '',
98
+ action: row.action,
99
+ tableName: row.tableName,
100
+ recordId,
101
+ changes,
102
+ createdAt: row.createdAt,
103
+ user: {
104
+ id: row.userIdJoined ?? '',
105
+ name: row.userName ?? '',
106
+ email: row.userEmail ?? '',
107
+ },
108
+ }
109
+
110
+ return activity
111
+ })