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,114 @@
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 { hc } from 'hono/client'
9
+ import type { ApiType } from '@/infrastructure/server/route-setup/api-routes'
10
+
11
+ /**
12
+ * Hono RPC Client Factory
13
+ *
14
+ * Creates a fully typed API client for making requests to the Sovrium API.
15
+ * The client provides:
16
+ * - Full TypeScript autocomplete for all endpoints
17
+ * - Type-safe request parameters and response data
18
+ * - Automatic URL construction
19
+ * - Native fetch-based implementation
20
+ *
21
+ * **Benefits of Hono RPC**:
22
+ * - Zero code generation - types extracted directly from server routes
23
+ * - No OpenAPI client generation step required
24
+ * - Real-time type safety - changes to server routes immediately reflected
25
+ * - Minimal bundle size - uses native fetch
26
+ *
27
+ * @param baseUrl - Base URL of the API server (e.g., 'http://localhost:3000')
28
+ * @returns Typed RPC client for making API requests
29
+ *
30
+ * @example
31
+ * Basic usage:
32
+ * ```typescript
33
+ * import { createApiClient } from '@/presentation/api/client'
34
+ *
35
+ * const client = createApiClient('http://localhost:3000')
36
+ *
37
+ * // GET /api/health - fully typed!
38
+ * const res = await client.api.health.$get()
39
+ * const data = await res.json()
40
+ * // data is typed as HealthResponse { status: 'ok', timestamp: string, app: { name: string } }
41
+ * console.log(data.status) // 'ok'
42
+ * ```
43
+ *
44
+ * @example
45
+ * With error handling:
46
+ * ```typescript
47
+ * const client = createApiClient('http://localhost:3000')
48
+ *
49
+ * try {
50
+ * const res = await client.api.health.$get()
51
+ *
52
+ * if (!res.ok) {
53
+ * throw new Error(`HTTP ${res.status}: ${res.statusText}`)
54
+ * }
55
+ *
56
+ * const data = await res.json()
57
+ * console.log('Health check:', data)
58
+ * } catch (error) {
59
+ * console.error('Health check failed:', error)
60
+ * }
61
+ * ```
62
+ *
63
+ * @example
64
+ * Future usage with path parameters (when tables API is implemented):
65
+ * ```typescript
66
+ * // GET /api/tables/:id
67
+ * const res = await client.api.tables[':id'].$get({
68
+ * param: { id: '123' }
69
+ * })
70
+ * const table = await res.json()
71
+ *
72
+ * // POST /api/tables/:id/records
73
+ * const res = await client.api.tables[':id'].records.$post({
74
+ * param: { id: '123' },
75
+ * json: { name: 'John', email: 'john@example.com' }
76
+ * })
77
+ * const record = await res.json()
78
+ * ```
79
+ *
80
+ * @example
81
+ * Using in React components with TanStack Query:
82
+ * ```typescript
83
+ * import { useQuery } from '@tanstack/react-query'
84
+ * import { createApiClient } from '@/presentation/api/client'
85
+ *
86
+ * const client = createApiClient('http://localhost:3000')
87
+ *
88
+ * function HealthStatus() {
89
+ * const { data, isLoading, error } = useQuery({
90
+ * queryKey: ['health'],
91
+ * queryFn: async () => {
92
+ * const res = await client.api.health.$get()
93
+ * if (!res.ok) throw new Error('Health check failed')
94
+ * return res.json()
95
+ * }
96
+ * })
97
+ *
98
+ * if (isLoading) return <div>Loading...</div>
99
+ * if (error) return <div>Error: {error.message}</div>
100
+ *
101
+ * return <div>Status: {data?.status}</div>
102
+ * }
103
+ * ```
104
+ */
105
+ export const createApiClient = (baseUrl: string) => {
106
+ return hc<ApiType>(baseUrl)
107
+ }
108
+
109
+ /**
110
+ * Re-export ApiType for convenience
111
+ *
112
+ * Allows consumers to import both the client and type from the same file.
113
+ */
114
+ export type { ApiType }
@@ -0,0 +1,233 @@
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 { logError, logWarning } from '@/infrastructure/logging/logger'
9
+ import type { Session } from '@/application/ports/models/user-session'
10
+ import type { Context, Next } from 'hono'
11
+
12
+ /**
13
+ * Minimal Better Auth instance interface
14
+ *
15
+ * Typed to the subset of the Better Auth API actually used by the middleware.
16
+ * Better Auth's full type varies by configuration (plugins, providers)
17
+ * and uses optional fields (ipAddress?) that conflict with our Session type
18
+ * (ipAddress: string | null), so getSession returns Promise<unknown>.
19
+ * The middleware handles extraction with runtime checks and explicit casts.
20
+ */
21
+ interface BetterAuthLike {
22
+ readonly api: {
23
+ readonly getSession: (options: { readonly headers: Headers }) => Promise<unknown>
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Hono context with session attached
29
+ *
30
+ * Used by auth middleware to store extracted session for route handlers
31
+ */
32
+ export type ContextWithSession = Context & {
33
+ readonly var: {
34
+ readonly session?: Session
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Extract client IP address from request headers
40
+ *
41
+ * Checks common proxy headers in priority order:
42
+ * 1. X-Forwarded-For (most common)
43
+ * 2. X-Real-IP (nginx)
44
+ * 3. CF-Connecting-IP (Cloudflare)
45
+ * 4. Falls back to direct connection IP
46
+ */
47
+ function getClientIP(c: Context): string | undefined {
48
+ const xForwardedFor = c.req.header('x-forwarded-for')
49
+ if (xForwardedFor) {
50
+ // X-Forwarded-For can contain multiple IPs, take the first one (client)
51
+ return xForwardedFor.split(',')[0]?.trim()
52
+ }
53
+
54
+ const xRealIp = c.req.header('x-real-ip')
55
+ if (xRealIp) {
56
+ return xRealIp
57
+ }
58
+
59
+ const cfConnectingIp = c.req.header('cf-connecting-ip')
60
+ if (cfConnectingIp) {
61
+ return cfConnectingIp
62
+ }
63
+
64
+ // Fallback to undefined if no IP headers found
65
+ return undefined
66
+ }
67
+
68
+ /**
69
+ * Validate session binding to original IP and User-Agent
70
+ *
71
+ * When strict mode is enabled, sessions are bound to the IP address and
72
+ * User-Agent that created them. This prevents session hijacking attacks.
73
+ *
74
+ * @param session - Session object from database
75
+ * @param currentIP - Current request IP address
76
+ * @param currentUserAgent - Current request User-Agent
77
+ * @returns true if session is valid, false if binding validation fails
78
+ */
79
+ function validateSessionBinding(
80
+ session: Session,
81
+ currentIP: string | undefined,
82
+ currentUserAgent: string | undefined
83
+ ): boolean {
84
+ // For now, allow sessions without binding metadata (backward compatibility)
85
+ // This will be tightened when strict mode is explicitly enabled
86
+ if (!session.ipAddress && !session.userAgent) {
87
+ return true
88
+ }
89
+
90
+ // If session has IP binding, validate it matches
91
+ if (session.ipAddress && currentIP && session.ipAddress !== currentIP) {
92
+ return false
93
+ }
94
+
95
+ // If session has User-Agent binding, validate it matches
96
+ if (session.userAgent && currentUserAgent && session.userAgent !== currentUserAgent) {
97
+ return false
98
+ }
99
+
100
+ return true
101
+ }
102
+
103
+ /**
104
+ * Process session result and attach to context if valid
105
+ *
106
+ * Validates session binding and logs security warnings for failed validations.
107
+ */
108
+ function processSessionResult(
109
+ c: Context,
110
+ sessionResult: { readonly session?: Session } | null
111
+ ): void {
112
+ if (!sessionResult?.session) {
113
+ return
114
+ }
115
+
116
+ const currentIP = getClientIP(c)
117
+ const currentUserAgent = c.req.header('user-agent')
118
+
119
+ if (validateSessionBinding(sessionResult.session as Session, currentIP, currentUserAgent)) {
120
+ c.set('session', sessionResult.session as Session)
121
+ } else {
122
+ // Session binding validation failed - log for security monitoring
123
+ logWarning(
124
+ `[AUTH] Session binding validation failed: ${JSON.stringify({
125
+ sessionId: sessionResult.session.id,
126
+ expectedIP: sessionResult.session.ipAddress,
127
+ currentIP,
128
+ expectedUserAgent: sessionResult.session.userAgent,
129
+ currentUserAgent,
130
+ })}`
131
+ )
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Auth middleware for Hono routes
137
+ *
138
+ * Extracts Better Auth session from request and attaches to context.
139
+ * Routes can access session via `c.var.session`.
140
+ *
141
+ * **Session Extraction Strategy**:
142
+ * 1. Check for Authorization header (Bearer token)
143
+ * 2. Query Better Auth session table to validate token
144
+ * 3. Validate session binding (IP/User-Agent) if strict mode enabled
145
+ * 4. Attach session to context if valid
146
+ * 5. Continue to route handler (session may be undefined for public routes)
147
+ *
148
+ * **Session Binding (Strict Mode)**:
149
+ * When enabled, sessions are bound to the IP address and User-Agent that
150
+ * created them. Requests from different IP/User-Agent will be rejected.
151
+ *
152
+ * **Usage**:
153
+ * ```typescript
154
+ * app.use('/api/tables/*', authMiddleware(auth))
155
+ * app.get('/api/tables/:id', async (c) => {
156
+ * const session = c.var.session
157
+ * if (!session) return c.json({ error: 'Unauthorized' }, 401)
158
+ * // Use session for database queries
159
+ * })
160
+ * ```
161
+ *
162
+ * @param auth - Better Auth instance with api.getSession method
163
+ * @returns Hono middleware function
164
+ */
165
+ export function authMiddleware(auth: BetterAuthLike) {
166
+ return async (c: Context, next: Next) => {
167
+ try {
168
+ const authHeader = c.req.header('authorization')
169
+
170
+ if (authHeader?.toLowerCase().startsWith('bearer ')) {
171
+ const apiKey = authHeader.slice(7)
172
+ const result = (await auth.api.getSession({
173
+ headers: new Headers({ authorization: apiKey }),
174
+ })) as { readonly session?: Session } | null
175
+ processSessionResult(c, result)
176
+ } else {
177
+ const result = (await auth.api.getSession({
178
+ headers: c.req.raw.headers,
179
+ })) as { readonly session?: Session } | null
180
+ processSessionResult(c, result)
181
+ }
182
+ } catch (error) {
183
+ logError('[AUTH] Session extraction failed', error)
184
+ }
185
+
186
+ // eslint-disable-next-line functional/no-expression-statements -- Required for middleware to continue to next handler
187
+ await next()
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Middleware handler for requiring authentication
193
+ */
194
+ async function requireAuthHandler(c: ContextWithSession, next: Next) {
195
+ const { session } = c.var
196
+
197
+ if (!session) {
198
+ return c.json(
199
+ {
200
+ success: false,
201
+ error: 'Unauthorized',
202
+ message: 'Authentication required',
203
+ code: 'UNAUTHORIZED',
204
+ },
205
+ 401
206
+ )
207
+ }
208
+
209
+ // eslint-disable-next-line functional/no-expression-statements -- Required for middleware to continue to next handler
210
+ await next()
211
+ }
212
+
213
+ /**
214
+ * Require authentication middleware
215
+ *
216
+ * Returns 401 if session is not present.
217
+ * Use this for protected routes that require authentication.
218
+ *
219
+ * **Usage**:
220
+ * ```typescript
221
+ * app.use('/api/tables/*', authMiddleware(auth))
222
+ * app.use('/api/tables/*', requireAuth())
223
+ * app.get('/api/tables/:id', async (c) => {
224
+ * const session = c.var.session! // Safe to use non-null assertion
225
+ * // Session is guaranteed to exist
226
+ * })
227
+ * ```
228
+ *
229
+ * @returns Hono middleware function
230
+ */
231
+ export function requireAuth() {
232
+ return requireAuthHandler
233
+ }
@@ -0,0 +1,155 @@
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 { getUserRole } from '@/application/use-cases/tables/user-role'
9
+ import type { ContextWithSession } from './auth'
10
+ import type { Session } from '@/application/ports/models/user-session'
11
+ import type { App } from '@/domain/models/app'
12
+ import type { Context, Next } from 'hono'
13
+
14
+ // ============================================================================
15
+ // Extended Context Types
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Hono context with validated table information attached
20
+ *
21
+ * Available after `validateTable()` middleware runs.
22
+ */
23
+ export type ContextWithValidatedTable = ContextWithSession & {
24
+ readonly var: {
25
+ readonly tableName: string
26
+ readonly tableId: string
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Hono context with user role attached
32
+ *
33
+ * Available after `enrichUserRole()` middleware runs.
34
+ * Requires session to exist (use after `requireAuth()`).
35
+ */
36
+ export type ContextWithUserRole = ContextWithSession & {
37
+ readonly var: {
38
+ readonly userRole: string
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Combined context with session, validated table, and user role
44
+ *
45
+ * Available after full middleware chain:
46
+ * `authMiddleware` → `requireAuth` → `validateTable` → `enrichUserRole`
47
+ *
48
+ * **Session is guaranteed to exist** because `requireAuth()` rejects
49
+ * requests without a valid session.
50
+ */
51
+ export type ContextWithTableAndRole = Context & {
52
+ readonly var: {
53
+ readonly session: Session // Non-optional - guaranteed by requireAuth()
54
+ readonly tableName: string
55
+ readonly tableId: string
56
+ readonly userRole: string
57
+ }
58
+ }
59
+
60
+ // ============================================================================
61
+ // Middleware Functions
62
+ // ============================================================================
63
+
64
+ /**
65
+ * Middleware to validate table exists and resolve table name
66
+ *
67
+ * Extracts :tableId param, validates table exists in app schema,
68
+ * and attaches resolved table name to context.
69
+ *
70
+ * **Context Variables Set**:
71
+ * - `tableName`: The resolved table name
72
+ * - `tableId`: The original tableId parameter
73
+ *
74
+ * **Usage**:
75
+ * ```typescript
76
+ * app.use('/api/tables/:tableId/*', validateTable(app))
77
+ * app.get('/api/tables/:tableId/records', (c: ContextWithValidatedTable) => {
78
+ * const { tableName } = c.var // Already validated!
79
+ * })
80
+ * ```
81
+ *
82
+ * @param app - Application configuration containing table definitions
83
+ * @returns Hono middleware function
84
+ */
85
+ export function validateTable(app: App) {
86
+ return async (c: Context, next: Next) => {
87
+ const tableId = c.req.param('tableId')
88
+
89
+ if (!tableId) {
90
+ return c.json(
91
+ { success: false, message: 'Table ID parameter required', code: 'VALIDATION_ERROR' },
92
+ 400
93
+ )
94
+ }
95
+
96
+ const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
97
+
98
+ if (!table) {
99
+ return c.json({ success: false, message: 'Resource not found', code: 'NOT_FOUND' }, 404)
100
+ }
101
+
102
+ // Attach to context for downstream handlers
103
+ c.set('tableName', table.name)
104
+ c.set('tableId', tableId)
105
+
106
+ // eslint-disable-next-line functional/no-expression-statements -- Required for middleware to continue
107
+ await next()
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Middleware to enrich context with user role
113
+ *
114
+ * Fetches user role from database and attaches to context.
115
+ * Requires session to exist (use after `requireAuth()` middleware).
116
+ *
117
+ * **Context Variables Set**:
118
+ * - `userRole`: The user's role in the organization
119
+ *
120
+ * **Usage**:
121
+ * ```typescript
122
+ * app.use('/api/tables/*', authMiddleware(auth))
123
+ * app.use('/api/tables/*', requireAuth())
124
+ * app.use('/api/tables/:tableId/*', enrichUserRole())
125
+ * app.get('/api/tables/:tableId/records', (c: ContextWithUserRole) => {
126
+ * const { userRole } = c.var // Already fetched!
127
+ * })
128
+ * ```
129
+ *
130
+ * @param getUserRoleFn - Optional function to resolve user role (for unit tests).
131
+ * Defaults to the real getUserRole from application layer.
132
+ * @returns Hono middleware function
133
+ */
134
+ export function enrichUserRole(getUserRoleFn?: (userId: string) => Promise<string>) {
135
+ const resolveRole = getUserRoleFn ?? getUserRole
136
+
137
+ return async (c: Context, next: Next) => {
138
+ const { session } = (c as ContextWithSession).var
139
+
140
+ // Defensive check (should not happen if requireAuth() used before)
141
+ if (!session) {
142
+ return c.json(
143
+ { success: false, message: 'Authentication required', code: 'UNAUTHORIZED' },
144
+ 401
145
+ )
146
+ }
147
+
148
+ const userRole = await resolveRole(session.userId)
149
+
150
+ c.set('userRole', userRole)
151
+
152
+ // eslint-disable-next-line functional/no-expression-statements -- Required for middleware to continue
153
+ await next()
154
+ }
155
+ }
@@ -0,0 +1,88 @@
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 { Context, Layer } from 'effect'
9
+ import type { App } from '@/domain/models/app'
10
+ import type { Effect } from 'effect'
11
+ import type { Context as HonoContext } from 'hono'
12
+
13
+ /**
14
+ * Validation error types
15
+ */
16
+ export class ValidationError {
17
+ readonly _tag = 'ValidationError'
18
+ constructor(
19
+ readonly message: string,
20
+ readonly field?: string
21
+ ) {}
22
+ }
23
+
24
+ export class PermissionError {
25
+ readonly _tag = 'PermissionError'
26
+ constructor(
27
+ readonly message: string,
28
+ readonly field?: string
29
+ ) {}
30
+ }
31
+
32
+ /**
33
+ * Validation context - provides app configuration and request context
34
+ */
35
+ export class ValidationContext extends Context.Tag('ValidationContext')<
36
+ ValidationContext,
37
+ {
38
+ readonly app: App
39
+ readonly tableName: string
40
+ readonly userRole: string
41
+ }
42
+ >() {}
43
+
44
+ /**
45
+ * Validation result type
46
+ */
47
+ export type ValidationResult<T> = Effect.Effect<T, ValidationError | PermissionError, never>
48
+
49
+ /**
50
+ * Create a validation layer from app, tableName, and userRole
51
+ */
52
+ export function createValidationLayer(app: App, tableName: string, userRole: string) {
53
+ return Layer.succeed(ValidationContext, {
54
+ app,
55
+ tableName,
56
+ userRole,
57
+ })
58
+ }
59
+
60
+ /**
61
+ * Validation error response helper
62
+ */
63
+ export function formatValidationError(
64
+ error: ValidationError | PermissionError,
65
+ c: HonoContext
66
+ ): Response {
67
+ if (error._tag === 'ValidationError') {
68
+ return c.json(
69
+ {
70
+ success: false,
71
+ message: error.message,
72
+ code: 'VALIDATION_ERROR',
73
+ ...(error.field ? { field: error.field } : {}),
74
+ },
75
+ 400
76
+ )
77
+ }
78
+
79
+ return c.json(
80
+ {
81
+ success: false,
82
+ message: error.message,
83
+ code: 'FORBIDDEN',
84
+ ...(error.field ? { field: error.field } : {}),
85
+ },
86
+ 403
87
+ )
88
+ }
@@ -0,0 +1,77 @@
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 { Effect } from 'effect'
9
+ import { GetActivityById } from '@/application/use-cases/activity/programs'
10
+ import { DatabaseLive } from '@/infrastructure/database'
11
+ import type { Context } from 'hono'
12
+
13
+ /**
14
+ * GET /api/activity/:activityId handler
15
+ *
16
+ * Fetches activity log details by ID with user metadata.
17
+ *
18
+ * **Authentication**: Requires authenticated session
19
+ * **Authorization**: All authenticated users can view activity logs
20
+ *
21
+ * **Response Structure**:
22
+ * - 200: Activity details with user metadata
23
+ * - 400: Invalid activity ID format
24
+ * - 401: Unauthorized (no session)
25
+ * - 404: Activity not found
26
+ *
27
+ * @param c - Hono context
28
+ * @returns JSON response with activity details or error
29
+ */
30
+ export async function getActivityByIdHandler(c: Context) {
31
+ const activityId = c.req.param('activityId')
32
+
33
+ const program = GetActivityById(activityId).pipe(Effect.provide(DatabaseLive))
34
+
35
+ const result = await Effect.runPromise(program.pipe(Effect.either))
36
+
37
+ if (result._tag === 'Left') {
38
+ const error = result.left
39
+
40
+ // Handle specific error types
41
+ if (error._tag === 'InvalidActivityIdError') {
42
+ return c.json(
43
+ {
44
+ success: false,
45
+ message: 'Invalid activity ID format',
46
+ code: 'INVALID_ACTIVITY_ID',
47
+ },
48
+ 400
49
+ )
50
+ }
51
+
52
+ if (error._tag === 'ActivityNotFoundError') {
53
+ return c.json(
54
+ {
55
+ success: false,
56
+ message: 'Activity not found',
57
+ code: 'ACTIVITY_NOT_FOUND',
58
+ },
59
+ 404
60
+ )
61
+ }
62
+
63
+ // Database error
64
+ return c.json(
65
+ {
66
+ success: false,
67
+ message: 'Failed to fetch activity',
68
+ code: 'DATABASE_ERROR',
69
+ },
70
+ 500
71
+ )
72
+ }
73
+
74
+ const activity = result.right
75
+
76
+ return c.json(activity, 200)
77
+ }
@@ -0,0 +1,28 @@
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 { getActivityByIdHandler } from './get-activity-by-id-handler'
9
+ import type { Hono } from 'hono'
10
+
11
+ /**
12
+ * Chain activity routes onto a Hono app
13
+ *
14
+ * **Authentication Middleware** (applied in api-routes.ts):
15
+ * - All activity endpoints require authentication
16
+ * - Middleware chain: requireAuth() → Handler
17
+ * - Authentication is ALWAYS required, even when app.auth is not configured
18
+ *
19
+ * **Routes**:
20
+ * - GET /api/activity/:activityId - Get activity log details
21
+ *
22
+ * @param honoApp - Hono instance to chain routes onto
23
+ * @returns Hono app with activity routes chained
24
+ */
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Hono type inference with middleware requires flexible typing
26
+ export function chainActivityRoutes<T extends Hono<any, any, any>>(honoApp: T) {
27
+ return honoApp.get('/api/activity/:activityId', getActivityByIdHandler)
28
+ }