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,118 @@
|
|
|
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, Schema } from 'effect'
|
|
9
|
+
import { AppValidationError } from '@/application/errors/app-validation-error'
|
|
10
|
+
import { PageRenderer } from '@/application/ports/services/page-renderer'
|
|
11
|
+
import { ServerFactory } from '@/application/ports/services/server-factory'
|
|
12
|
+
import { bootstrapAdmin } from '@/application/use-cases/auth/bootstrap-admin'
|
|
13
|
+
import { AppSchema } from '@/domain/models/app'
|
|
14
|
+
import { Logger } from '@/infrastructure/logging/logger'
|
|
15
|
+
import type { ServerInstance } from '@/application/models/server'
|
|
16
|
+
import type { AuthRepository } from '@/application/ports/repositories/auth-repository'
|
|
17
|
+
import type { App } from '@/domain/models/app'
|
|
18
|
+
import type { Auth } from '@/infrastructure/auth/better-auth'
|
|
19
|
+
import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
|
|
20
|
+
import type { CSSCompilationError } from '@/infrastructure/errors/css-compilation-error'
|
|
21
|
+
import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
|
|
22
|
+
import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Server configuration options
|
|
26
|
+
*/
|
|
27
|
+
export interface StartOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Port number for the HTTP server
|
|
30
|
+
* @default 3000
|
|
31
|
+
*/
|
|
32
|
+
readonly port?: number
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Hostname to bind the server to
|
|
36
|
+
* @default "localhost"
|
|
37
|
+
*/
|
|
38
|
+
readonly hostname?: string
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Directory to serve static files from during development
|
|
42
|
+
* Files are served at their relative path (e.g., `publicDir/logos/x.png` → `/logos/x.png`)
|
|
43
|
+
*/
|
|
44
|
+
readonly publicDir?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Use case for starting an Sovrium web server
|
|
49
|
+
*
|
|
50
|
+
* This orchestrates the server startup process:
|
|
51
|
+
* 1. Validates the app configuration using Effect Schema
|
|
52
|
+
* 2. Obtains rendering and server creation services via Effect Context
|
|
53
|
+
* 3. Creates and starts the server via injected dependencies
|
|
54
|
+
* 4. Bootstraps admin account if configured via environment variables
|
|
55
|
+
*
|
|
56
|
+
* Dependencies are provided via Effect.provide(AppLayer) at the application boundary.
|
|
57
|
+
*
|
|
58
|
+
* @param app - Application configuration
|
|
59
|
+
* @param options - Server configuration options
|
|
60
|
+
* @returns Effect that yields ServerInstance or errors
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // In src/index.ts
|
|
65
|
+
* const program = startServer(appConfig, { port: 3000 }).pipe(
|
|
66
|
+
* Effect.provide(AppLayer)
|
|
67
|
+
* )
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export const startServer = (
|
|
71
|
+
app: unknown,
|
|
72
|
+
options: StartOptions = {}
|
|
73
|
+
): Effect.Effect<
|
|
74
|
+
ServerInstance,
|
|
75
|
+
| AppValidationError
|
|
76
|
+
| ServerCreationError
|
|
77
|
+
| CSSCompilationError
|
|
78
|
+
| AuthConfigRequiredForUserFields
|
|
79
|
+
| SchemaInitializationError
|
|
80
|
+
| Error,
|
|
81
|
+
ServerFactory | PageRenderer | Auth | AuthRepository | Logger
|
|
82
|
+
> =>
|
|
83
|
+
Effect.gen(function* () {
|
|
84
|
+
// Validate app configuration using domain model schema
|
|
85
|
+
const validatedApp = yield* Effect.try({
|
|
86
|
+
try: (): App => Schema.decodeUnknownSync(AppSchema)(app),
|
|
87
|
+
catch: (error) => new AppValidationError(error),
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// Obtain dependencies from Effect Context
|
|
91
|
+
const serverFactory = yield* ServerFactory
|
|
92
|
+
const pageRenderer = yield* PageRenderer
|
|
93
|
+
|
|
94
|
+
// Bootstrap admin account BEFORE starting the server
|
|
95
|
+
// This ensures admin user exists before server signals "ready"
|
|
96
|
+
const logger = yield* Logger
|
|
97
|
+
yield* bootstrapAdmin(validatedApp).pipe(
|
|
98
|
+
Effect.catchAll((error) =>
|
|
99
|
+
// Log bootstrap errors but don't fail server startup
|
|
100
|
+
logger.warn('Admin bootstrap error', error.message)
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
// Create server using injected dependencies
|
|
105
|
+
// Server only starts listening after bootstrap completes
|
|
106
|
+
const serverInstance = yield* serverFactory.create({
|
|
107
|
+
app: validatedApp,
|
|
108
|
+
port: options.port,
|
|
109
|
+
hostname: options.hostname,
|
|
110
|
+
publicDir: options.publicDir,
|
|
111
|
+
renderHomePage: pageRenderer.renderHome,
|
|
112
|
+
renderPage: pageRenderer.renderPage,
|
|
113
|
+
renderNotFoundPage: pageRenderer.renderNotFound,
|
|
114
|
+
renderErrorPage: pageRenderer.renderError,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return serverInstance
|
|
118
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
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, Console } from 'effect'
|
|
9
|
+
import type { AppValidationError } from '@/application/errors/app-validation-error'
|
|
10
|
+
import type { CSSCompilationError } from '@/infrastructure/errors/css-compilation-error'
|
|
11
|
+
import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Error types that can occur during server startup
|
|
15
|
+
*/
|
|
16
|
+
export type ServerStartupError = AppValidationError | ServerCreationError | CSSCompilationError
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handles server startup errors and logs appropriate messages
|
|
20
|
+
*
|
|
21
|
+
* This utility provides comprehensive error handling for all error types
|
|
22
|
+
* that can occur during server startup, including:
|
|
23
|
+
* - App validation errors (invalid configuration)
|
|
24
|
+
* - Server creation errors (port already in use, etc.)
|
|
25
|
+
* - CSS compilation errors (Tailwind/PostCSS issues)
|
|
26
|
+
*
|
|
27
|
+
* @param error - Error that occurred during server startup
|
|
28
|
+
* @returns Effect that logs error details and exits with code 1
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { Effect } from 'effect'
|
|
33
|
+
* import { start } from '@/index'
|
|
34
|
+
* import { handleStartupError } from '@/application/use-cases/server/startup-error-handler'
|
|
35
|
+
*
|
|
36
|
+
* const program = start(myApp).pipe(
|
|
37
|
+
* Effect.catchAll(handleStartupError)
|
|
38
|
+
* )
|
|
39
|
+
*
|
|
40
|
+
* Effect.runPromise(program)
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const handleStartupError = (error: ServerStartupError): Effect.Effect<never> =>
|
|
44
|
+
Effect.gen(function* () {
|
|
45
|
+
yield* Console.error('Failed to start server:')
|
|
46
|
+
|
|
47
|
+
// Handle specific error types
|
|
48
|
+
if ('_tag' in error) {
|
|
49
|
+
switch (error._tag) {
|
|
50
|
+
case 'AppValidationError':
|
|
51
|
+
yield* Console.error('Invalid app configuration:', error.cause)
|
|
52
|
+
break
|
|
53
|
+
case 'ServerCreationError':
|
|
54
|
+
yield* Console.error('Server creation failed:', error.cause)
|
|
55
|
+
break
|
|
56
|
+
case 'CSSCompilationError':
|
|
57
|
+
yield* Console.error('CSS compilation failed:', error.cause)
|
|
58
|
+
break
|
|
59
|
+
default:
|
|
60
|
+
yield* Console.error('Unknown error:', error)
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
yield* Console.error('Unknown error:', error)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Exit process with error code
|
|
67
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
68
|
+
process.exit(1)
|
|
69
|
+
})
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Page } from '@/domain/models/app'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Hreflang configuration for multilingual sitemaps
|
|
12
|
+
*/
|
|
13
|
+
export interface HreflangConfig {
|
|
14
|
+
/** Maps language codes to full locales (e.g., { en: 'en-US', fr: 'fr-FR' }) */
|
|
15
|
+
readonly localeMap: Readonly<Record<string, string>>
|
|
16
|
+
/** Default language code for x-default hreflang (e.g., 'en') */
|
|
17
|
+
readonly defaultLanguage: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Format HTML with Prettier for professional formatting
|
|
22
|
+
* Loads Prettier config and formats HTML using the HTML parser
|
|
23
|
+
*/
|
|
24
|
+
export const formatHtmlWithPrettier = async (html: string): Promise<string> => {
|
|
25
|
+
const prettier = await import('prettier')
|
|
26
|
+
const config = await prettier.resolveConfig(process.cwd())
|
|
27
|
+
|
|
28
|
+
return await prettier.format(html, {
|
|
29
|
+
...config,
|
|
30
|
+
parser: 'html',
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build the full URL for a page in a specific language
|
|
36
|
+
*/
|
|
37
|
+
const buildLanguageUrl = (baseUrl: string, lang: string, pagePath: string): string => {
|
|
38
|
+
const normalizedPath = pagePath === '/' ? '' : pagePath
|
|
39
|
+
return `${baseUrl}/${lang}${normalizedPath}${normalizedPath === '' ? '/' : ''}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generate hreflang <xhtml:link> elements for a single URL entry
|
|
44
|
+
*/
|
|
45
|
+
export const generateHreflangLinks = (
|
|
46
|
+
baseUrl: string,
|
|
47
|
+
pagePath: string,
|
|
48
|
+
languages: readonly string[],
|
|
49
|
+
hreflangConfig: HreflangConfig
|
|
50
|
+
): readonly string[] => {
|
|
51
|
+
const languageLinks = languages.map((lang) => {
|
|
52
|
+
const locale = hreflangConfig.localeMap[lang] ?? lang
|
|
53
|
+
const url = buildLanguageUrl(baseUrl, lang, pagePath)
|
|
54
|
+
return `<xhtml:link rel="alternate" hreflang="${locale}" href="${url}" />`
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const defaultUrl = buildLanguageUrl(baseUrl, hreflangConfig.defaultLanguage, pagePath)
|
|
58
|
+
const xDefaultLink = `<xhtml:link rel="alternate" hreflang="x-default" href="${defaultUrl}" />`
|
|
59
|
+
|
|
60
|
+
return [...languageLinks, xDefaultLink]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build a single <url> entry for the sitemap
|
|
65
|
+
*/
|
|
66
|
+
const buildUrlEntry = (
|
|
67
|
+
loc: string,
|
|
68
|
+
lastmod: string,
|
|
69
|
+
page: Page,
|
|
70
|
+
hreflangSection: string
|
|
71
|
+
): string => {
|
|
72
|
+
const priority = page.meta?.priority ?? 0.5
|
|
73
|
+
const changefreq = page.meta?.changefreq ?? 'monthly'
|
|
74
|
+
return ` <url>
|
|
75
|
+
<loc>${loc}</loc>${hreflangSection}
|
|
76
|
+
<lastmod>${lastmod}</lastmod>
|
|
77
|
+
<priority>${priority.toFixed(1)}</priority>
|
|
78
|
+
<changefreq>${changefreq}</changefreq>
|
|
79
|
+
</url>`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate sitemap.xml content
|
|
84
|
+
*/
|
|
85
|
+
export const generateSitemapContent = (
|
|
86
|
+
pages: readonly Page[],
|
|
87
|
+
baseUrl: string,
|
|
88
|
+
_basePath: string = '',
|
|
89
|
+
options?: { readonly languages?: readonly string[]; readonly hreflangConfig?: HreflangConfig }
|
|
90
|
+
): string => {
|
|
91
|
+
const indexablePages = pages.filter((page) => !page.meta?.noindex && !page.path.startsWith('/_'))
|
|
92
|
+
const lastmod = new Date().toISOString().split('T')[0] ?? ''
|
|
93
|
+
const languages = options?.languages
|
|
94
|
+
const hreflangConfig = options?.hreflangConfig
|
|
95
|
+
const hasHreflang = languages && languages.length > 0 && hreflangConfig !== undefined
|
|
96
|
+
|
|
97
|
+
const entries: readonly string[] =
|
|
98
|
+
languages && languages.length > 0
|
|
99
|
+
? languages.flatMap((lang) =>
|
|
100
|
+
indexablePages.map((page) => {
|
|
101
|
+
const hreflangLinks = hasHreflang
|
|
102
|
+
? generateHreflangLinks(baseUrl, page.path, languages, hreflangConfig).map(
|
|
103
|
+
(link) => ` ${link}`
|
|
104
|
+
)
|
|
105
|
+
: []
|
|
106
|
+
const hreflangSection = hreflangLinks.length > 0 ? `\n${hreflangLinks.join('\n')}` : ''
|
|
107
|
+
return buildUrlEntry(
|
|
108
|
+
buildLanguageUrl(baseUrl, lang, page.path),
|
|
109
|
+
lastmod,
|
|
110
|
+
page,
|
|
111
|
+
hreflangSection
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
)
|
|
115
|
+
: indexablePages.map((page) => buildUrlEntry(`${baseUrl}${page.path}`, lastmod, page, ''))
|
|
116
|
+
|
|
117
|
+
const xmlnsAttr = hasHreflang
|
|
118
|
+
? ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"\n xmlns:xhtml="http://www.w3.org/1999/xhtml"'
|
|
119
|
+
: ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"'
|
|
120
|
+
|
|
121
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
122
|
+
<urlset${xmlnsAttr}>
|
|
123
|
+
${entries.join('\n')}
|
|
124
|
+
</urlset>`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Generate robots.txt content
|
|
129
|
+
*/
|
|
130
|
+
export const generateRobotsContent = (
|
|
131
|
+
pages: readonly Page[],
|
|
132
|
+
baseUrl: string,
|
|
133
|
+
_basePath: string = '',
|
|
134
|
+
includeSitemap: boolean = false
|
|
135
|
+
): string => {
|
|
136
|
+
const baseLines = ['User-agent: *', 'Allow: /']
|
|
137
|
+
|
|
138
|
+
// Add Disallow rules for:
|
|
139
|
+
// 1. Pages with noindex or robots directives containing "noindex"
|
|
140
|
+
// 2. Underscore-prefixed pages (admin/internal pages)
|
|
141
|
+
const disallowedPages = pages.filter(
|
|
142
|
+
(page) =>
|
|
143
|
+
page.meta?.noindex === true ||
|
|
144
|
+
(page.meta?.robots && page.meta.robots.includes('noindex')) ||
|
|
145
|
+
page.path.startsWith('/_')
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const disallowLines = disallowedPages.map((page) => `Disallow: ${page.path}`)
|
|
149
|
+
|
|
150
|
+
const sitemapLine = includeSitemap ? [`Sitemap: ${baseUrl}/sitemap.xml`] : []
|
|
151
|
+
const lines = [...baseLines, ...disallowLines, ...sitemapLine]
|
|
152
|
+
|
|
153
|
+
return lines.join('\n')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Generate client-side hydration script
|
|
158
|
+
*
|
|
159
|
+
* This minimal script enables React hydration on the client side.
|
|
160
|
+
* For production, this would:
|
|
161
|
+
* - Load React runtime
|
|
162
|
+
* - Re-render components with client-side state
|
|
163
|
+
* - Attach event listeners
|
|
164
|
+
* - Enable interactive features
|
|
165
|
+
*
|
|
166
|
+
* Current implementation: Minimal placeholder for testing
|
|
167
|
+
*/
|
|
168
|
+
export const generateClientHydrationScript = (): string => {
|
|
169
|
+
return `/**
|
|
170
|
+
* Sovrium Client-Side Hydration Script
|
|
171
|
+
* Generated by Sovrium Static Site Generator
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
// Minimal hydration script for static sites
|
|
175
|
+
// This enables client-side interactivity after initial SSR
|
|
176
|
+
console.log('Sovrium: Client-side hydration enabled')
|
|
177
|
+
|
|
178
|
+
// Future: Load React runtime and hydrate components
|
|
179
|
+
// Future: Initialize client-side routing
|
|
180
|
+
// Future: Restore interactive state
|
|
181
|
+
`
|
|
182
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
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
|
+
/* eslint-disable max-params, max-lines-per-function -- Complex multi-language generators require explicit dependencies */
|
|
9
|
+
|
|
10
|
+
import { Effect, Console, Schema, type Context } from 'effect'
|
|
11
|
+
import { AppValidationError } from '@/application/errors/app-validation-error'
|
|
12
|
+
import { AppSchema } from '@/domain/models/app'
|
|
13
|
+
import type { CSSCompilationError } from '@/application/ports/services/css-compiler'
|
|
14
|
+
import type { PageRenderer as PageRendererService } from '@/application/ports/services/page-renderer'
|
|
15
|
+
import type { ServerFactory as ServerFactoryService } from '@/application/ports/services/server-factory'
|
|
16
|
+
import type {
|
|
17
|
+
SSGGenerationError,
|
|
18
|
+
StaticSiteGenerator as StaticSiteGeneratorService,
|
|
19
|
+
} from '@/application/ports/services/static-site-generator'
|
|
20
|
+
import type { App } from '@/domain/models/app'
|
|
21
|
+
import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
|
|
22
|
+
import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
|
|
23
|
+
import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
|
|
24
|
+
|
|
25
|
+
// Service types extracted from Context.Tag
|
|
26
|
+
type ServerFactory = Context.Tag.Service<ServerFactoryService>
|
|
27
|
+
type PageRenderer = Context.Tag.Service<PageRendererService>
|
|
28
|
+
type StaticSiteGenerator = Context.Tag.Service<StaticSiteGeneratorService>
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generate static files for multi-language configuration
|
|
32
|
+
*/
|
|
33
|
+
export const generateMultiLanguageFiles = (
|
|
34
|
+
validatedApp: App,
|
|
35
|
+
outputDir: string,
|
|
36
|
+
replaceAppTokens: (app: App, lang: string) => App,
|
|
37
|
+
serverFactory: ServerFactory,
|
|
38
|
+
pageRenderer: PageRenderer,
|
|
39
|
+
staticSiteGenerator: StaticSiteGenerator
|
|
40
|
+
): Effect.Effect<
|
|
41
|
+
readonly string[],
|
|
42
|
+
| AppValidationError
|
|
43
|
+
| CSSCompilationError
|
|
44
|
+
| ServerCreationError
|
|
45
|
+
| SSGGenerationError
|
|
46
|
+
| AuthConfigRequiredForUserFields
|
|
47
|
+
| SchemaInitializationError
|
|
48
|
+
| Error,
|
|
49
|
+
never
|
|
50
|
+
> =>
|
|
51
|
+
Effect.gen(function* () {
|
|
52
|
+
yield* Console.log(`🌍 Generating multi-language static site...`)
|
|
53
|
+
const supportedLanguages = validatedApp.languages!.supported
|
|
54
|
+
|
|
55
|
+
// Generate files for each language using Effect.forEach
|
|
56
|
+
const langFiles = yield* Effect.forEach(
|
|
57
|
+
supportedLanguages,
|
|
58
|
+
(lang) =>
|
|
59
|
+
Effect.gen(function* () {
|
|
60
|
+
yield* Console.log(`📝 Generating pages for language: ${lang.code}...`)
|
|
61
|
+
|
|
62
|
+
// Replace tokens for this language
|
|
63
|
+
const langApp = replaceAppTokens(validatedApp, lang.code)
|
|
64
|
+
|
|
65
|
+
// Validate the language-specific app
|
|
66
|
+
const validatedLangApp = yield* Effect.try({
|
|
67
|
+
try: (): App => Schema.decodeUnknownSync(AppSchema)(langApp),
|
|
68
|
+
catch: (error) => new AppValidationError(error),
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Create server instance for this language
|
|
72
|
+
const serverInstance = yield* serverFactory.create({
|
|
73
|
+
app: validatedLangApp,
|
|
74
|
+
port: 0,
|
|
75
|
+
hostname: 'localhost',
|
|
76
|
+
renderHomePage: pageRenderer.renderHome,
|
|
77
|
+
renderPage: pageRenderer.renderPage,
|
|
78
|
+
renderNotFoundPage: pageRenderer.renderNotFound,
|
|
79
|
+
renderErrorPage: pageRenderer.renderError,
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
yield* serverInstance.stop
|
|
83
|
+
|
|
84
|
+
// Generate static files in language subdirectory
|
|
85
|
+
const langOutputDir = `${outputDir}/${lang.code}`
|
|
86
|
+
// Filter out underscore-prefixed pages (admin/internal pages)
|
|
87
|
+
const pagePaths =
|
|
88
|
+
validatedLangApp.pages
|
|
89
|
+
?.filter((page) => !page.path.startsWith('/_'))
|
|
90
|
+
.map((page) => page.path) || []
|
|
91
|
+
const ssgResult = yield* staticSiteGenerator.generate(serverInstance.app, {
|
|
92
|
+
outputDir: langOutputDir,
|
|
93
|
+
pagePaths,
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// Return files with language prefix (normalize paths to be relative)
|
|
97
|
+
return ssgResult.files.map((f) => {
|
|
98
|
+
// toSSG returns relative paths from the outputDir
|
|
99
|
+
// Simply prefix with language code
|
|
100
|
+
return `${lang.code}/${f}`
|
|
101
|
+
})
|
|
102
|
+
}),
|
|
103
|
+
{ concurrency: 'unbounded' }
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
// Generate root index.html with default language
|
|
107
|
+
yield* Console.log(`📝 Generating root index.html with default language...`)
|
|
108
|
+
const defaultLang = validatedApp.languages!.default
|
|
109
|
+
const defaultLangApp = replaceAppTokens(validatedApp, defaultLang)
|
|
110
|
+
const validatedDefaultApp = yield* Effect.try({
|
|
111
|
+
try: (): App => Schema.decodeUnknownSync(AppSchema)(defaultLangApp),
|
|
112
|
+
catch: (error) => new AppValidationError(error),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const defaultServer = yield* serverFactory.create({
|
|
116
|
+
app: validatedDefaultApp,
|
|
117
|
+
port: 0,
|
|
118
|
+
hostname: 'localhost',
|
|
119
|
+
renderHomePage: pageRenderer.renderHome,
|
|
120
|
+
renderPage: pageRenderer.renderPage,
|
|
121
|
+
renderNotFoundPage: pageRenderer.renderNotFound,
|
|
122
|
+
renderErrorPage: pageRenderer.renderError,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
yield* defaultServer.stop
|
|
126
|
+
|
|
127
|
+
// Generate only root index.html
|
|
128
|
+
const rootSSGResult = yield* staticSiteGenerator.generate(defaultServer.app, {
|
|
129
|
+
outputDir,
|
|
130
|
+
pagePaths: ['/'],
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
// Combine all files immutably
|
|
134
|
+
return [...langFiles.flat(), ...rootSSGResult.files]
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Generate static files for single-language configuration
|
|
139
|
+
*/
|
|
140
|
+
export const generateSingleLanguageFiles = (
|
|
141
|
+
validatedApp: App,
|
|
142
|
+
outputDir: string,
|
|
143
|
+
serverFactory: ServerFactory,
|
|
144
|
+
pageRenderer: PageRenderer,
|
|
145
|
+
staticSiteGenerator: StaticSiteGenerator
|
|
146
|
+
): Effect.Effect<
|
|
147
|
+
readonly string[],
|
|
148
|
+
| CSSCompilationError
|
|
149
|
+
| ServerCreationError
|
|
150
|
+
| SSGGenerationError
|
|
151
|
+
| AuthConfigRequiredForUserFields
|
|
152
|
+
| SchemaInitializationError
|
|
153
|
+
| Error,
|
|
154
|
+
never
|
|
155
|
+
> =>
|
|
156
|
+
Effect.gen(function* () {
|
|
157
|
+
// No multi-language - generate normally
|
|
158
|
+
yield* Console.log('🏗️ Creating application instance...')
|
|
159
|
+
const serverInstance = yield* serverFactory.create({
|
|
160
|
+
app: validatedApp,
|
|
161
|
+
port: 0,
|
|
162
|
+
hostname: 'localhost',
|
|
163
|
+
renderHomePage: pageRenderer.renderHome,
|
|
164
|
+
renderPage: pageRenderer.renderPage,
|
|
165
|
+
renderNotFoundPage: pageRenderer.renderNotFound,
|
|
166
|
+
renderErrorPage: pageRenderer.renderError,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
yield* serverInstance.stop
|
|
170
|
+
|
|
171
|
+
// Filter out underscore-prefixed pages (admin/internal pages)
|
|
172
|
+
const pagePaths =
|
|
173
|
+
validatedApp.pages?.filter((page) => !page.path.startsWith('/_')).map((page) => page.path) ||
|
|
174
|
+
[]
|
|
175
|
+
yield* Console.log(`📝 Generating static HTML files for ${pagePaths.length} pages...`)
|
|
176
|
+
const ssgResult = yield* staticSiteGenerator.generate(serverInstance.app, {
|
|
177
|
+
outputDir,
|
|
178
|
+
pagePaths,
|
|
179
|
+
})
|
|
180
|
+
return ssgResult.files
|
|
181
|
+
})
|