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,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 type { Languages } from '@/domain/models/app/languages'
9
+
10
+ /**
11
+ * Normalize language code to match translation keys
12
+ *
13
+ * Tries exact match first, then falls back to base language code (e.g., 'fr-FR' → 'fr')
14
+ *
15
+ * @param lang - Language code (e.g., 'fr-FR', 'en-US', 'fr')
16
+ * @param translations - Available translations object
17
+ * @returns Matching translation key or original language code
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * normalizeLanguageCode('fr-FR', { fr: {...}, en: {...} }) // 'fr'
22
+ * normalizeLanguageCode('fr', { fr: {...}, en: {...} }) // 'fr'
23
+ * normalizeLanguageCode('en-US', { 'en-US': {...} }) // 'en-US'
24
+ * ```
25
+ */
26
+ export function normalizeLanguageCode(
27
+ lang: string,
28
+ translations: Record<string, Record<string, string>>
29
+ ): string {
30
+ // Try exact match first
31
+ if (translations[lang]) {
32
+ return lang
33
+ }
34
+
35
+ // Try base language code (e.g., 'fr-FR' → 'fr')
36
+ const baseLang = lang.split('-')[0]
37
+ if (baseLang && translations[baseLang]) {
38
+ return baseLang
39
+ }
40
+
41
+ // No match found - return original
42
+ return lang
43
+ }
44
+
45
+ /**
46
+ * Resolve translation key with fallback support
47
+ *
48
+ * Implements the $t:key pattern for centralized translations.
49
+ * When a translation is missing in the current language, falls back to the fallback language.
50
+ *
51
+ * @param key - Translation key (e.g., 'welcome', 'common.save')
52
+ * @param currentLang - Current language code (e.g., 'fr-FR')
53
+ * @param languages - Languages configuration from app schema
54
+ * @returns Translated string or key if not found
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const text = resolveTranslation('welcome', 'fr-FR', languages)
59
+ * // Returns: 'Bienvenue' if exists in fr-FR
60
+ * // Returns: 'Welcome' if missing in fr-FR but exists in fallback en-US
61
+ * // Returns: 'welcome' if not found in any language
62
+ * ```
63
+ */
64
+ export function resolveTranslation(
65
+ key: string,
66
+ currentLang: string,
67
+ languages?: Languages
68
+ ): string {
69
+ // No translations configured - return key as-is
70
+ if (!languages?.translations) {
71
+ return key
72
+ }
73
+
74
+ const { translations, fallback } = languages
75
+
76
+ // Normalize language code to match translation keys (e.g., 'fr-FR' → 'fr')
77
+ const normalizedLang = normalizeLanguageCode(currentLang, translations)
78
+
79
+ // Try current language first
80
+ const currentTranslations = translations[normalizedLang]
81
+ if (currentTranslations?.[key]) {
82
+ return currentTranslations[key]
83
+ }
84
+
85
+ // Try fallback language (defaults to default language)
86
+ const fallbackLang = fallback || languages.default
87
+ if (fallbackLang !== normalizedLang) {
88
+ const normalizedFallback = normalizeLanguageCode(fallbackLang, translations)
89
+ const fallbackTranslations = translations[normalizedFallback]
90
+ if (fallbackTranslations?.[key]) {
91
+ return fallbackTranslations[key]
92
+ }
93
+ }
94
+
95
+ // Translation not found - return key
96
+ return key
97
+ }
98
+
99
+ /**
100
+ * Resolve $t:key pattern in a string
101
+ *
102
+ * Processes strings containing $t:key syntax and replaces them with translations.
103
+ * Supports fallback when translation is missing.
104
+ *
105
+ * @param text - String that may contain $t:key patterns
106
+ * @param currentLang - Current language code
107
+ * @param languages - Languages configuration from app schema
108
+ * @returns String with resolved translations
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * resolveTranslationPattern('$t:welcome', 'fr-FR', languages) // 'Bienvenue'
113
+ * resolveTranslationPattern('$t:goodbye', 'fr-FR', languages) // 'Goodbye' (fallback)
114
+ * resolveTranslationPattern('Hello world', 'fr-FR', languages) // 'Hello world' (no pattern)
115
+ * ```
116
+ */
117
+ export function resolveTranslationPattern(
118
+ text: string,
119
+ currentLang: string,
120
+ languages?: Languages
121
+ ): string {
122
+ // Check if text starts with $t: pattern
123
+ if (text.startsWith('$t:')) {
124
+ const key = text.slice(3) // Remove '$t:' prefix
125
+ return resolveTranslation(key, currentLang, languages)
126
+ }
127
+
128
+ // No pattern found - return text as-is
129
+ return text
130
+ }
131
+
132
+ /**
133
+ * Collect all available translations for a key across all languages
134
+ *
135
+ * Used for pre-resolving translations on the server side, allowing client-side
136
+ * code to simply lookup translations without re-implementing fallback logic.
137
+ *
138
+ * @param key - Translation key (e.g., 'welcome', 'common.save')
139
+ * @param languages - Languages configuration from app schema
140
+ * @returns Object mapping language codes to translated strings, or undefined if no translations
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * collectTranslationsForKey('welcome', languages)
145
+ * // Returns: { 'en-US': 'Welcome', 'fr-FR': 'Bienvenue', 'es-ES': 'Bienvenido' }
146
+ * ```
147
+ */
148
+ export function collectTranslationsForKey(
149
+ key: string,
150
+ languages?: Languages
151
+ ): Record<string, string> | undefined {
152
+ if (!languages?.translations) {
153
+ return undefined
154
+ }
155
+
156
+ // Collect translation for this key from all available languages (functional approach)
157
+ const result = Object.entries(languages.translations).reduce(
158
+ (acc, [lang, translations]) => {
159
+ const translationDict = translations as Record<string, string>
160
+ if (translationDict[key]) {
161
+ return { ...acc, [lang]: translationDict[key] }
162
+ }
163
+ return acc
164
+ },
165
+ {} as Record<string, string>
166
+ )
167
+
168
+ // Return undefined if no translations found (key doesn't exist in any language)
169
+ return Object.keys(result).length > 0 ? result : undefined
170
+ }
package/src/index.ts ADDED
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ /**
9
+ * Sovrium - A Bun web framework with React SSR and Tailwind CSS
10
+ *
11
+ * This is the main entry point for Sovrium applications. It provides a simple
12
+ * Promise-based API for starting a web server with automatic:
13
+ * - React 19 server-side rendering
14
+ * - Tailwind CSS compilation (no build step)
15
+ * - Type-safe configuration validation
16
+ * - Graceful shutdown handling
17
+ */
18
+
19
+ import { Console, Effect, Schema } from 'effect'
20
+ import { generateStatic as generateStaticUseCase } from '@/application/use-cases/server/generate-static'
21
+ import { startServer } from '@/application/use-cases/server/start-server'
22
+ import { AppSchema } from '@/domain/models/app'
23
+ import { createAppLayer } from '@/infrastructure/layers/app-layer'
24
+ import { withGracefulShutdown } from '@/infrastructure/server/lifecycle'
25
+ import type { ServerInstance } from '@/application/models/server'
26
+ import type {
27
+ GenerateStaticOptions,
28
+ GenerateStaticResult,
29
+ } from '@/application/use-cases/server/generate-static'
30
+ import type { StartOptions } from '@/application/use-cases/server/start-server'
31
+ import type { App, AppEncoded } from '@/domain/models/app'
32
+
33
+ /**
34
+ * Simple server interface with Promise-based methods
35
+ */
36
+ export interface SimpleServer {
37
+ /**
38
+ * Server URL (e.g., "http://localhost:3000")
39
+ */
40
+ readonly url: string
41
+
42
+ /**
43
+ * Stop the server gracefully
44
+ * @returns Promise that resolves when server is stopped
45
+ */
46
+ stop: () => Promise<void>
47
+ }
48
+
49
+ /**
50
+ * Convert Effect-based ServerInstance to simple Promise-based interface
51
+ */
52
+ const toSimpleServer = (server: Readonly<ServerInstance>): SimpleServer => ({
53
+ url: server.url,
54
+ stop: () => Effect.runPromise(server.stop),
55
+ })
56
+
57
+ /**
58
+ * Start an Sovrium server with automatic logging and graceful shutdown
59
+ *
60
+ * This is the main entry point for Sovrium applications. It:
61
+ * 1. Validates the app configuration using Effect Schema
62
+ * 2. Compiles Tailwind CSS dynamically using PostCSS
63
+ * 3. Creates a Hono web server with React SSR
64
+ * 4. Serves the homepage at "/" and compiled CSS at "/assets/output.css"
65
+ * 5. Sets up graceful shutdown handlers (SIGINT, SIGTERM)
66
+ * 6. Returns a simple server interface with url and stop method
67
+ *
68
+ * @param app - Application configuration with name and description
69
+ * @param options - Optional server configuration (port, hostname)
70
+ * @returns Promise that resolves to a simple server interface
71
+ *
72
+ * @example
73
+ * Basic usage:
74
+ * ```typescript
75
+ * import { start } from 'sovrium'
76
+ *
77
+ * const myApp = {
78
+ * name: 'My App',
79
+ * description: 'A simple Bun application'
80
+ * }
81
+ *
82
+ * // Start with default port (3000) and hostname ('localhost')
83
+ * const server = await start(myApp)
84
+ * console.log(`Server running at ${server.url}`)
85
+ * // Server stays alive until Ctrl+C
86
+ * ```
87
+ *
88
+ * @example
89
+ * With custom configuration:
90
+ * ```typescript
91
+ * const server = await start(myApp, {
92
+ * port: 8080,
93
+ * hostname: '0.0.0.0'
94
+ * })
95
+ * ```
96
+ *
97
+ * @example
98
+ * With error handling:
99
+ * ```typescript
100
+ * start(myApp).catch((error) => {
101
+ * console.error('Failed to start server:', error)
102
+ * process.exit(1)
103
+ * })
104
+ * ```
105
+ */
106
+ export const start = async (app: AppEncoded, options: StartOptions = {}): Promise<SimpleServer> => {
107
+ // Parse app configuration once to extract auth config
108
+ const validatedApp: App = Schema.decodeUnknownSync(AppSchema)(app)
109
+
110
+ const program = Effect.gen(function* () {
111
+ yield* Console.log('Starting Sovrium server...')
112
+
113
+ // Start the server (dependencies injected via AppLayer with auth config)
114
+ const server = yield* startServer(app, options)
115
+
116
+ // Setup graceful shutdown in background (forked so it doesn't block)
117
+ yield* Effect.fork(withGracefulShutdown(server))
118
+
119
+ // Return the server instance immediately (don't wait for shutdown)
120
+ return server
121
+ }).pipe(
122
+ // Provide dependencies (ServerFactory + PageRenderer + Auth with app-specific config)
123
+ Effect.provide(createAppLayer(validatedApp.auth))
124
+ )
125
+
126
+ // Run the Effect program and convert to simple server interface
127
+ const server = await Effect.runPromise(program)
128
+ return toSimpleServer(server)
129
+ }
130
+
131
+ /**
132
+ * Build static site files from a Sovrium application
133
+ *
134
+ * This function generates static HTML files and supporting assets that can be
135
+ * deployed to any static hosting provider (GitHub Pages, Netlify, Vercel, etc.).
136
+ *
137
+ * @param app - Application configuration with pages, theme, etc.
138
+ * @param options - Optional static generation configuration
139
+ * @returns Promise that resolves to generation result with output directory and file list
140
+ *
141
+ * @example
142
+ * Basic usage:
143
+ * ```typescript
144
+ * import { build } from 'sovrium'
145
+ *
146
+ * const myApp = {
147
+ * name: 'My App',
148
+ * pages: [
149
+ * {
150
+ * name: 'home',
151
+ * path: '/',
152
+ * meta: { title: 'Home' },
153
+ * sections: []
154
+ * }
155
+ * ]
156
+ * }
157
+ *
158
+ * const result = await build(myApp)
159
+ * console.log(`Generated ${result.files.length} files to ${result.outputDir}`)
160
+ * ```
161
+ *
162
+ * @example
163
+ * With options:
164
+ * ```typescript
165
+ * const result = await build(myApp, {
166
+ * outputDir: './dist',
167
+ * baseUrl: 'https://example.com',
168
+ * generateSitemap: true,
169
+ * generateRobotsTxt: true,
170
+ * deployment: 'github-pages'
171
+ * })
172
+ * ```
173
+ */
174
+ export const build = async (
175
+ app: AppEncoded,
176
+ options: GenerateStaticOptions = {}
177
+ ): Promise<GenerateStaticResult> => {
178
+ // Parse app configuration once to extract auth config
179
+ const validatedApp: App = Schema.decodeUnknownSync(AppSchema)(app)
180
+
181
+ const program = Effect.gen(function* () {
182
+ yield* Console.log('Generating static site...')
183
+
184
+ // Generate static site (dependencies injected via AppLayer)
185
+ const result = yield* generateStaticUseCase(app, options)
186
+
187
+ yield* Console.log(`✅ Static site generated to ${result.outputDir}`)
188
+ yield* Console.log(` Generated ${result.files.length} files`)
189
+
190
+ return result
191
+ }).pipe(
192
+ // Provide dependencies (ServerFactory + PageRenderer + Auth with app-specific config)
193
+ Effect.provide(createAppLayer(validatedApp.auth))
194
+ )
195
+
196
+ // Run the Effect program and return the result
197
+ return await Effect.runPromise(program)
198
+ }
199
+
200
+ /**
201
+ * Re-export types for convenience
202
+ */
203
+ export type { StartOptions, GenerateStaticOptions, GenerateStaticResult }
204
+ export type { App, AppEncoded } from '@/domain/models/app'
205
+ export { AppSchema } from '@/domain/models/app'
206
+ export type { Page, PageEncoded } from '@/domain/models/app/pages'
207
+ export { PageSchema } from '@/domain/models/app/pages'
208
+ export type { ComponentTemplate } from '@/domain/models/app/component/component'
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ /**
9
+ * Minimal first-party analytics tracking script (~1KB minified)
10
+ *
11
+ * Features:
12
+ * - Sends page path, title, referrer, screen size via navigator.sendBeacon
13
+ * - Extracts UTM params from URL on load
14
+ * - Listens for history.pushState / popstate for SPA navigation
15
+ * - Respects navigator.doNotTrack if configured
16
+ * - No cookies, no external dependencies
17
+ *
18
+ * Template variables replaced at serve time:
19
+ * - __ENDPOINT__ — collection API URL (e.g., /api/analytics/collect)
20
+ * - __APP_NAME__ — application name for multi-tenant support
21
+ * - __RESPECT_DNT__ — whether to respect Do Not Track header ("true" or "false")
22
+ */
23
+ export function generateTrackingScript(
24
+ endpoint: string,
25
+ appName: string,
26
+ respectDoNotTrack: boolean
27
+ ): string {
28
+ return `(function(){
29
+ "use strict";
30
+ var E="${endpoint}",A="${appName}",D=${respectDoNotTrack ? 'true' : 'false'};
31
+ if(D&&navigator.doNotTrack==="1")return;
32
+ var u=function(){
33
+ try{var s=new URLSearchParams(location.search);
34
+ var d={p:location.pathname,t:document.title,r:document.referrer||void 0,
35
+ sw:screen.width,sh:screen.height,
36
+ us:s.get("utm_source")||void 0,um:s.get("utm_medium")||void 0,
37
+ uc:s.get("utm_campaign")||void 0,ux:s.get("utm_content")||void 0,
38
+ ut:s.get("utm_term")||void 0};
39
+ var b=JSON.stringify(d);
40
+ if(navigator.sendBeacon){navigator.sendBeacon(E,new Blob([b],{type:"application/json"}))}
41
+ else{var x=new XMLHttpRequest();x.open("POST",E,true);x.setRequestHeader("Content-Type","application/json");x.send(b)}
42
+ }catch(e){}};
43
+ u();
44
+ var op=history.pushState;
45
+ history.pushState=function(){op.apply(this,arguments);u()};
46
+ window.addEventListener("popstate",u);
47
+ })();`
48
+ }
@@ -0,0 +1,216 @@
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 { betterAuth } from 'better-auth'
9
+ import { drizzleAdapter } from 'better-auth/adapters/drizzle'
10
+ import { createAuthMiddleware, APIError } from 'better-auth/api'
11
+ import { openAPI } from 'better-auth/plugins'
12
+ import { getStrategy, hasStrategy } from '@/domain/models/app/auth'
13
+ import { db } from '@/infrastructure/database'
14
+ import { createEmailHandlers } from './email-handlers'
15
+ import { buildAdminPlugin } from './plugins/admin'
16
+ import { buildMagicLinkPlugin } from './plugins/magic-link'
17
+ import { buildTwoFactorPlugin } from './plugins/two-factor'
18
+ import { users, sessions, accounts, verifications, twoFactors } from './schema'
19
+ import type { Auth } from '@/domain/models/app/auth'
20
+
21
+ /**
22
+ * Build socialProviders configuration from auth config
23
+ *
24
+ * Maps enabled OAuth providers to Better Auth socialProviders configuration.
25
+ * Credentials are loaded from environment variables using the pattern:
26
+ * - {PROVIDER}_CLIENT_ID (e.g., GOOGLE_CLIENT_ID)
27
+ * - {PROVIDER}_CLIENT_SECRET (e.g., GOOGLE_CLIENT_SECRET)
28
+ */
29
+ export const buildSocialProviders = (authConfig?: Auth) => {
30
+ const oauthStrategy = getStrategy(authConfig, 'oauth')
31
+ if (!oauthStrategy?.providers) return {}
32
+
33
+ return oauthStrategy.providers.reduce(
34
+ (providers, provider) => {
35
+ const envVarPrefix = provider.toUpperCase()
36
+ return {
37
+ ...providers,
38
+ [provider]: {
39
+ clientId: process.env[`${envVarPrefix}_CLIENT_ID`] || '',
40
+ clientSecret: process.env[`${envVarPrefix}_CLIENT_SECRET`] || '',
41
+ },
42
+ }
43
+ },
44
+ {} as Record<string, { clientId: string; clientSecret: string }>
45
+ )
46
+ }
47
+
48
+ /**
49
+ * Schema mapping for Better Auth's drizzle adapter
50
+ *
51
+ * IMPORTANT: The keys MUST be Better Auth's internal model names (user, account, session, etc.)
52
+ * NOT the custom table names. The actual database table name is determined by the Drizzle
53
+ * table definition (e.g., pgTable('_sovrium_auth_users', ...)).
54
+ *
55
+ * This is a critical fix for GitHub issue #5879 - using table names as keys causes
56
+ * the adapter to return wrong records, breaking account linking.
57
+ *
58
+ * See: https://github.com/better-auth/better-auth/issues/5879
59
+ */
60
+ const drizzleSchema = {
61
+ user: users,
62
+ session: sessions,
63
+ account: accounts,
64
+ verification: verifications,
65
+ twoFactor: twoFactors,
66
+ }
67
+
68
+ /**
69
+ * Build Better Auth plugins array with custom table names
70
+ *
71
+ * Conditionally includes plugins when enabled in auth configuration.
72
+ * If a plugin is not enabled, its endpoints will not be available (404).
73
+ */
74
+ export const buildAuthPlugins = (
75
+ handlers: Readonly<ReturnType<typeof createEmailHandlers>>,
76
+ authConfig?: Auth
77
+ ) => [
78
+ openAPI({ disableDefaultReference: true }),
79
+ ...buildAdminPlugin(authConfig),
80
+ ...buildTwoFactorPlugin(authConfig),
81
+ ...buildMagicLinkPlugin(handlers.magicLink, authConfig),
82
+ ]
83
+
84
+ /**
85
+ * Build rate limiting configuration for Better Auth
86
+ *
87
+ * NOTE: Better Auth's native rate limiting has known issues with customRules not working reliably
88
+ * (see GitHub issues #392, #1891, #2153). As a workaround, Sovrium uses custom Hono middleware
89
+ * in auth-routes.ts to implement endpoint-specific rate limiting for sign-in, sign-up, and
90
+ * password-reset endpoints.
91
+ *
92
+ * This configuration keeps Better Auth's rate limiting disabled to avoid conflicts with the
93
+ * custom middleware implementation.
94
+ */
95
+ export function buildRateLimitConfig() {
96
+ return {
97
+ enabled: false, // Disabled in favor of custom Hono middleware
98
+ window: 60,
99
+ max: 100,
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Build email and password configuration from auth config
105
+ */
106
+ export function buildEmailAndPasswordConfig(
107
+ authConfig: Auth | undefined,
108
+ handlers: Readonly<ReturnType<typeof createEmailHandlers>>
109
+ ) {
110
+ const strategy = getStrategy(authConfig, 'emailAndPassword')
111
+ const requireEmailVerification = strategy?.requireEmailVerification ?? false
112
+
113
+ return {
114
+ enabled: hasStrategy(authConfig, 'emailAndPassword'),
115
+ requireEmailVerification,
116
+ sendResetPassword: handlers.passwordReset,
117
+ minPasswordLength: strategy?.minPasswordLength ?? 8,
118
+ maxPasswordLength: strategy?.maxPasswordLength ?? 128,
119
+ }
120
+ }
121
+
122
+ type AuthMiddlewareCtx = Parameters<typeof createAuthMiddleware>[0] extends (
123
+ ctx: infer C
124
+ ) => unknown
125
+ ? C
126
+ : never
127
+
128
+ /**
129
+ * Validate admin create-user password length (Better Auth Issue #4651 workaround).
130
+ * The admin plugin doesn't respect emailAndPassword validation settings.
131
+ */
132
+ // eslint-disable-next-line functional/prefer-immutable-types
133
+ async function validateAdminCreateUserPassword(ctx: AuthMiddlewareCtx) {
134
+ const body = ctx.body as { password?: string }
135
+ if (!body?.password) return
136
+ const minLength = 8
137
+ const maxLength = 128
138
+ if (body.password.length < minLength) {
139
+ // eslint-disable-next-line functional/no-throw-statements
140
+ throw new APIError('BAD_REQUEST', {
141
+ message: `Password must be at least ${minLength} characters`,
142
+ })
143
+ }
144
+ if (body.password.length > maxLength) {
145
+ // eslint-disable-next-line functional/no-throw-statements
146
+ throw new APIError('BAD_REQUEST', {
147
+ message: `Password must not exceed ${maxLength} characters`,
148
+ })
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Build auth hooks with request validation middleware
154
+ *
155
+ * Validates password length for admin createUser endpoint (Better Auth Issue #4651 workaround).
156
+ * The admin plugin doesn't respect emailAndPassword validation settings.
157
+ *
158
+ * Note: The /change-email endpoint uses Better Auth 1.5's native email enumeration protection,
159
+ * which always returns 200 OK regardless of whether the target email exists.
160
+ */
161
+ export function buildAuthHooks() {
162
+ return {
163
+ before: createAuthMiddleware(async (ctx) => {
164
+ if (ctx.path === '/admin/create-user') {
165
+ // eslint-disable-next-line functional/no-expression-statements
166
+ await validateAdminCreateUserPassword(ctx)
167
+ }
168
+ }),
169
+ }
170
+ }
171
+ /**
172
+ * Create Better Auth instance with dynamic configuration
173
+ */
174
+ export function createAuthInstance(authConfig?: Auth) {
175
+ const handlers = createEmailHandlers(authConfig)
176
+ const emailAndPasswordConfig = buildEmailAndPasswordConfig(authConfig, handlers)
177
+ const { requireEmailVerification } = emailAndPasswordConfig
178
+
179
+ return betterAuth({
180
+ secret: process.env.AUTH_SECRET,
181
+ baseURL: process.env.BASE_URL || `http://localhost:${process.env.PORT || 3000}`,
182
+ database: drizzleAdapter(db, {
183
+ provider: 'pg',
184
+ usePlural: false,
185
+ schema: drizzleSchema,
186
+ }),
187
+ // NOTE: modelName options removed - drizzleSchema uses standard model names
188
+ // and Drizzle pgTable() definitions specify actual database table names
189
+ trustedOrigins: ['*'],
190
+ advanced: {
191
+ useSecureCookies: process.env.NODE_ENV === 'production',
192
+ disableCSRFCheck: process.env.NODE_ENV !== 'production',
193
+ },
194
+ emailAndPassword: emailAndPasswordConfig,
195
+ emailVerification: {
196
+ sendOnSignUp: requireEmailVerification,
197
+ autoSignInAfterVerification: true,
198
+ sendVerificationEmail: handlers.verification,
199
+ },
200
+ user: {
201
+ changeEmail: { enabled: true, sendChangeEmailVerification: handlers.verification },
202
+ },
203
+ socialProviders: buildSocialProviders(authConfig),
204
+ plugins: buildAuthPlugins(handlers, authConfig),
205
+ rateLimit: buildRateLimitConfig(),
206
+ hooks: buildAuthHooks(),
207
+ })
208
+ }
209
+
210
+ /**
211
+ * Default Better Auth instance for OpenAPI schema generation
212
+ * Uses default configuration (requireEmailVerification: false)
213
+ *
214
+ * For app-specific configuration, use createAuthLayer(authConfig) instead.
215
+ */
216
+ export const auth = createAuthInstance()