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,136 @@
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 { readdir, mkdir } from 'node:fs/promises'
9
+ import { join, relative } from 'node:path'
10
+ import { Effect, Data } from 'effect'
11
+ import type { Dirent } from 'node:fs'
12
+
13
+ /**
14
+ * File copy error - infrastructure layer error
15
+ */
16
+ export class FileCopyError extends Data.TaggedError('FileCopyError')<{
17
+ readonly message: string
18
+ readonly cause?: unknown
19
+ }> {}
20
+
21
+ /**
22
+ * Copy a single file from source to destination using Bun's native file API
23
+ */
24
+ const copyFile = (
25
+ sourcePath: string,
26
+ destPath: string
27
+ ): Effect.Effect<string, FileCopyError, never> =>
28
+ Effect.gen(function* () {
29
+ // Read file using Bun's native file API (faster and more idiomatic)
30
+ // arrayBuffer() preserves binary content exactly
31
+ const content = yield* Effect.tryPromise({
32
+ try: () => Bun.file(sourcePath).arrayBuffer(),
33
+ catch: (error) =>
34
+ new FileCopyError({
35
+ message: `Failed to read file ${sourcePath}`,
36
+ cause: error,
37
+ }),
38
+ })
39
+
40
+ // Write file using Bun.write (faster than Node.js fs/promises)
41
+ // Bun.write handles ArrayBuffer, Buffer, string, etc.
42
+ yield* Effect.tryPromise({
43
+ try: () => Bun.write(destPath, content),
44
+ catch: (error) =>
45
+ new FileCopyError({
46
+ message: `Failed to write file ${destPath}`,
47
+ cause: error,
48
+ }),
49
+ })
50
+
51
+ return destPath
52
+ })
53
+
54
+ /**
55
+ * Create a directory at the destination
56
+ */
57
+ const createDirectory = (destPath: string): Effect.Effect<void, FileCopyError, never> =>
58
+ Effect.tryPromise({
59
+ try: () => mkdir(destPath, { recursive: true }),
60
+ catch: (error) =>
61
+ new FileCopyError({
62
+ message: `Failed to create directory ${destPath}`,
63
+ cause: error,
64
+ }),
65
+ })
66
+
67
+ /**
68
+ * Read directory entries
69
+ */
70
+ const readDirectoryEntries = (
71
+ sourcePath: string
72
+ ): Effect.Effect<readonly Dirent[], FileCopyError, never> =>
73
+ Effect.tryPromise({
74
+ try: () => readdir(sourcePath, { withFileTypes: true }),
75
+ catch: (error) =>
76
+ new FileCopyError({
77
+ message: `Failed to read directory ${sourcePath}`,
78
+ cause: error,
79
+ }),
80
+ })
81
+
82
+ /**
83
+ * Recursively copy directory contents from source to destination
84
+ *
85
+ * This function:
86
+ * 1. Preserves directory structure
87
+ * 2. Handles binary files correctly (no corruption)
88
+ * 3. Skips the assets/ directory in destination (reserved for CSS)
89
+ * 4. Returns list of copied file paths (relative to destination)
90
+ *
91
+ * @param source - Source directory path
92
+ * @param destination - Destination directory path
93
+ * @returns Effect with list of copied file paths (relative to destination)
94
+ */
95
+ export const copyDirectory = (
96
+ source: string,
97
+ destination: string
98
+ ): Effect.Effect<readonly string[], FileCopyError, never> => {
99
+ // Recursive copy function that returns list of copied files
100
+ const copyRecursive = (
101
+ sourcePath: string,
102
+ destPath: string
103
+ ): Effect.Effect<readonly string[], FileCopyError, never> =>
104
+ Effect.gen(function* () {
105
+ const entries = yield* readDirectoryEntries(sourcePath)
106
+
107
+ // Process entries and collect copied files immutably
108
+ const copiedFiles = yield* Effect.forEach(
109
+ entries,
110
+ (entry) =>
111
+ Effect.gen(function* () {
112
+ const sourceEntryPath = join(sourcePath, entry.name)
113
+ const destEntryPath = join(destPath, entry.name)
114
+
115
+ if (entry.isDirectory()) {
116
+ yield* createDirectory(destEntryPath)
117
+ return yield* copyRecursive(sourceEntryPath, destEntryPath)
118
+ }
119
+
120
+ if (entry.isFile()) {
121
+ yield* copyFile(sourceEntryPath, destEntryPath)
122
+ const relativePath = relative(destination, destEntryPath)
123
+ return [relativePath] as readonly string[]
124
+ }
125
+
126
+ // Not a directory or file (e.g., symlink) - skip
127
+ return [] as readonly string[]
128
+ }),
129
+ { concurrency: 'unbounded' }
130
+ )
131
+
132
+ return copiedFiles.flat() as readonly string[]
133
+ })
134
+
135
+ return copyRecursive(source, destination)
136
+ }
@@ -0,0 +1,61 @@
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 { Layer } from 'effect'
9
+ import { createAuthLayer } from '@/infrastructure/auth/better-auth'
10
+ import { CSSCompilerLive } from '@/infrastructure/css/css-compiler-live'
11
+ import { DatabaseLive } from '@/infrastructure/database/drizzle/layer'
12
+ import { AuthRepositoryLive } from '@/infrastructure/database/repositories/auth-repository-live'
13
+ import { DevToolsLayerOptional } from '@/infrastructure/devtools'
14
+ import { PageRendererLive } from '@/infrastructure/layers/page-renderer-layer'
15
+ import { LoggerLive } from '@/infrastructure/logging/logger'
16
+ import { ServerFactoryLive } from '@/infrastructure/server/server-factory-live'
17
+ import { StaticSiteGeneratorLive } from '@/infrastructure/server/static-site-generator-live'
18
+ import type { Auth as AuthConfig } from '@/domain/models/app/auth'
19
+
20
+ /**
21
+ * Application layer composition
22
+ *
23
+ * Combines all live service implementations into a single Layer
24
+ * that can be provided to Application use cases.
25
+ *
26
+ * This is the production dependency wiring point - swap out
27
+ * individual layers here for testing or different environments.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // In src/index.ts (production)
32
+ * const program = startServer(appConfig).pipe(
33
+ * Effect.provide(createAppLayer(appConfig.auth))
34
+ * )
35
+ *
36
+ * // In tests (with mocks)
37
+ * const TestLayer = Layer.mergeAll(MockServerFactory, MockPageRenderer)
38
+ * const program = startServer(appConfig).pipe(
39
+ * Effect.provide(TestLayer)
40
+ * )
41
+ * ```
42
+ */
43
+ export const createAppLayer = (authConfig?: AuthConfig) =>
44
+ Layer.mergeAll(
45
+ createAuthLayer(authConfig),
46
+ DatabaseLive,
47
+ ServerFactoryLive,
48
+ PageRendererLive,
49
+ CSSCompilerLive,
50
+ StaticSiteGeneratorLive,
51
+ DevToolsLayerOptional,
52
+ LoggerLive,
53
+ AuthRepositoryLive
54
+ )
55
+
56
+ /**
57
+ * Default application layer with default auth configuration
58
+ *
59
+ * @deprecated Use createAppLayer(authConfig) instead for app-specific configuration
60
+ */
61
+ export const AppLayer = createAppLayer()
@@ -0,0 +1,41 @@
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 { Layer } from 'effect'
9
+ import { PageRenderer } from '@/application/ports/services/page-renderer'
10
+ import { renderErrorPage, renderNotFoundPage } from '@/presentation/rendering/render-error-pages'
11
+ import { renderHomePage, renderPage } from '@/presentation/rendering/render-homepage'
12
+
13
+ /**
14
+ * Live implementation of PageRenderer using React SSR
15
+ *
16
+ * This Layer provides production page rendering logic,
17
+ * wrapping the presentation layer rendering functions in an
18
+ * Effect Context service.
19
+ *
20
+ * Located in Infrastructure layer because Effect Layer "Live"
21
+ * implementations are adapters (ports/adapters pattern).
22
+ * Infrastructure adapters CAN depend on presentation utilities
23
+ * for rendering logic.
24
+ *
25
+ * The implementation uses Layer.succeed because all rendering
26
+ * functions are pure and synchronous (no async operations).
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * // Provide PageRendererLive to use cases
31
+ * const program = startServer(appConfig).pipe(
32
+ * Effect.provide(PageRendererLive)
33
+ * )
34
+ * ```
35
+ */
36
+ export const PageRendererLive = Layer.succeed(PageRenderer, {
37
+ renderHome: renderHomePage,
38
+ renderPage,
39
+ renderNotFound: renderNotFoundPage,
40
+ renderError: renderErrorPage,
41
+ })
@@ -0,0 +1,8 @@
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
+ export { logError, logWarning, logInfo, logDebug, createModuleLogger } from './logger'
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { Console, Context, Effect, Layer } from 'effect'
9
+
10
+ /**
11
+ * Logger service for application-wide logging
12
+ *
13
+ * Provides structured logging with log levels:
14
+ * - debug: Detailed diagnostic information
15
+ * - info: General informational messages
16
+ * - warn: Warning messages for potential issues
17
+ * - error: Error messages for failures
18
+ */
19
+ export class Logger extends Context.Tag('Logger')<
20
+ Logger,
21
+ {
22
+ readonly debug: (message: string, ...args: unknown[]) => Effect.Effect<void>
23
+ readonly info: (message: string, ...args: unknown[]) => Effect.Effect<void>
24
+ readonly warn: (message: string, ...args: unknown[]) => Effect.Effect<void>
25
+ readonly error: (message: string, error?: unknown) => Effect.Effect<void>
26
+ }
27
+ >() {}
28
+
29
+ /**
30
+ * Format log message with timestamp
31
+ */
32
+ const formatLogMessage = (level: string, message: string): string => {
33
+ const timestamp = new Date().toISOString()
34
+ return `[${timestamp}] [${level}] ${message}`
35
+ }
36
+
37
+ /**
38
+ * Console-based logger implementation
39
+ *
40
+ * Uses Effect Console for output with structured formatting
41
+ * Format: [2025-01-15T10:30:00.000Z] [LEVEL] message
42
+ *
43
+ * Benefits of Effect Console over console.*:
44
+ * - Already Effect-based (no need to wrap in Effect.sync)
45
+ * - Testable via Console.setConsole for mocking
46
+ * - Integrates with Effect DevTools and tracing
47
+ * - Type-safe with better TypeScript inference
48
+ */
49
+ export const LoggerLive = Layer.succeed(Logger, {
50
+ debug: (message, ...args) =>
51
+ Effect.gen(function* () {
52
+ if (process.env.LOG_LEVEL === 'debug' || process.env.NODE_ENV === 'development') {
53
+ yield* Console.debug(formatLogMessage('DEBUG', message), ...args)
54
+ }
55
+ }),
56
+
57
+ info: (message, ...args) => Console.log(formatLogMessage('INFO', message), ...args),
58
+
59
+ warn: (message, ...args) => Console.warn(formatLogMessage('WARN', message), ...args),
60
+
61
+ error: (message, error) =>
62
+ error
63
+ ? Console.error(formatLogMessage('ERROR', message), error)
64
+ : Console.error(formatLogMessage('ERROR', message)),
65
+ })
66
+
67
+ /**
68
+ * Silent logger for testing
69
+ *
70
+ * Discards all log messages
71
+ */
72
+ export const LoggerSilent = Layer.succeed(Logger, {
73
+ debug: () => Effect.void,
74
+ info: () => Effect.void,
75
+ warn: () => Effect.void,
76
+ error: () => Effect.void,
77
+ })
78
+
79
+ // ============================================================================
80
+ // Convenience Functions for Non-Effect Contexts
81
+ // ============================================================================
82
+
83
+ /**
84
+ * Convenience logging functions for non-Effect contexts
85
+ *
86
+ * These functions provide a bridge to use the Logger service from code that
87
+ * doesn't use Effect.gen (async callbacks, module initialization, etc.).
88
+ *
89
+ * Implementation: Thin wrapper around Logger service that automatically
90
+ * provides LoggerLive layer and runs the Effect synchronously.
91
+ *
92
+ * Why use this instead of console.*:
93
+ * 1. Consistent formatting with Logger service (timestamps, levels)
94
+ * 2. Single source of truth for logging implementation
95
+ * 3. Log levels for filtering (error, warning, info, debug)
96
+ * 4. Future-proof: easy to add log aggregation, tracing, etc.
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * import { logError, logWarning, logInfo } from '@/infrastructure/logging/logger'
101
+ *
102
+ * // In a non-Effect callback (e.g., Better Auth email handler)
103
+ * try {
104
+ * await sendEmail(...)
105
+ * } catch (error) {
106
+ * logError('[EMAIL] Failed to send email', error)
107
+ * }
108
+ * ```
109
+ */
110
+
111
+ /**
112
+ * Run a Logger service Effect synchronously with LoggerLive layer
113
+ *
114
+ * This is safe for logging effects as they don't require async operations
115
+ * and complete synchronously.
116
+ */
117
+ const runLogEffect = <A>(effect: Effect.Effect<A, never, Logger>): void => {
118
+ // eslint-disable-next-line functional/no-expression-statements -- Side effect for logging
119
+ Effect.runSync(effect.pipe(Effect.provide(LoggerLive)))
120
+ }
121
+
122
+ /**
123
+ * Log an error message with optional cause
124
+ *
125
+ * Use for unexpected errors, exceptions, and failure conditions.
126
+ *
127
+ * @param message - Error message (include context like [EMAIL], [AUTH])
128
+ * @param cause - Optional error cause for stack trace
129
+ */
130
+ export const logError = (message: string, cause?: unknown): void => {
131
+ runLogEffect(
132
+ Effect.gen(function* () {
133
+ const logger = yield* Logger
134
+ yield* logger.error(message, cause)
135
+ })
136
+ )
137
+ }
138
+
139
+ /**
140
+ * Log a warning message
141
+ *
142
+ * Use for non-critical issues that should be addressed but don't
143
+ * prevent operation (missing optional config, deprecated usage, etc.).
144
+ *
145
+ * @param message - Warning message
146
+ */
147
+ export const logWarning = (message: string): void => {
148
+ runLogEffect(
149
+ Effect.gen(function* () {
150
+ const logger = yield* Logger
151
+ yield* logger.warn(message)
152
+ })
153
+ )
154
+ }
155
+
156
+ /**
157
+ * Log an info message
158
+ *
159
+ * Use for notable events during normal operation (startup, config loaded, etc.).
160
+ *
161
+ * @param message - Info message
162
+ */
163
+ export const logInfo = (message: string): void => {
164
+ runLogEffect(
165
+ Effect.gen(function* () {
166
+ const logger = yield* Logger
167
+ yield* logger.info(message)
168
+ })
169
+ )
170
+ }
171
+
172
+ /**
173
+ * Log a debug message
174
+ *
175
+ * Use for detailed debugging information (variable values, flow tracing).
176
+ * These are typically filtered out in production.
177
+ *
178
+ * @param message - Debug message
179
+ */
180
+ export const logDebug = (message: string): void => {
181
+ runLogEffect(
182
+ Effect.gen(function* () {
183
+ const logger = yield* Logger
184
+ yield* logger.debug(message)
185
+ })
186
+ )
187
+ }
188
+
189
+ /**
190
+ * Create a logger with a fixed prefix for a specific module
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * const emailLogger = createModuleLogger('EMAIL')
195
+ * emailLogger.error('Failed to send') // Logs: [EMAIL] Failed to send
196
+ * emailLogger.warn('SMTP not configured')
197
+ * ```
198
+ */
199
+ export const createModuleLogger = (module: string) => ({
200
+ error: (message: string, cause?: unknown) => logError(`[${module}] ${message}`, cause),
201
+ warning: (message: string) => logWarning(`[${module}] ${message}`),
202
+ info: (message: string) => logInfo(`[${module}] ${message}`),
203
+ debug: (message: string) => logDebug(`[${module}] ${message}`),
204
+ })
@@ -0,0 +1,53 @@
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
+ * File Loader - Infrastructure Layer
10
+ *
11
+ * File system I/O operations for loading schema files.
12
+ */
13
+
14
+ import { detectFormat, getFileExtension, parseJsonContent, parseYamlContent } from '@/domain/utils'
15
+ import type { AppEncoded } from '@/domain/models/app'
16
+
17
+ /**
18
+ * Load and parse schema from a file (throws on error, no process.exit)
19
+ *
20
+ * @throws Error if file doesn't exist, format is unsupported, or parsing fails
21
+ */
22
+ export const loadSchemaFromFile = async (filePath: string): Promise<AppEncoded> => {
23
+ const file = Bun.file(filePath)
24
+ const exists = await file.exists()
25
+
26
+ if (!exists) {
27
+ // eslint-disable-next-line functional/no-throw-statements
28
+ throw new Error(`File not found: ${filePath}`)
29
+ }
30
+
31
+ const format = detectFormat(filePath)
32
+
33
+ if (format === 'unsupported') {
34
+ const extension = getFileExtension(filePath)
35
+ // eslint-disable-next-line functional/no-throw-statements
36
+ throw new Error(`Unsupported file format: .${extension}. Supported: .json, .yaml, .yml`)
37
+ }
38
+
39
+ const content = await file.text()
40
+
41
+ return format === 'json' ? parseJsonContent(content) : parseYamlContent(content)
42
+ }
43
+
44
+ /**
45
+ * Check if a file exists
46
+ */
47
+ export const fileExists = async (filePath: string): Promise<boolean> => Bun.file(filePath).exists()
48
+
49
+ /**
50
+ * Read file content as text
51
+ */
52
+ export const readFileContent = async (filePath: string): Promise<string> =>
53
+ Bun.file(filePath).text()
@@ -0,0 +1,15 @@
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
+ * Schema Infrastructure Module
10
+ *
11
+ * I/O operations for loading schemas from files and remote URLs.
12
+ */
13
+
14
+ export { loadSchemaFromFile, fileExists, readFileContent } from './file-loader'
15
+ export { fetchRemoteSchema } from './remote-loader'
@@ -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
+ * Remote Loader - Infrastructure Layer
10
+ *
11
+ * Network I/O operations for fetching schemas from remote URLs.
12
+ */
13
+
14
+ import {
15
+ detectFormatFromContentType,
16
+ detectFormatFromUrl,
17
+ parseSchemaContent,
18
+ } from '@/domain/utils'
19
+ import type { AppEncoded } from '@/domain/models/app'
20
+
21
+ /**
22
+ * Fetch and parse schema from a remote URL
23
+ *
24
+ * @throws Error if fetch fails or content cannot be parsed
25
+ */
26
+ export const fetchRemoteSchema = async (url: string): Promise<AppEncoded> => {
27
+ try {
28
+ const response = await fetch(url)
29
+
30
+ if (!response.ok) {
31
+ // eslint-disable-next-line functional/no-throw-statements
32
+ throw new Error(`Failed to fetch schema from ${url}: HTTP ${response.status}`)
33
+ }
34
+
35
+ const contentType = response.headers.get('content-type') || ''
36
+ const content = await response.text()
37
+
38
+ // Try to detect format from Content-Type header, then URL extension
39
+ const format = detectFormatFromContentType(contentType) || detectFormatFromUrl(url)
40
+
41
+ return parseSchemaContent(content, format)
42
+ } catch (error) {
43
+ // eslint-disable-next-line functional/no-throw-statements
44
+ throw new Error(
45
+ `Failed to fetch or parse schema from ${url}: ${error instanceof Error ? error.message : String(error)}`
46
+ )
47
+ }
48
+ }
@@ -0,0 +1,26 @@
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
+ * Server Infrastructure Module
10
+ *
11
+ * Provides HTTP server creation, lifecycle management, and factory implementations.
12
+ * Uses Hono web framework with graceful shutdown support.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { ServerFactoryLive } from '@/infrastructure/server'
17
+ *
18
+ * const program = startServer(config).pipe(
19
+ * Effect.provide(ServerFactoryLive)
20
+ * )
21
+ * ```
22
+ */
23
+
24
+ export { createServer } from './server'
25
+ export { withGracefulShutdown } from './lifecycle'
26
+ export { ServerFactoryLive } from './server-factory-live'
@@ -0,0 +1,87 @@
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 { detectLanguageFromHeader } from '@/infrastructure/utils/accept-language-parser'
9
+ import type { App } from '@/domain/models/app'
10
+
11
+ /**
12
+ * Get array of supported language codes from app configuration
13
+ *
14
+ * @param app - Application configuration
15
+ * @returns Array of short language codes or empty array if languages not configured
16
+ *
17
+ * @example
18
+ * getSupportedLanguageCodes(app) // => ['en', 'fr', 'es']
19
+ */
20
+ export function getSupportedLanguageCodes(app: App): ReadonlyArray<string> {
21
+ return app.languages?.supported.map((l) => l.code) || []
22
+ }
23
+
24
+ /**
25
+ * Extract and validate language code from URL path
26
+ *
27
+ * @param path - URL path (e.g., '/fr/', '/en/about')
28
+ * @param supportedLanguages - Array of supported short language codes
29
+ * @returns Short language code if valid, undefined otherwise
30
+ *
31
+ * @example
32
+ * extractLanguageFromPath('/fr/', ['en', 'fr']) // => 'fr'
33
+ * extractLanguageFromPath('/fr/about', ['en', 'fr']) // => 'fr'
34
+ * extractLanguageFromPath('/invalid/', ['en', 'fr']) // => undefined
35
+ * extractLanguageFromPath('/', ['en', 'fr']) // => undefined
36
+ */
37
+ export function extractLanguageFromPath(
38
+ path: string,
39
+ supportedLanguages: ReadonlyArray<string>
40
+ ): string | undefined {
41
+ // Extract first path segment (e.g., '/fr-FR/about' => 'fr-FR')
42
+ const segments = path.split('/').filter(Boolean)
43
+ if (segments.length === 0) {
44
+ return undefined
45
+ }
46
+
47
+ const potentialLang = segments[0]
48
+ if (!potentialLang) {
49
+ return undefined
50
+ }
51
+
52
+ // Validate against supported languages
53
+ return supportedLanguages.includes(potentialLang) ? potentialLang : undefined
54
+ }
55
+
56
+ /**
57
+ * Detect language from Accept-Language header if browser detection is enabled
58
+ *
59
+ * @param app - Application configuration
60
+ * @param header - Accept-Language HTTP header value
61
+ * @returns Detected short language code or undefined
62
+ *
63
+ * @example
64
+ * detectLanguageIfEnabled(app, 'fr-FR,fr;q=0.9,en;q=0.8') // => 'fr'
65
+ * detectLanguageIfEnabled(appWithDetectionDisabled, 'fr-FR') // => undefined
66
+ */
67
+ export function detectLanguageIfEnabled(app: App, header: string | undefined): string | undefined {
68
+ if (app.languages?.detectBrowser === false) {
69
+ return undefined
70
+ }
71
+ return detectLanguageFromHeader(header, getSupportedLanguageCodes(app))
72
+ }
73
+
74
+ /**
75
+ * Validate and extract language code from URL subdirectory path
76
+ *
77
+ * @param app - Application configuration
78
+ * @param path - URL path (e.g., '/fr/', '/en/about')
79
+ * @returns Short language code if valid subdirectory, undefined otherwise
80
+ *
81
+ * @example
82
+ * validateLanguageSubdirectory(app, '/fr/') // => 'fr'
83
+ * validateLanguageSubdirectory(app, '/products/pricing') // => undefined
84
+ */
85
+ export function validateLanguageSubdirectory(app: App, path: string): string | undefined {
86
+ return extractLanguageFromPath(path, getSupportedLanguageCodes(app))
87
+ }