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.
- package/CHANGELOG.md +3497 -0
- package/LICENSE.md +147 -0
- package/LICENSE_EE.md +297 -0
- package/README.md +321 -0
- package/drizzle/0000_melted_kabuki.sql +163 -0
- package/drizzle/meta/0000_snapshot.json +1216 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +167 -0
- package/schemas/0.0.1/app.openapi.json +70 -0
- package/schemas/0.0.1/app.schema.json +7961 -0
- package/schemas/0.0.2/app.openapi.json +80 -0
- package/schemas/0.0.2/app.schema.json +8829 -0
- package/schemas/development/app.openapi.json +70 -0
- package/schemas/development/app.schema.json +7456 -0
- package/src/application/errors/app-validation-error.ts +14 -0
- package/src/application/errors/static-generation-error.ts +16 -0
- package/src/application/metadata/favicon-transformer.ts +127 -0
- package/src/application/models/server.ts +27 -0
- package/src/application/ports/models/user-metadata.ts +36 -0
- package/src/application/ports/models/user-session.ts +34 -0
- package/src/application/ports/repositories/activity-log-repository.ts +68 -0
- package/src/application/ports/repositories/activity-repository.ts +49 -0
- package/src/application/ports/repositories/analytics-repository.ts +164 -0
- package/src/application/ports/repositories/auth-repository.ts +33 -0
- package/src/application/ports/repositories/batch-repository.ts +86 -0
- package/src/application/ports/repositories/comment-repository.ts +150 -0
- package/src/application/ports/repositories/index.ts +41 -0
- package/src/application/ports/repositories/table-repository.ts +139 -0
- package/src/application/ports/services/css-compiler.ts +55 -0
- package/src/application/ports/services/index.ts +16 -0
- package/src/application/ports/services/page-renderer.ts +79 -0
- package/src/application/ports/services/server-factory.ts +80 -0
- package/src/application/ports/services/static-site-generator.ts +82 -0
- package/src/application/use-cases/activity/programs.ts +66 -0
- package/src/application/use-cases/analytics/collect-page-view.ts +114 -0
- package/src/application/use-cases/analytics/purge-old-data.ts +40 -0
- package/src/application/use-cases/analytics/query-campaigns.ts +43 -0
- package/src/application/use-cases/analytics/query-devices.ts +36 -0
- package/src/application/use-cases/analytics/query-overview.ts +50 -0
- package/src/application/use-cases/analytics/query-pages.ts +40 -0
- package/src/application/use-cases/analytics/query-referrers.ts +43 -0
- package/src/application/use-cases/analytics/ua-parser.ts +89 -0
- package/src/application/use-cases/analytics/visitor-hash.ts +77 -0
- package/src/application/use-cases/auth/bootstrap-admin.ts +270 -0
- package/src/application/use-cases/list-activity-logs.ts +123 -0
- package/src/application/use-cases/server/generate-static-helpers.ts +374 -0
- package/src/application/use-cases/server/generate-static.ts +287 -0
- package/src/application/use-cases/server/start-server.ts +118 -0
- package/src/application/use-cases/server/startup-error-handler.ts +69 -0
- package/src/application/use-cases/server/static-content-generators.ts +182 -0
- package/src/application/use-cases/server/static-language-generators.ts +181 -0
- package/src/application/use-cases/server/static-url-rewriter.ts +237 -0
- package/src/application/use-cases/server/translation-replacer.ts +164 -0
- package/src/application/use-cases/tables/activity-programs.ts +93 -0
- package/src/application/use-cases/tables/batch-operations.ts +156 -0
- package/src/application/use-cases/tables/comment-programs.ts +436 -0
- package/src/application/use-cases/tables/permissions/permissions.ts +25 -0
- package/src/application/use-cases/tables/programs.ts +435 -0
- package/src/application/use-cases/tables/table-operations.ts +412 -0
- package/src/application/use-cases/tables/user-role.ts +52 -0
- package/src/application/use-cases/tables/utils/display-formatter.ts +471 -0
- package/src/application/use-cases/tables/utils/field-read-filter.ts +189 -0
- package/src/application/use-cases/tables/utils/list-helpers.ts +122 -0
- package/src/application/use-cases/tables/utils/record-transformer.ts +319 -0
- package/src/cli.ts +370 -0
- package/src/domain/errors/create-tagged-error.ts +36 -0
- package/src/domain/errors/index.ts +78 -0
- package/src/domain/models/api/analytics.ts +179 -0
- package/src/domain/models/api/auth.ts +231 -0
- package/src/domain/models/api/common.ts +60 -0
- package/src/domain/models/api/error.ts +89 -0
- package/src/domain/models/api/health.ts +38 -0
- package/src/domain/models/api/index.ts +42 -0
- package/src/domain/models/api/request.ts +132 -0
- package/src/domain/models/api/tables.ts +444 -0
- package/src/domain/models/app/analytics/index.ts +129 -0
- package/src/domain/models/app/auth/config.ts +116 -0
- package/src/domain/models/app/auth/index.ts +230 -0
- package/src/domain/models/app/auth/methods/email-and-password.ts +67 -0
- package/src/domain/models/app/auth/methods/index.ts +11 -0
- package/src/domain/models/app/auth/methods/magic-link.ts +54 -0
- package/src/domain/models/app/auth/oauth/index.ts +8 -0
- package/src/domain/models/app/auth/oauth/providers.ts +105 -0
- package/src/domain/models/app/auth/plugins/admin.ts +130 -0
- package/src/domain/models/app/auth/plugins/index.ts +74 -0
- package/src/domain/models/app/auth/plugins/two-factor.ts +63 -0
- package/src/domain/models/app/auth/roles.ts +179 -0
- package/src/domain/models/app/auth/strategies.ts +191 -0
- package/src/domain/models/app/auth/validation.ts +127 -0
- package/src/domain/models/app/common/branded-ids.ts +200 -0
- package/src/domain/models/app/common/definitions.ts +187 -0
- package/src/domain/models/app/component/common/component-children.ts +119 -0
- package/src/domain/models/app/component/common/component-props.ts +89 -0
- package/src/domain/models/app/component/common/component-reference.ts +170 -0
- package/src/domain/models/app/component/component.ts +81 -0
- package/src/domain/models/app/components.ts +65 -0
- package/src/domain/models/app/description.ts +83 -0
- package/src/domain/models/app/index.ts +258 -0
- package/src/domain/models/app/language/language-config.ts +200 -0
- package/src/domain/models/app/languages.ts +205 -0
- package/src/domain/models/app/name.ts +66 -0
- package/src/domain/models/app/page/common/interactions/click-interaction.ts +116 -0
- package/src/domain/models/app/page/common/interactions/entrance-animation.ts +84 -0
- package/src/domain/models/app/page/common/interactions/hover-interaction.ts +144 -0
- package/src/domain/models/app/page/common/interactions/interactions.ts +64 -0
- package/src/domain/models/app/page/common/interactions/scroll-interaction.ts +93 -0
- package/src/domain/models/app/page/common/responsive.ts +114 -0
- package/src/domain/models/app/page/common/url.ts +35 -0
- package/src/domain/models/app/page/common/variable-reference.ts +53 -0
- package/src/domain/models/app/page/id.ts +44 -0
- package/src/domain/models/app/page/index.ts +270 -0
- package/src/domain/models/app/page/meta/analytics.ts +248 -0
- package/src/domain/models/app/page/meta/custom-elements.ts +180 -0
- package/src/domain/models/app/page/meta/dns-prefetch.ts +77 -0
- package/src/domain/models/app/page/meta/favicon-set.ts +203 -0
- package/src/domain/models/app/page/meta/favicon.ts +50 -0
- package/src/domain/models/app/page/meta/favicons-config.ts +73 -0
- package/src/domain/models/app/page/meta/index.ts +278 -0
- package/src/domain/models/app/page/meta/open-graph.ts +166 -0
- package/src/domain/models/app/page/meta/preload.ts +190 -0
- package/src/domain/models/app/page/meta/structured-data/article.ts +211 -0
- package/src/domain/models/app/page/meta/structured-data/breadcrumb.ts +115 -0
- package/src/domain/models/app/page/meta/structured-data/common-fields.ts +201 -0
- package/src/domain/models/app/page/meta/structured-data/education-event.ts +256 -0
- package/src/domain/models/app/page/meta/structured-data/faq-page.ts +127 -0
- package/src/domain/models/app/page/meta/structured-data/index.ts +95 -0
- package/src/domain/models/app/page/meta/structured-data/local-business.ts +247 -0
- package/src/domain/models/app/page/meta/structured-data/organization.ts +171 -0
- package/src/domain/models/app/page/meta/structured-data/person.ts +138 -0
- package/src/domain/models/app/page/meta/structured-data/postal-address.ts +106 -0
- package/src/domain/models/app/page/meta/structured-data/product.ts +214 -0
- package/src/domain/models/app/page/meta/twitter-card.ts +217 -0
- package/src/domain/models/app/page/name.ts +38 -0
- package/src/domain/models/app/page/path.ts +21 -0
- package/src/domain/models/app/page/scripts/external-scripts.ts +163 -0
- package/src/domain/models/app/page/scripts/features.ts +135 -0
- package/src/domain/models/app/page/scripts/inline-scripts.ts +114 -0
- package/src/domain/models/app/page/scripts/scripts.ts +102 -0
- package/src/domain/models/app/page/sections.ts +298 -0
- package/src/domain/models/app/pages.ts +61 -0
- package/src/domain/models/app/permissions/index.ts +61 -0
- package/src/domain/models/app/permissions/resource-action.ts +114 -0
- package/src/domain/models/app/permissions/roles.ts +120 -0
- package/src/domain/models/app/table/check-constraints.ts +105 -0
- package/src/domain/models/app/table/cycle-detection.ts +124 -0
- package/src/domain/models/app/table/database-identifier.ts +153 -0
- package/src/domain/models/app/table/field-name.ts +36 -0
- package/src/domain/models/app/table/field-types/advanced/array-field.ts +33 -0
- package/src/domain/models/app/table/field-types/advanced/autonumber-field.ts +54 -0
- package/src/domain/models/app/table/field-types/advanced/button-field.ts +56 -0
- package/src/domain/models/app/table/field-types/advanced/color-field.ts +57 -0
- package/src/domain/models/app/table/field-types/advanced/count-field.ts +54 -0
- package/src/domain/models/app/table/field-types/advanced/formula-field.ts +58 -0
- package/src/domain/models/app/table/field-types/advanced/geolocation-field.ts +49 -0
- package/src/domain/models/app/table/field-types/advanced/index.ts +16 -0
- package/src/domain/models/app/table/field-types/advanced/json-field.ts +25 -0
- package/src/domain/models/app/table/field-types/advanced/unknown-field.ts +85 -0
- package/src/domain/models/app/table/field-types/base-field.ts +42 -0
- package/src/domain/models/app/table/field-types/date-time/created-at-field.ts +49 -0
- package/src/domain/models/app/table/field-types/date-time/date-field.ts +95 -0
- package/src/domain/models/app/table/field-types/date-time/deleted-at-field.ts +56 -0
- package/src/domain/models/app/table/field-types/date-time/duration-field.ts +73 -0
- package/src/domain/models/app/table/field-types/date-time/index.ts +12 -0
- package/src/domain/models/app/table/field-types/date-time/updated-at-field.ts +50 -0
- package/src/domain/models/app/table/field-types/index.ts +19 -0
- package/src/domain/models/app/table/field-types/media/barcode-field.ts +58 -0
- package/src/domain/models/app/table/field-types/media/index.ts +10 -0
- package/src/domain/models/app/table/field-types/media/multiple-attachments-field.ts +80 -0
- package/src/domain/models/app/table/field-types/media/single-attachment-field.ts +81 -0
- package/src/domain/models/app/table/field-types/numeric/currency-field.ts +144 -0
- package/src/domain/models/app/table/field-types/numeric/decimal-field.ts +113 -0
- package/src/domain/models/app/table/field-types/numeric/index.ts +13 -0
- package/src/domain/models/app/table/field-types/numeric/integer-field.ts +98 -0
- package/src/domain/models/app/table/field-types/numeric/percentage-field.ts +115 -0
- package/src/domain/models/app/table/field-types/numeric/progress-field.ts +71 -0
- package/src/domain/models/app/table/field-types/numeric/rating-field.ts +74 -0
- package/src/domain/models/app/table/field-types/relational/index.ts +10 -0
- package/src/domain/models/app/table/field-types/relational/lookup-field.ts +46 -0
- package/src/domain/models/app/table/field-types/relational/relationship-field.ts +112 -0
- package/src/domain/models/app/table/field-types/relational/rollup-field.ts +58 -0
- package/src/domain/models/app/table/field-types/selection/checkbox-field.ts +51 -0
- package/src/domain/models/app/table/field-types/selection/index.ts +11 -0
- package/src/domain/models/app/table/field-types/selection/multi-select-field.ts +68 -0
- package/src/domain/models/app/table/field-types/selection/single-select-field.ts +54 -0
- package/src/domain/models/app/table/field-types/selection/status-field.ts +37 -0
- package/src/domain/models/app/table/field-types/text/email-field.ts +80 -0
- package/src/domain/models/app/table/field-types/text/index.ts +13 -0
- package/src/domain/models/app/table/field-types/text/long-text-field.ts +77 -0
- package/src/domain/models/app/table/field-types/text/phone-number-field.ts +82 -0
- package/src/domain/models/app/table/field-types/text/rich-text-field.ts +66 -0
- package/src/domain/models/app/table/field-types/text/single-line-text-field.ts +79 -0
- package/src/domain/models/app/table/field-types/text/url-field.ts +81 -0
- package/src/domain/models/app/table/field-types/user/created-by-field.ts +50 -0
- package/src/domain/models/app/table/field-types/user/deleted-by-field.ts +57 -0
- package/src/domain/models/app/table/field-types/user/index.ts +11 -0
- package/src/domain/models/app/table/field-types/user/updated-by-field.ts +51 -0
- package/src/domain/models/app/table/field-types/user/user-field.ts +52 -0
- package/src/domain/models/app/table/field-types/validation-utils.ts +166 -0
- package/src/domain/models/app/table/fields.ts +216 -0
- package/src/domain/models/app/table/foreign-keys.ts +111 -0
- package/src/domain/models/app/table/formula-keywords.ts +326 -0
- package/src/domain/models/app/table/id.ts +31 -0
- package/src/domain/models/app/table/index.ts +290 -0
- package/src/domain/models/app/table/indexes.ts +80 -0
- package/src/domain/models/app/table/name.ts +37 -0
- package/src/domain/models/app/table/permissions/field-permission.ts +83 -0
- package/src/domain/models/app/table/permissions/index.ts +167 -0
- package/src/domain/models/app/table/permissions/permission-evaluator.ts +372 -0
- package/src/domain/models/app/table/permissions/permission.ts +49 -0
- package/src/domain/models/app/table/primary-key.ts +62 -0
- package/src/domain/models/app/table/table-formula-validation.ts +168 -0
- package/src/domain/models/app/table/table-indexes-validation.ts +38 -0
- package/src/domain/models/app/table/table-permissions-validation.ts +77 -0
- package/src/domain/models/app/table/table-primary-key-validation.ts +49 -0
- package/src/domain/models/app/table/table-views-validation.ts +408 -0
- package/src/domain/models/app/table/unique-constraints.ts +79 -0
- package/src/domain/models/app/table/views/fields.ts +28 -0
- package/src/domain/models/app/table/views/filters.ts +162 -0
- package/src/domain/models/app/table/views/group-by.ts +32 -0
- package/src/domain/models/app/table/views/id.ts +50 -0
- package/src/domain/models/app/table/views/index.ts +177 -0
- package/src/domain/models/app/table/views/name.ts +32 -0
- package/src/domain/models/app/table/views/permissions.ts +98 -0
- package/src/domain/models/app/table/views/sorts.ts +31 -0
- package/src/domain/models/app/tables.ts +695 -0
- package/src/domain/models/app/theme/animations.ts +208 -0
- package/src/domain/models/app/theme/border-radius.ts +58 -0
- package/src/domain/models/app/theme/breakpoints.ts +62 -0
- package/src/domain/models/app/theme/colors.ts +110 -0
- package/src/domain/models/app/theme/fonts.ts +164 -0
- package/src/domain/models/app/theme/shadows.ts +61 -0
- package/src/domain/models/app/theme/spacing.ts +115 -0
- package/src/domain/models/app/theme.ts +66 -0
- package/src/domain/models/app/version.ts +87 -0
- package/src/domain/models/record-comment.ts +91 -0
- package/src/domain/utils/content-parsing.ts +49 -0
- package/src/domain/utils/format-detection.ts +69 -0
- package/src/domain/utils/index.ts +9 -0
- package/src/domain/utils/route-matcher.ts +184 -0
- package/src/domain/utils/translation-resolver.ts +170 -0
- package/src/index.ts +208 -0
- package/src/infrastructure/analytics/tracking-script.ts +48 -0
- package/src/infrastructure/auth/better-auth/auth.ts +216 -0
- package/src/infrastructure/auth/better-auth/email-handlers.ts +162 -0
- package/src/infrastructure/auth/better-auth/index.ts +16 -0
- package/src/infrastructure/auth/better-auth/layer.ts +97 -0
- package/src/infrastructure/auth/better-auth/plugins/admin.ts +56 -0
- package/src/infrastructure/auth/better-auth/plugins/magic-link.ts +31 -0
- package/src/infrastructure/auth/better-auth/plugins/two-factor.ts +19 -0
- package/src/infrastructure/auth/better-auth/schema.ts +152 -0
- package/src/infrastructure/auth/index.ts +27 -0
- package/src/infrastructure/css/cache/css-cache-service.ts +130 -0
- package/src/infrastructure/css/compiler.ts +210 -0
- package/src/infrastructure/css/css-compiler-live.ts +20 -0
- package/src/infrastructure/css/index.ts +25 -0
- package/src/infrastructure/css/styles/animation-styles-generator.ts +177 -0
- package/src/infrastructure/css/styles/click-animations.ts +147 -0
- package/src/infrastructure/css/styles/component-layer-generators.ts +147 -0
- package/src/infrastructure/css/theme/theme-generators.ts +130 -0
- package/src/infrastructure/css/theme/theme-layer-generators.ts +219 -0
- package/src/infrastructure/css/theme/theme-token-resolver.ts +76 -0
- package/src/infrastructure/database/activity-queries.ts +111 -0
- package/src/infrastructure/database/auth/auth-validation.ts +101 -0
- package/src/infrastructure/database/drizzle/db-bun.ts +17 -0
- package/src/infrastructure/database/drizzle/db.ts +17 -0
- package/src/infrastructure/database/drizzle/index.ts +16 -0
- package/src/infrastructure/database/drizzle/layer.ts +34 -0
- package/src/infrastructure/database/drizzle/migrate.ts +77 -0
- package/src/infrastructure/database/drizzle/schema/activity-log.ts +111 -0
- package/src/infrastructure/database/drizzle/schema/analytics-page-views.ts +116 -0
- package/src/infrastructure/database/drizzle/schema/migration-audit.ts +68 -0
- package/src/infrastructure/database/drizzle/schema/record-comments.ts +79 -0
- package/src/infrastructure/database/drizzle/schema.ts +12 -0
- package/src/infrastructure/database/field-utils.ts +87 -0
- package/src/infrastructure/database/filter-operators.ts +136 -0
- package/src/infrastructure/database/formula/formula-trigger-generators.ts +114 -0
- package/src/infrastructure/database/formula/formula-utils.ts +440 -0
- package/src/infrastructure/database/generators/index-generators.ts +152 -0
- package/src/infrastructure/database/generators/trigger-generators.ts +154 -0
- package/src/infrastructure/database/index.ts +35 -0
- package/src/infrastructure/database/lookup/lookup-expression-generators.ts +356 -0
- package/src/infrastructure/database/lookup/lookup-expressions.ts +116 -0
- package/src/infrastructure/database/lookup/lookup-view-generators.ts +403 -0
- package/src/infrastructure/database/lookup/lookup-view-helpers.ts +65 -0
- package/src/infrastructure/database/lookup/lookup-view-triggers.ts +121 -0
- package/src/infrastructure/database/migration-audit-trail.ts +375 -0
- package/src/infrastructure/database/repositories/activity-log-repository-live.ts +99 -0
- package/src/infrastructure/database/repositories/activity-repository-live.ts +21 -0
- package/src/infrastructure/database/repositories/analytics-repository-live.ts +316 -0
- package/src/infrastructure/database/repositories/auth-repository-live.ts +42 -0
- package/src/infrastructure/database/repositories/batch-repository-live.ts +29 -0
- package/src/infrastructure/database/repositories/comment-repository-live.ts +39 -0
- package/src/infrastructure/database/repositories/table-repository-live.ts +38 -0
- package/src/infrastructure/database/schema/schema-dependency-sorting.ts +142 -0
- package/src/infrastructure/database/schema/schema-initializer.ts +598 -0
- package/src/infrastructure/database/schema-migration/column-detection.ts +286 -0
- package/src/infrastructure/database/schema-migration/constants.ts +31 -0
- package/src/infrastructure/database/schema-migration/constraint-sync.ts +288 -0
- package/src/infrastructure/database/schema-migration/index-sync.ts +108 -0
- package/src/infrastructure/database/schema-migration/index.ts +66 -0
- package/src/infrastructure/database/schema-migration/migration-statements.ts +106 -0
- package/src/infrastructure/database/schema-migration/rename-detection.ts +87 -0
- package/src/infrastructure/database/schema-migration/table-operations.ts +65 -0
- package/src/infrastructure/database/schema-migration/type-utils.ts +98 -0
- package/src/infrastructure/database/schema-migration/types.ts +14 -0
- package/src/infrastructure/database/schema-migration-helpers.ts +53 -0
- package/src/infrastructure/database/session-context.ts +20 -0
- package/src/infrastructure/database/sql/sql-check-constraints.ts +252 -0
- package/src/infrastructure/database/sql/sql-column-generators.ts +174 -0
- package/src/infrastructure/database/sql/sql-execution.ts +245 -0
- package/src/infrastructure/database/sql/sql-field-predicates.ts +81 -0
- package/src/infrastructure/database/sql/sql-generators.ts +91 -0
- package/src/infrastructure/database/sql/sql-junction-tables.ts +79 -0
- package/src/infrastructure/database/sql/sql-key-constraints.ts +210 -0
- package/src/infrastructure/database/sql/sql-type-mappings.ts +106 -0
- package/src/infrastructure/database/sql/sql-utils.ts +53 -0
- package/src/infrastructure/database/table-live-layers.ts +30 -0
- package/src/infrastructure/database/table-operations/column-generators.ts +82 -0
- package/src/infrastructure/database/table-operations/create-table-sql.ts +81 -0
- package/src/infrastructure/database/table-operations/index.ts +55 -0
- package/src/infrastructure/database/table-operations/migration-utils.ts +157 -0
- package/src/infrastructure/database/table-operations/table-effects.ts +234 -0
- package/src/infrastructure/database/table-operations/table-features.ts +96 -0
- package/src/infrastructure/database/table-operations/type-compatibility.ts +58 -0
- package/src/infrastructure/database/table-operations.ts +47 -0
- package/src/infrastructure/database/table-queries/batch/batch-create.ts +80 -0
- package/src/infrastructure/database/table-queries/batch/batch-delete.ts +212 -0
- package/src/infrastructure/database/table-queries/batch/batch-helpers.ts +124 -0
- package/src/infrastructure/database/table-queries/batch/batch-restore.ts +161 -0
- package/src/infrastructure/database/table-queries/batch/batch-update.ts +146 -0
- package/src/infrastructure/database/table-queries/batch/batch-upsert.ts +357 -0
- package/src/infrastructure/database/table-queries/batch/batch.ts +14 -0
- package/src/infrastructure/database/table-queries/crud/crud-read.ts +351 -0
- package/src/infrastructure/database/table-queries/crud/crud-write.ts +399 -0
- package/src/infrastructure/database/table-queries/crud/crud.ts +16 -0
- package/src/infrastructure/database/table-queries/index.ts +11 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/authorship-helpers.ts +152 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/create-record-helpers.ts +90 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/delete-helpers.ts +163 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/record-fetch-helpers.ts +79 -0
- package/src/infrastructure/database/table-queries/mutation-helpers/update-helpers.ts +74 -0
- package/src/infrastructure/database/table-queries/query-helpers/activity-log-helpers.ts +53 -0
- package/src/infrastructure/database/table-queries/query-helpers/activity-queries.ts +106 -0
- package/src/infrastructure/database/table-queries/query-helpers/aggregation-helpers.ts +314 -0
- package/src/infrastructure/database/table-queries/query-helpers/comment-queries.ts +414 -0
- package/src/infrastructure/database/table-queries/query-helpers/record-validation-queries.ts +126 -0
- package/src/infrastructure/database/table-queries/query-helpers/trash-helpers.ts +58 -0
- package/src/infrastructure/database/table-queries/shared/error-handling.ts +47 -0
- package/src/infrastructure/database/table-queries/shared/typed-execute.ts +27 -0
- package/src/infrastructure/database/table-queries/shared/user-join-helpers.ts +38 -0
- package/src/infrastructure/database/table-queries/shared/validation.ts +39 -0
- package/src/infrastructure/database/views/view-generators.ts +258 -0
- package/src/infrastructure/devtools/devtools-layer.ts +43 -0
- package/src/infrastructure/devtools/index.ts +8 -0
- package/src/infrastructure/email/email-config.ts +103 -0
- package/src/infrastructure/email/email-service.ts +152 -0
- package/src/infrastructure/email/index.ts +107 -0
- package/src/infrastructure/email/nodemailer.ts +125 -0
- package/src/infrastructure/email/templates.ts +244 -0
- package/src/infrastructure/errors/auth-config-required-error.ts +21 -0
- package/src/infrastructure/errors/auth-error.ts +16 -0
- package/src/infrastructure/errors/css-compilation-error.ts +14 -0
- package/src/infrastructure/errors/index.ts +26 -0
- package/src/infrastructure/errors/schema-initialization-error.ts +19 -0
- package/src/infrastructure/errors/server-creation-error.ts +14 -0
- package/src/infrastructure/filesystem/copy-directory.ts +136 -0
- package/src/infrastructure/layers/app-layer.ts +61 -0
- package/src/infrastructure/layers/page-renderer-layer.ts +41 -0
- package/src/infrastructure/logging/index.ts +8 -0
- package/src/infrastructure/logging/logger.ts +204 -0
- package/src/infrastructure/schema/file-loader.ts +53 -0
- package/src/infrastructure/schema/index.ts +15 -0
- package/src/infrastructure/schema/remote-loader.ts +48 -0
- package/src/infrastructure/server/index.ts +26 -0
- package/src/infrastructure/server/language-detection.ts +87 -0
- package/src/infrastructure/server/lifecycle.ts +67 -0
- package/src/infrastructure/server/route-setup/api-routes.ts +310 -0
- package/src/infrastructure/server/route-setup/auth-route-utils.ts +399 -0
- package/src/infrastructure/server/route-setup/auth-routes.ts +245 -0
- package/src/infrastructure/server/route-setup/openapi-routes.ts +45 -0
- package/src/infrastructure/server/route-setup/openapi-schema.ts +120 -0
- package/src/infrastructure/server/route-setup/page-routes.ts +219 -0
- package/src/infrastructure/server/route-setup/static-assets.ts +191 -0
- package/src/infrastructure/server/server-factory-live.ts +45 -0
- package/src/infrastructure/server/server.ts +275 -0
- package/src/infrastructure/server/ssg-adapter.ts +196 -0
- package/src/infrastructure/server/static-site-generator-live.ts +20 -0
- package/src/infrastructure/utils/accept-language-parser.ts +106 -0
- package/src/infrastructure/utils/glob-matcher.ts +50 -0
- package/src/presentation/api/client.ts +114 -0
- package/src/presentation/api/middleware/auth.ts +233 -0
- package/src/presentation/api/middleware/table.ts +155 -0
- package/src/presentation/api/middleware/validation.ts +88 -0
- package/src/presentation/api/routes/activity/get-activity-by-id-handler.ts +77 -0
- package/src/presentation/api/routes/activity/index.ts +28 -0
- package/src/presentation/api/routes/activity.ts +339 -0
- package/src/presentation/api/routes/analytics.ts +328 -0
- package/src/presentation/api/routes/auth.ts +169 -0
- package/src/presentation/api/routes/index.ts +11 -0
- package/src/presentation/api/routes/tables/activity-handlers.ts +57 -0
- package/src/presentation/api/routes/tables/batch-permission-helpers.ts +163 -0
- package/src/presentation/api/routes/tables/batch-routes.ts +355 -0
- package/src/presentation/api/routes/tables/comment-handlers.ts +377 -0
- package/src/presentation/api/routes/tables/create-record-helpers.ts +179 -0
- package/src/presentation/api/routes/tables/effect-runner.ts +58 -0
- package/src/presentation/api/routes/tables/error-handlers.ts +53 -0
- package/src/presentation/api/routes/tables/field-permission-validation.ts +167 -0
- package/src/presentation/api/routes/tables/filter-parser.ts +75 -0
- package/src/presentation/api/routes/tables/formula-parser.ts +118 -0
- package/src/presentation/api/routes/tables/index.ts +113 -0
- package/src/presentation/api/routes/tables/list-records-filter.ts +54 -0
- package/src/presentation/api/routes/tables/param-parsers.ts +59 -0
- package/src/presentation/api/routes/tables/record-handlers.ts +484 -0
- package/src/presentation/api/routes/tables/record-routes.ts +53 -0
- package/src/presentation/api/routes/tables/record-update-handler.ts +200 -0
- package/src/presentation/api/routes/tables/sort-validation.ts +85 -0
- package/src/presentation/api/routes/tables/table-routes.ts +76 -0
- package/src/presentation/api/routes/tables/timezone-validation.ts +41 -0
- package/src/presentation/api/routes/tables/upsert-helpers.ts +471 -0
- package/src/presentation/api/routes/tables/utils.ts +159 -0
- package/src/presentation/api/routes/tables/view-routes.ts +51 -0
- package/src/presentation/api/routes/tables.ts +9 -0
- package/src/presentation/api/utils/context-helpers.ts +43 -0
- package/src/presentation/api/utils/error-sanitizer.ts +235 -0
- package/src/presentation/api/utils/field-permission-validator.ts +53 -0
- package/src/presentation/api/utils/filter-field-validator.ts +90 -0
- package/src/presentation/api/utils/index.ts +13 -0
- package/src/presentation/api/utils/run-effect.ts +94 -0
- package/src/presentation/api/utils/validate-request.ts +89 -0
- package/src/presentation/api/validation/index.ts +29 -0
- package/src/presentation/api/validation/rules/field-rules.ts +158 -0
- package/src/presentation/api/validation/rules/record-rules.ts +73 -0
- package/src/presentation/cli/index.ts +19 -0
- package/src/presentation/cli/schema-loader.ts +172 -0
- package/src/presentation/hooks/use-breakpoint.ts +155 -0
- package/src/presentation/rendering/render-error-pages.tsx +60 -0
- package/src/presentation/rendering/render-homepage.tsx +137 -0
- package/src/presentation/scripts/script-renderers.ts +112 -0
- package/src/presentation/styling/animation-composer.ts +117 -0
- package/src/presentation/styling/index.ts +13 -0
- package/src/presentation/styling/parse-style.ts +243 -0
- package/src/presentation/styling/style-utils.ts +50 -0
- package/src/presentation/styling/theme-colors.ts +53 -0
- package/src/presentation/translations/component-utils.ts +54 -0
- package/src/presentation/translations/index.ts +16 -0
- package/src/presentation/translations/translation-resolver.ts +22 -0
- package/src/presentation/ui/languages/language-switcher.tsx +119 -0
- package/src/presentation/ui/metadata/analytics-builders.tsx +174 -0
- package/src/presentation/ui/metadata/analytics-head.tsx +39 -0
- package/src/presentation/ui/metadata/custom-elements-builders.tsx +157 -0
- package/src/presentation/ui/metadata/extract-component-meta.ts +108 -0
- package/src/presentation/ui/metadata/head-elements.tsx +164 -0
- package/src/presentation/ui/metadata/index.tsx +35 -0
- package/src/presentation/ui/metadata/meta-utils.tsx +42 -0
- package/src/presentation/ui/metadata/open-graph-meta.tsx +57 -0
- package/src/presentation/ui/metadata/structured-data-from-component.tsx +134 -0
- package/src/presentation/ui/metadata/structured-data.tsx +88 -0
- package/src/presentation/ui/metadata/twitter-card-meta.tsx +80 -0
- package/src/presentation/ui/pages/DefaultHomePage.tsx +43 -0
- package/src/presentation/ui/pages/DefaultPageConfigs.ts +220 -0
- package/src/presentation/ui/pages/DynamicPage.tsx +307 -0
- package/src/presentation/ui/pages/ErrorPage.tsx +25 -0
- package/src/presentation/ui/pages/NotFoundPage.tsx +25 -0
- package/src/presentation/ui/pages/PageBodyScripts.tsx +242 -0
- package/src/presentation/ui/pages/PageBodyStyles.ts +52 -0
- package/src/presentation/ui/pages/PageHead.tsx +380 -0
- package/src/presentation/ui/pages/PageLangResolver.ts +58 -0
- package/src/presentation/ui/pages/PageMain.tsx +58 -0
- package/src/presentation/ui/pages/PageMetadata.ts +168 -0
- package/src/presentation/ui/pages/PageMetadataI18n.ts +169 -0
- package/src/presentation/ui/pages/PageScripts.ts +78 -0
- package/src/presentation/ui/pages/SectionRenderer.tsx +67 -0
- package/src/presentation/ui/pages/SectionSpacing.tsx +131 -0
- package/src/presentation/ui/sections/component-renderer.tsx +426 -0
- package/src/presentation/ui/sections/component-renderer.types.ts +33 -0
- package/src/presentation/ui/sections/components/component-reference-handler.tsx +74 -0
- package/src/presentation/ui/sections/components/component-resolution.ts +65 -0
- package/src/presentation/ui/sections/components/index.ts +9 -0
- package/src/presentation/ui/sections/hero.tsx +394 -0
- package/src/presentation/ui/sections/props/component-builder.ts +183 -0
- package/src/presentation/ui/sections/props/element-props.ts +179 -0
- package/src/presentation/ui/sections/props/index.ts +9 -0
- package/src/presentation/ui/sections/props/prop-conversion.ts +171 -0
- package/src/presentation/ui/sections/props/props-builder-config.ts +42 -0
- package/src/presentation/ui/sections/props/props-builder.ts +296 -0
- package/src/presentation/ui/sections/renderers/element-renderers/html-element-renderer.tsx +124 -0
- package/src/presentation/ui/sections/renderers/element-renderers/index.ts +59 -0
- package/src/presentation/ui/sections/renderers/element-renderers/interactive-renderers.tsx +231 -0
- package/src/presentation/ui/sections/renderers/element-renderers/media-renderers.tsx +102 -0
- package/src/presentation/ui/sections/renderers/element-renderers/text-content-renderers.tsx +42 -0
- package/src/presentation/ui/sections/renderers/element-renderers.ts +53 -0
- package/src/presentation/ui/sections/renderers/html-element-helpers.ts +100 -0
- package/src/presentation/ui/sections/renderers/specialized-renderers.tsx +212 -0
- package/src/presentation/ui/sections/rendering/component-dispatch-config.ts +31 -0
- package/src/presentation/ui/sections/rendering/component-registry/index.ts +39 -0
- package/src/presentation/ui/sections/rendering/component-registry/interactive-components.ts +54 -0
- package/src/presentation/ui/sections/rendering/component-registry/media-components.ts +36 -0
- package/src/presentation/ui/sections/rendering/component-registry/special-components.tsx +153 -0
- package/src/presentation/ui/sections/rendering/component-registry/structural-components.ts +215 -0
- package/src/presentation/ui/sections/rendering/component-registry/text-components.ts +57 -0
- package/src/presentation/ui/sections/rendering/component-registry-helpers.tsx +29 -0
- package/src/presentation/ui/sections/rendering/component-registry.tsx +21 -0
- package/src/presentation/ui/sections/rendering/component-type-dispatcher.tsx +33 -0
- package/src/presentation/ui/sections/rendering/index.ts +9 -0
- package/src/presentation/ui/sections/responsive/responsive-children-builder.tsx +96 -0
- package/src/presentation/ui/sections/responsive/responsive-content-builder.tsx +95 -0
- package/src/presentation/ui/sections/responsive/responsive-props-merger.ts +195 -0
- package/src/presentation/ui/sections/responsive/responsive-resolver.ts +213 -0
- package/src/presentation/ui/sections/styling/animation-composer-wrapper.ts +65 -0
- package/src/presentation/ui/sections/styling/class-builders.ts +45 -0
- package/src/presentation/ui/sections/styling/color-resolver.ts +43 -0
- package/src/presentation/ui/sections/styling/hover-interaction-handler.ts +107 -0
- package/src/presentation/ui/sections/styling/index.ts +9 -0
- package/src/presentation/ui/sections/styling/interaction-props-builder.ts +55 -0
- package/src/presentation/ui/sections/styling/shadow-resolver.ts +83 -0
- package/src/presentation/ui/sections/styling/spacing-resolver.ts +104 -0
- package/src/presentation/ui/sections/styling/style-processor.ts +170 -0
- package/src/presentation/ui/sections/styling/theme-tokens.ts +184 -0
- package/src/presentation/ui/sections/translations/i18n-content-resolver.ts +198 -0
- package/src/presentation/ui/sections/translations/index.ts +9 -0
- package/src/presentation/ui/sections/translations/translation-handler.ts +143 -0
- package/src/presentation/ui/sections/translations/variable-substitution.ts +225 -0
- package/src/presentation/ui/sections/utils/time-parser.ts +82 -0
- package/src/presentation/utils/link-attributes.ts +50 -0
- package/src/presentation/utils/string-utils.ts +58 -0
- package/src/presentation/utils/styles.ts +50 -0
- package/tsconfig.json +46 -0
|
@@ -0,0 +1,120 @@
|
|
|
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 { OpenAPIHono, createRoute } from '@hono/zod-openapi'
|
|
9
|
+
import { healthResponseSchema } from '@/domain/models/api/health'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* OpenAPI Schema Generator
|
|
13
|
+
*
|
|
14
|
+
* This file creates a parallel OpenAPI schema using OpenAPIHono.
|
|
15
|
+
* **Important**: This is separate from the runtime API routes.
|
|
16
|
+
*
|
|
17
|
+
* Located in Infrastructure layer because schema generation is an
|
|
18
|
+
* infrastructure concern (documentation/tooling), not presentation logic.
|
|
19
|
+
*
|
|
20
|
+
* **Why Separate?**
|
|
21
|
+
* - Runtime routes use regular Hono (for RPC compatibility with `:id` syntax)
|
|
22
|
+
* - OpenAPI schema uses OpenAPIHono (for documentation with `{id}` syntax)
|
|
23
|
+
* - Both share the same Zod schemas for consistency
|
|
24
|
+
*
|
|
25
|
+
* **Usage**:
|
|
26
|
+
* 1. Runtime: Server uses regular Hono routes from api-routes.ts
|
|
27
|
+
* 2. Docs: Server exposes this schema at `/api/openapi.json` and `/api/scalar`
|
|
28
|
+
* 3. Export: Script exports this schema to `schemas/0.0.1/app.openapi.json`
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create OpenAPI Hono app with all routes
|
|
33
|
+
*
|
|
34
|
+
* This function defines all API routes using OpenAPI syntax for documentation.
|
|
35
|
+
* The routes here are "dummy" implementations - they're only used to generate
|
|
36
|
+
* the OpenAPI schema. The real implementations are in api-routes.ts.
|
|
37
|
+
*/
|
|
38
|
+
const createOpenApiApp = () => {
|
|
39
|
+
const app = new OpenAPIHono()
|
|
40
|
+
|
|
41
|
+
// Define health check route with OpenAPI annotations
|
|
42
|
+
const healthRoute = createRoute({
|
|
43
|
+
method: 'get',
|
|
44
|
+
path: '/api/health',
|
|
45
|
+
summary: 'Health check endpoint',
|
|
46
|
+
description:
|
|
47
|
+
'Returns server health status. Used by monitoring tools and E2E tests to verify server is running.',
|
|
48
|
+
operationId: 'healthCheck',
|
|
49
|
+
tags: ['infrastructure'],
|
|
50
|
+
responses: {
|
|
51
|
+
200: {
|
|
52
|
+
content: {
|
|
53
|
+
'application/json': {
|
|
54
|
+
schema: healthResponseSchema,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
description: 'Server is healthy',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Mount route with dummy handler (only for schema generation)
|
|
63
|
+
|
|
64
|
+
app.openapi(healthRoute, (c) => {
|
|
65
|
+
return c.json({
|
|
66
|
+
status: 'ok',
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
app: {
|
|
69
|
+
name: 'Sovrium',
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Future routes will be added here:
|
|
75
|
+
// app.openapi(listTablesRoute, ...)
|
|
76
|
+
// app.openapi(getTableRoute, ...)
|
|
77
|
+
|
|
78
|
+
return app
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get OpenAPI document as JSON
|
|
83
|
+
*
|
|
84
|
+
* This function generates the complete OpenAPI specification document.
|
|
85
|
+
* It's used by:
|
|
86
|
+
* - `/api/openapi.json` endpoint (runtime documentation)
|
|
87
|
+
* - `/api/scalar` endpoint (Scalar UI)
|
|
88
|
+
* - `scripts/export-openapi.ts` (export to schemas/ folder)
|
|
89
|
+
*
|
|
90
|
+
* @returns OpenAPI 3.1.0 specification document
|
|
91
|
+
*/
|
|
92
|
+
export const getOpenAPIDocument = () => {
|
|
93
|
+
const app = createOpenApiApp()
|
|
94
|
+
|
|
95
|
+
return app.getOpenAPIDocument({
|
|
96
|
+
openapi: '3.1.0',
|
|
97
|
+
info: {
|
|
98
|
+
title: 'Sovrium API',
|
|
99
|
+
version: '0.0.1',
|
|
100
|
+
description:
|
|
101
|
+
'REST API specification for Sovrium application.\n\n' +
|
|
102
|
+
'**Generated Schema**: This schema is automatically generated from the runtime implementation. ' +
|
|
103
|
+
'It reflects the currently implemented endpoints and their schemas.\n\n' +
|
|
104
|
+
'**Design Specs**: Hand-written OpenAPI specs in `docs/specifications/app/` define the complete API design. ' +
|
|
105
|
+
'Comparing this generated schema with the design specs shows implementation progress.',
|
|
106
|
+
},
|
|
107
|
+
servers: [
|
|
108
|
+
{
|
|
109
|
+
url: 'http://localhost:3000',
|
|
110
|
+
description: 'Development server',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
tags: [
|
|
114
|
+
{
|
|
115
|
+
name: 'infrastructure',
|
|
116
|
+
description: 'Infrastructure endpoints (health, metrics)',
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
})
|
|
120
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Console, Effect } from 'effect'
|
|
9
|
+
import { type Context, type Hono } from 'hono'
|
|
10
|
+
import {
|
|
11
|
+
detectLanguageIfEnabled,
|
|
12
|
+
validateLanguageSubdirectory,
|
|
13
|
+
} from '@/infrastructure/server/language-detection'
|
|
14
|
+
import type { App } from '@/domain/models/app'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Hono app configuration for route setup
|
|
18
|
+
*/
|
|
19
|
+
export interface HonoAppConfig {
|
|
20
|
+
readonly app: App
|
|
21
|
+
readonly publicDir?: string
|
|
22
|
+
readonly renderHomePage: (app: App, detectedLanguage?: string) => string
|
|
23
|
+
readonly renderPage: (app: App, path: string, detectedLanguage?: string) => string | undefined
|
|
24
|
+
readonly renderNotFoundPage: (app?: App, detectedLanguage?: string) => string
|
|
25
|
+
readonly renderErrorPage: (app?: App, detectedLanguage?: string) => string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Setup homepage route
|
|
30
|
+
*
|
|
31
|
+
* Handles:
|
|
32
|
+
* - No languages configured: Serve default
|
|
33
|
+
* - Browser detection disabled: Serve default
|
|
34
|
+
* - Browser detection enabled: Detect and redirect if needed
|
|
35
|
+
*
|
|
36
|
+
* @param honoApp - Hono application instance
|
|
37
|
+
* @param config - Route configuration
|
|
38
|
+
* @returns Hono app with homepage route configured
|
|
39
|
+
*/
|
|
40
|
+
export function setupHomepageRoute(honoApp: Readonly<Hono>, config: HonoAppConfig): Readonly<Hono> {
|
|
41
|
+
const { app, renderHomePage, renderErrorPage } = config
|
|
42
|
+
|
|
43
|
+
return honoApp.get('/', (c) => {
|
|
44
|
+
try {
|
|
45
|
+
// If no languages configured, render with default (en-US)
|
|
46
|
+
if (!app.languages) {
|
|
47
|
+
const html = renderHomePage(app, undefined)
|
|
48
|
+
return c.html(html)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If browser detection disabled, always serve default language at /
|
|
52
|
+
if (app.languages.detectBrowser === false) {
|
|
53
|
+
const html = renderHomePage(app, undefined)
|
|
54
|
+
return c.html(html)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Browser detection enabled - detect language from Accept-Language header
|
|
58
|
+
const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
59
|
+
const targetLanguage = detectedLanguage || app.languages.default
|
|
60
|
+
|
|
61
|
+
// Only redirect if detected language is different from default
|
|
62
|
+
if (targetLanguage !== app.languages.default) {
|
|
63
|
+
return c.redirect(`/${targetLanguage}/`, 302)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Same as default - serve at / (no redirect, cacheable)
|
|
67
|
+
const html = renderHomePage(app, undefined)
|
|
68
|
+
return c.html(html)
|
|
69
|
+
} catch (error) {
|
|
70
|
+
Effect.runSync(Console.error('Error rendering homepage:', error))
|
|
71
|
+
return c.html(renderErrorPage(app), 500)
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Handle /:lang/ route (homepage in specific language)
|
|
78
|
+
*/
|
|
79
|
+
function handleLanguageHomepageRoute(config: HonoAppConfig) {
|
|
80
|
+
const { app, renderHomePage, renderPage, renderNotFoundPage, renderErrorPage } = config
|
|
81
|
+
return (c: Readonly<Context>) => {
|
|
82
|
+
try {
|
|
83
|
+
const { path } = c.req
|
|
84
|
+
const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
85
|
+
const exactPageMatch = renderPage(app, path, detectedLanguage)
|
|
86
|
+
if (exactPageMatch) {
|
|
87
|
+
return c.html(exactPageMatch)
|
|
88
|
+
}
|
|
89
|
+
const urlLanguage = validateLanguageSubdirectory(app, path)
|
|
90
|
+
if (!urlLanguage) {
|
|
91
|
+
const detectedLang = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
92
|
+
return c.html(renderNotFoundPage(app, detectedLang), 404)
|
|
93
|
+
}
|
|
94
|
+
const html = renderHomePage(app, urlLanguage)
|
|
95
|
+
return c.html(html)
|
|
96
|
+
} catch (error) {
|
|
97
|
+
Effect.runSync(Console.error('Error rendering homepage:', error))
|
|
98
|
+
const detectedLang = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
99
|
+
return c.html(renderErrorPage(app, detectedLang), 500)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Handle /:lang/* route (pages in specific language)
|
|
106
|
+
*/
|
|
107
|
+
function handleLanguagePageRoute(config: HonoAppConfig) {
|
|
108
|
+
const { app, renderPage, renderNotFoundPage, renderErrorPage } = config
|
|
109
|
+
return (c: Readonly<Context>) => {
|
|
110
|
+
const { path } = c.req
|
|
111
|
+
const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
112
|
+
try {
|
|
113
|
+
const exactPageMatch = renderPage(app, path, detectedLanguage)
|
|
114
|
+
if (exactPageMatch) {
|
|
115
|
+
return c.html(exactPageMatch)
|
|
116
|
+
}
|
|
117
|
+
const urlLanguage = validateLanguageSubdirectory(app, path)
|
|
118
|
+
if (!urlLanguage) {
|
|
119
|
+
return c.html(renderNotFoundPage(app, detectedLanguage), 404)
|
|
120
|
+
}
|
|
121
|
+
const pathWithoutLang = path.replace(`/${urlLanguage}`, '') || '/'
|
|
122
|
+
const html = renderPage(app, pathWithoutLang, urlLanguage)
|
|
123
|
+
if (!html) {
|
|
124
|
+
return c.html(renderNotFoundPage(app, urlLanguage), 404)
|
|
125
|
+
}
|
|
126
|
+
return c.html(html)
|
|
127
|
+
} catch (error) {
|
|
128
|
+
Effect.runSync(Console.error('Error rendering page:', error))
|
|
129
|
+
return c.html(renderErrorPage(app, detectedLanguage), 500)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Setup language subdirectory routes
|
|
136
|
+
*
|
|
137
|
+
* Handles:
|
|
138
|
+
* - GET /:lang/ - Homepage in specific language
|
|
139
|
+
* - GET /:lang/* - Pages in specific language
|
|
140
|
+
*
|
|
141
|
+
* @param honoApp - Hono application instance
|
|
142
|
+
* @param config - Route configuration
|
|
143
|
+
* @returns Hono app with language routes configured
|
|
144
|
+
*/
|
|
145
|
+
export function setupLanguageRoutes(
|
|
146
|
+
honoApp: Readonly<Hono>,
|
|
147
|
+
config: HonoAppConfig
|
|
148
|
+
): Readonly<Hono> {
|
|
149
|
+
return honoApp
|
|
150
|
+
.get('/:lang/', handleLanguageHomepageRoute(config))
|
|
151
|
+
.get('/:lang/*', handleLanguagePageRoute(config))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Setup dynamic page routes
|
|
156
|
+
*
|
|
157
|
+
* Catches all other routes and attempts to render them as pages
|
|
158
|
+
*
|
|
159
|
+
* @param honoApp - Hono application instance
|
|
160
|
+
* @param config - Route configuration
|
|
161
|
+
* @returns Hono app with dynamic page routes configured
|
|
162
|
+
*/
|
|
163
|
+
export function setupDynamicPageRoutes(
|
|
164
|
+
honoApp: Readonly<Hono>,
|
|
165
|
+
config: HonoAppConfig
|
|
166
|
+
): Readonly<Hono> {
|
|
167
|
+
const { app, renderPage, renderNotFoundPage } = config
|
|
168
|
+
|
|
169
|
+
return honoApp.get('*', (c) => {
|
|
170
|
+
const { path } = c.req
|
|
171
|
+
const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
172
|
+
const html = renderPage(app, path, detectedLanguage)
|
|
173
|
+
if (!html) {
|
|
174
|
+
return c.html(renderNotFoundPage(app, detectedLanguage), 404)
|
|
175
|
+
}
|
|
176
|
+
return c.html(html)
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Setup test error route
|
|
182
|
+
*
|
|
183
|
+
* Only available in non-production environments
|
|
184
|
+
*
|
|
185
|
+
* @param honoApp - Hono application instance
|
|
186
|
+
* @param config - Route configuration
|
|
187
|
+
* @returns Hono app with test error route configured
|
|
188
|
+
*/
|
|
189
|
+
export function setupTestErrorRoute(
|
|
190
|
+
honoApp: Readonly<Hono>,
|
|
191
|
+
config: HonoAppConfig
|
|
192
|
+
): Readonly<Hono> {
|
|
193
|
+
const { app, renderNotFoundPage } = config
|
|
194
|
+
|
|
195
|
+
return honoApp.get('/test/error', (c) => {
|
|
196
|
+
if (process.env.NODE_ENV === 'production') {
|
|
197
|
+
const detectedLanguage = detectLanguageIfEnabled(app, c.req.header('Accept-Language'))
|
|
198
|
+
return c.html(renderNotFoundPage(app, detectedLanguage), 404)
|
|
199
|
+
}
|
|
200
|
+
// eslint-disable-next-line functional/no-throw-statements
|
|
201
|
+
throw new Error('Test error')
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Setup page routes (homepage, language subdirectories, dynamic pages)
|
|
207
|
+
*
|
|
208
|
+
* Mounts all page-related routes in correct order
|
|
209
|
+
*
|
|
210
|
+
* @param honoApp - Hono application instance
|
|
211
|
+
* @param config - Route configuration
|
|
212
|
+
* @returns Hono app with all page routes configured
|
|
213
|
+
*/
|
|
214
|
+
export function setupPageRoutes(honoApp: Readonly<Hono>, config: HonoAppConfig): Readonly<Hono> {
|
|
215
|
+
return setupDynamicPageRoutes(
|
|
216
|
+
setupLanguageRoutes(setupTestErrorRoute(setupHomepageRoute(honoApp, config), config), config),
|
|
217
|
+
config
|
|
218
|
+
)
|
|
219
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
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, Effect } from 'effect'
|
|
9
|
+
import { type Context, type Hono } from 'hono'
|
|
10
|
+
import { generateTrackingScript } from '@/infrastructure/analytics/tracking-script'
|
|
11
|
+
import { compileCSS } from '@/infrastructure/css/compiler'
|
|
12
|
+
import type { App } from '@/domain/models/app'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Cache duration for static assets (CSS, JS) in seconds (1 hour)
|
|
16
|
+
*/
|
|
17
|
+
const STATIC_ASSET_CACHE_DURATION_SECONDS = 3600
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Setup CSS compilation route
|
|
21
|
+
*
|
|
22
|
+
* Serves dynamically compiled CSS with theme tokens at /assets/output.css
|
|
23
|
+
*
|
|
24
|
+
* @param honoApp - Hono application instance
|
|
25
|
+
* @param app - Application configuration
|
|
26
|
+
* @returns Hono app with CSS route configured
|
|
27
|
+
*/
|
|
28
|
+
export function setupCSSRoute(honoApp: Readonly<Hono>, app: App): Readonly<Hono> {
|
|
29
|
+
return honoApp.get('/assets/output.css', async (c) => {
|
|
30
|
+
try {
|
|
31
|
+
const result = await Effect.runPromise(
|
|
32
|
+
compileCSS(app).pipe(Effect.tap(() => Console.log('CSS compiled successfully')))
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return c.text(result.css, 200, {
|
|
36
|
+
'Content-Type': 'text/css',
|
|
37
|
+
'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
|
|
38
|
+
})
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// Log error - intentional side effect for error tracking
|
|
41
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
42
|
+
await Effect.runPromise(Console.error('CSS compilation failed:', error))
|
|
43
|
+
return c.text('/* CSS compilation failed */', 500, {
|
|
44
|
+
'Content-Type': 'text/css',
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create handler for serving JavaScript file
|
|
52
|
+
*
|
|
53
|
+
* @param scriptName - Display name for error logging
|
|
54
|
+
* @param scriptPath - File path to JavaScript file
|
|
55
|
+
* @returns Hono route handler function
|
|
56
|
+
*/
|
|
57
|
+
export function createJavaScriptHandler(scriptName: string, scriptPath: string) {
|
|
58
|
+
return async (c: Readonly<Context>) => {
|
|
59
|
+
try {
|
|
60
|
+
const file = Bun.file(scriptPath)
|
|
61
|
+
const content = await file.text()
|
|
62
|
+
|
|
63
|
+
return c.text(content, 200, {
|
|
64
|
+
'Content-Type': 'application/javascript',
|
|
65
|
+
'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
|
|
66
|
+
})
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
69
|
+
await Effect.runPromise(Console.error(`Failed to load ${scriptName}:`, error))
|
|
70
|
+
return c.text(`/* ${scriptName} failed to load */`, 500, {
|
|
71
|
+
'Content-Type': 'application/javascript',
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Setup built-in analytics tracking script route
|
|
79
|
+
*
|
|
80
|
+
* Serves dynamically generated analytics tracking script at /assets/analytics.js
|
|
81
|
+
* Template variables are replaced at serve time with app-specific values.
|
|
82
|
+
* Only serves the script when built-in analytics is enabled.
|
|
83
|
+
*
|
|
84
|
+
* @param honoApp - Hono application instance
|
|
85
|
+
* @param app - Application configuration
|
|
86
|
+
* @returns Hono app with analytics script route configured
|
|
87
|
+
*/
|
|
88
|
+
export function setupAnalyticsScriptRoute(honoApp: Readonly<Hono>, app: App): Readonly<Hono> {
|
|
89
|
+
const analyticsEnabled = app.analytics !== undefined && app.analytics !== false
|
|
90
|
+
|
|
91
|
+
if (!analyticsEnabled) return honoApp
|
|
92
|
+
|
|
93
|
+
const respectDoNotTrack =
|
|
94
|
+
typeof app.analytics === 'object' ? app.analytics.respectDoNotTrack !== false : true
|
|
95
|
+
const scriptContent = generateTrackingScript(
|
|
96
|
+
'/api/analytics/collect',
|
|
97
|
+
app.name,
|
|
98
|
+
respectDoNotTrack
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return honoApp.get('/assets/analytics.js', (c) => {
|
|
102
|
+
return c.text(scriptContent, 200, {
|
|
103
|
+
'Content-Type': 'application/javascript',
|
|
104
|
+
'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Setup JavaScript asset routes
|
|
111
|
+
*
|
|
112
|
+
* Serves client-side JavaScript files at /assets/*.js
|
|
113
|
+
*
|
|
114
|
+
* @param honoApp - Hono application instance
|
|
115
|
+
* @returns Hono app with JavaScript routes configured
|
|
116
|
+
*/
|
|
117
|
+
export function setupJavaScriptRoutes(honoApp: Readonly<Hono>): Readonly<Hono> {
|
|
118
|
+
return honoApp
|
|
119
|
+
.get(
|
|
120
|
+
'/assets/language-switcher.js',
|
|
121
|
+
createJavaScriptHandler(
|
|
122
|
+
'language-switcher.js',
|
|
123
|
+
'./src/presentation/scripts/client/language-switcher.js'
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
.get(
|
|
127
|
+
'/assets/banner-dismiss.js',
|
|
128
|
+
createJavaScriptHandler(
|
|
129
|
+
'banner-dismiss.js',
|
|
130
|
+
'./src/presentation/scripts/client/banner-dismiss.js'
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
.get(
|
|
134
|
+
'/assets/scroll-animation.js',
|
|
135
|
+
createJavaScriptHandler(
|
|
136
|
+
'scroll-animation.js',
|
|
137
|
+
'./src/presentation/scripts/client/scroll-animation.js'
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Setup public directory file serving for development
|
|
144
|
+
*
|
|
145
|
+
* Serves files from a local directory at their relative path.
|
|
146
|
+
* e.g., `publicDir/logos/escp.png` is served at `/logos/escp.png`
|
|
147
|
+
*
|
|
148
|
+
* @param honoApp - Hono application instance
|
|
149
|
+
* @param publicDir - Directory path to serve files from
|
|
150
|
+
* @returns Hono app with public dir route configured
|
|
151
|
+
*/
|
|
152
|
+
export function setupPublicDirRoute(honoApp: Readonly<Hono>, publicDir: string): Readonly<Hono> {
|
|
153
|
+
return honoApp.get('/*', async (c, next) => {
|
|
154
|
+
const { path } = c.req
|
|
155
|
+
const filePath = `${publicDir}${path}`
|
|
156
|
+
const file = Bun.file(filePath)
|
|
157
|
+
|
|
158
|
+
if (await file.exists()) {
|
|
159
|
+
return new Response(file, {
|
|
160
|
+
headers: {
|
|
161
|
+
'Cache-Control': `public, max-age=${STATIC_ASSET_CACHE_DURATION_SECONDS}`,
|
|
162
|
+
},
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
167
|
+
await next()
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Setup static asset routes (CSS, JavaScript, and optional public directory)
|
|
173
|
+
*
|
|
174
|
+
* Mounts CSS, JavaScript, and optionally public directory asset routes
|
|
175
|
+
*
|
|
176
|
+
* @param honoApp - Hono application instance
|
|
177
|
+
* @param app - Application configuration
|
|
178
|
+
* @param publicDir - Optional directory to serve static files from
|
|
179
|
+
* @returns Hono app with static asset routes configured
|
|
180
|
+
*/
|
|
181
|
+
export function setupStaticAssets(
|
|
182
|
+
honoApp: Readonly<Hono>,
|
|
183
|
+
app: App,
|
|
184
|
+
publicDir?: string
|
|
185
|
+
): Readonly<Hono> {
|
|
186
|
+
const withAssets = setupAnalyticsScriptRoute(
|
|
187
|
+
setupJavaScriptRoutes(setupCSSRoute(honoApp, app)),
|
|
188
|
+
app
|
|
189
|
+
)
|
|
190
|
+
return publicDir ? setupPublicDirRoute(withAssets, publicDir) : withAssets
|
|
191
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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, Layer } from 'effect'
|
|
9
|
+
import { ServerFactory } from '@/application/ports/services/server-factory'
|
|
10
|
+
import { createServer } from './server'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Live implementation of ServerFactory using Bun.serve
|
|
14
|
+
*
|
|
15
|
+
* This Layer provides the production server creation logic,
|
|
16
|
+
* wrapping the infrastructure createServer function in an
|
|
17
|
+
* Effect Context service.
|
|
18
|
+
*
|
|
19
|
+
* The implementation uses Layer.effect because createServer
|
|
20
|
+
* returns an Effect (async operations with error handling).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Provide ServerFactoryLive to use cases
|
|
25
|
+
* const program = startServer(appConfig).pipe(
|
|
26
|
+
* Effect.provide(ServerFactoryLive)
|
|
27
|
+
* )
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const ServerFactoryLive = Layer.effect(
|
|
31
|
+
ServerFactory,
|
|
32
|
+
Effect.sync(() => ({
|
|
33
|
+
create: (config) =>
|
|
34
|
+
createServer({
|
|
35
|
+
app: config.app,
|
|
36
|
+
port: config.port,
|
|
37
|
+
hostname: config.hostname,
|
|
38
|
+
publicDir: config.publicDir,
|
|
39
|
+
renderHomePage: config.renderHomePage,
|
|
40
|
+
renderPage: config.renderPage,
|
|
41
|
+
renderNotFoundPage: config.renderNotFoundPage,
|
|
42
|
+
renderErrorPage: config.renderErrorPage,
|
|
43
|
+
}),
|
|
44
|
+
}))
|
|
45
|
+
)
|