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,131 @@
|
|
|
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 ReactElement, type ReactNode } from 'react'
|
|
9
|
+
import { isCssValue, isTailwindClass } from '@/presentation/styling/style-utils'
|
|
10
|
+
import type {
|
|
11
|
+
ComponentReference,
|
|
12
|
+
SimpleComponentReference,
|
|
13
|
+
} from '@/domain/models/app/component/common/component-reference'
|
|
14
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
15
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Render a container div with spacing
|
|
19
|
+
*
|
|
20
|
+
* @param testId - Data testid for the container
|
|
21
|
+
* @param value - Spacing value (Tailwind class or CSS value)
|
|
22
|
+
* @returns Container div element
|
|
23
|
+
*/
|
|
24
|
+
function renderContainer(testId: string, value: string): ReactElement {
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
data-testid={testId}
|
|
28
|
+
{...(isTailwindClass(value) ? { className: value } : { style: { maxWidth: value } })}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Render optional container elements based on theme spacing
|
|
35
|
+
*
|
|
36
|
+
* @param theme - Theme configuration
|
|
37
|
+
* @param sections - Sections to check for existing containers
|
|
38
|
+
* @returns Container elements or undefined
|
|
39
|
+
*/
|
|
40
|
+
function renderContainerElements(
|
|
41
|
+
theme: Theme,
|
|
42
|
+
sections: ReadonlyArray<Component | SimpleComponentReference | ComponentReference>
|
|
43
|
+
): ReactElement | null {
|
|
44
|
+
const hasContainer = sections.some((s) => 'type' in s && s.type === 'container')
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
{theme?.spacing?.container &&
|
|
49
|
+
!hasContainer &&
|
|
50
|
+
renderContainer('container', theme.spacing.container)}
|
|
51
|
+
|
|
52
|
+
{(() => {
|
|
53
|
+
const containerSmall = (theme?.spacing as Record<string, unknown>)?.['container-small']
|
|
54
|
+
if (typeof containerSmall === 'string') {
|
|
55
|
+
return renderContainer('container-small', containerSmall)
|
|
56
|
+
}
|
|
57
|
+
return undefined
|
|
58
|
+
})()}
|
|
59
|
+
|
|
60
|
+
{(() => {
|
|
61
|
+
const containerXSmall = (theme?.spacing as Record<string, unknown>)?.['container-xsmall']
|
|
62
|
+
if (typeof containerXSmall === 'string') {
|
|
63
|
+
return renderContainer('container-xsmall', containerXSmall)
|
|
64
|
+
}
|
|
65
|
+
return undefined
|
|
66
|
+
})()}
|
|
67
|
+
</>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Wrap sections in a section element if needed
|
|
73
|
+
*
|
|
74
|
+
* @param sections - Sections to check
|
|
75
|
+
* @param theme - Theme configuration
|
|
76
|
+
* @param children - Content to wrap
|
|
77
|
+
* @returns Section-wrapped content or fragment with children
|
|
78
|
+
*/
|
|
79
|
+
export function wrapWithSectionIfNeeded(
|
|
80
|
+
sections: ReadonlyArray<Component | SimpleComponentReference | ComponentReference>,
|
|
81
|
+
theme: Theme | undefined,
|
|
82
|
+
children: ReactNode
|
|
83
|
+
): ReactElement {
|
|
84
|
+
const hasSection = sections.some((s) => 'type' in s && s.type === 'section')
|
|
85
|
+
const sectionSpacing = theme?.spacing?.section
|
|
86
|
+
const shouldWrap = !hasSection && sectionSpacing
|
|
87
|
+
|
|
88
|
+
if (!shouldWrap || !sectionSpacing) {
|
|
89
|
+
// eslint-disable-next-line react/jsx-no-useless-fragment -- Required to return ReactElement
|
|
90
|
+
return <>{children}</>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const useTailwind = !isCssValue(sectionSpacing)
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<section
|
|
97
|
+
data-testid="section"
|
|
98
|
+
{...(useTailwind && { className: sectionSpacing })}
|
|
99
|
+
{...(!useTailwind && { style: { padding: sectionSpacing } })}
|
|
100
|
+
>
|
|
101
|
+
{children}
|
|
102
|
+
</section>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Render complete section with spacing wrappers
|
|
108
|
+
*
|
|
109
|
+
* @param theme - Theme configuration
|
|
110
|
+
* @param sections - Sections to render
|
|
111
|
+
* @param children - Pre-rendered section content
|
|
112
|
+
* @returns Section with spacing applied
|
|
113
|
+
*/
|
|
114
|
+
export function renderSectionWithSpacing(
|
|
115
|
+
theme: Theme | undefined,
|
|
116
|
+
sections: ReadonlyArray<Component | SimpleComponentReference | ComponentReference>,
|
|
117
|
+
children: ReactNode
|
|
118
|
+
): ReactElement {
|
|
119
|
+
// No theme spacing - render directly
|
|
120
|
+
if (!theme?.spacing?.section && !theme?.spacing?.container) {
|
|
121
|
+
// eslint-disable-next-line react/jsx-no-useless-fragment -- Required to return ReactElement
|
|
122
|
+
return <>{children}</>
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<>
|
|
127
|
+
{wrapWithSectionIfNeeded(sections, theme, children)}
|
|
128
|
+
{theme && renderContainerElements(theme, sections)}
|
|
129
|
+
</>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
@@ -0,0 +1,426 @@
|
|
|
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-lines, max-lines-per-function, max-statements -- Complex component renderer with many helpers */
|
|
9
|
+
|
|
10
|
+
import { type ReactElement, Fragment, useId } from 'react'
|
|
11
|
+
import { useBreakpoint } from '@/presentation/hooks/use-breakpoint'
|
|
12
|
+
import {
|
|
13
|
+
StructuredDataFromComponent,
|
|
14
|
+
type ComponentMeta,
|
|
15
|
+
} from '@/presentation/ui/metadata/structured-data-from-component'
|
|
16
|
+
import {
|
|
17
|
+
extractComponentReference,
|
|
18
|
+
renderComponentReferenceError,
|
|
19
|
+
} from './components/component-reference-handler'
|
|
20
|
+
import { resolveComponent } from './components/component-resolution'
|
|
21
|
+
import { buildComponentProps } from './props/component-builder'
|
|
22
|
+
import { dispatchComponentType } from './rendering/component-type-dispatcher'
|
|
23
|
+
import { buildResponsiveChildrenVariants } from './responsive/responsive-children-builder'
|
|
24
|
+
import { buildResponsiveContentVariants } from './responsive/responsive-content-builder'
|
|
25
|
+
import { mergeResponsiveProps } from './responsive/responsive-props-merger'
|
|
26
|
+
import { buildInteractionProps } from './styling/interaction-props-builder'
|
|
27
|
+
import { resolveI18nContent } from './translations/i18n-content-resolver'
|
|
28
|
+
import { resolveChildTranslation } from './translations/translation-handler'
|
|
29
|
+
import {
|
|
30
|
+
substituteVariableValues,
|
|
31
|
+
substitutePropsVariables,
|
|
32
|
+
substituteChildrenVariables,
|
|
33
|
+
} from './translations/variable-substitution'
|
|
34
|
+
import type {
|
|
35
|
+
ComponentReference,
|
|
36
|
+
SimpleComponentReference,
|
|
37
|
+
} from '@/domain/models/app/component/common/component-reference'
|
|
38
|
+
import type { Components } from '@/domain/models/app/components'
|
|
39
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
40
|
+
import type { VariantOverrides } from '@/domain/models/app/page/common/responsive'
|
|
41
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
42
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Component renderer props
|
|
46
|
+
*/
|
|
47
|
+
type ComponentRendererProps = {
|
|
48
|
+
readonly component: Component | SimpleComponentReference | ComponentReference
|
|
49
|
+
readonly pageVars?: Record<string, string | number | boolean>
|
|
50
|
+
readonly componentName?: string
|
|
51
|
+
readonly componentInstanceIndex?: number
|
|
52
|
+
readonly components?: Components
|
|
53
|
+
readonly theme?: Theme
|
|
54
|
+
readonly languages?: Languages
|
|
55
|
+
readonly currentLang?: string
|
|
56
|
+
readonly childIndex?: number
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Handles component reference resolution and rendering
|
|
61
|
+
*
|
|
62
|
+
* @param component - Component reference
|
|
63
|
+
* @param props - Component renderer props
|
|
64
|
+
* @returns Rendered component reference or error
|
|
65
|
+
*/
|
|
66
|
+
function renderComponentReference(
|
|
67
|
+
component: SimpleComponentReference | ComponentReference,
|
|
68
|
+
props: ComponentRendererProps
|
|
69
|
+
): ReactElement | null {
|
|
70
|
+
const { refName, vars } = extractComponentReference(component)
|
|
71
|
+
const resolved = resolveComponent(refName, props.components, vars)
|
|
72
|
+
|
|
73
|
+
if (!resolved) {
|
|
74
|
+
return renderComponentReferenceError({ refName, components: props.components })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<ComponentRenderer
|
|
79
|
+
component={resolved.component}
|
|
80
|
+
pageVars={props.pageVars}
|
|
81
|
+
componentName={resolved.name}
|
|
82
|
+
componentInstanceIndex={props.componentInstanceIndex}
|
|
83
|
+
components={props.components}
|
|
84
|
+
theme={props.theme}
|
|
85
|
+
languages={props.languages}
|
|
86
|
+
currentLang={props.currentLang}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Renders children recursively
|
|
93
|
+
*
|
|
94
|
+
* @param children - Child components or strings
|
|
95
|
+
* @param props - Component renderer props
|
|
96
|
+
* @returns Rendered children elements (cast to ReactElement[] for compatibility)
|
|
97
|
+
*/
|
|
98
|
+
function renderChildren(
|
|
99
|
+
children: ReadonlyArray<Component | string> | undefined,
|
|
100
|
+
props: ComponentRendererProps
|
|
101
|
+
): readonly ReactElement[] {
|
|
102
|
+
if (!children) return []
|
|
103
|
+
|
|
104
|
+
return children.map((child: Component | string, index: number) =>
|
|
105
|
+
typeof child === 'string' ? (
|
|
106
|
+
resolveChildTranslation(child, props.currentLang, props.languages)
|
|
107
|
+
) : (
|
|
108
|
+
<ComponentRenderer
|
|
109
|
+
key={index}
|
|
110
|
+
component={child}
|
|
111
|
+
pageVars={props.pageVars}
|
|
112
|
+
components={props.components}
|
|
113
|
+
theme={props.theme}
|
|
114
|
+
languages={props.languages}
|
|
115
|
+
currentLang={props.currentLang}
|
|
116
|
+
childIndex={index}
|
|
117
|
+
/>
|
|
118
|
+
)
|
|
119
|
+
) as ReactElement[]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Apply page-level variable substitution to component
|
|
124
|
+
*/
|
|
125
|
+
function applyVariableSubstitution(
|
|
126
|
+
component: Component,
|
|
127
|
+
pageVars: ComponentRendererProps['pageVars']
|
|
128
|
+
): Component {
|
|
129
|
+
if (!pageVars) return component
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
...component,
|
|
133
|
+
props: substitutePropsVariables(component.props, pageVars),
|
|
134
|
+
children: substituteChildrenVariables(component.children, pageVars),
|
|
135
|
+
content:
|
|
136
|
+
typeof component.content === 'string'
|
|
137
|
+
? (substituteVariableValues(component.content, pageVars) as string)
|
|
138
|
+
: component.content,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Add data-component-type attribute for testing
|
|
144
|
+
*/
|
|
145
|
+
function addComponentTypeAttribute(
|
|
146
|
+
elementProps: Record<string, unknown>,
|
|
147
|
+
type: string
|
|
148
|
+
): Record<string, unknown> {
|
|
149
|
+
return {
|
|
150
|
+
...elementProps,
|
|
151
|
+
'data-component-type': type,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check if component has responsive content overrides
|
|
157
|
+
*/
|
|
158
|
+
function hasResponsiveContentOverrides(responsive: Component['responsive']): boolean {
|
|
159
|
+
return (
|
|
160
|
+
!!responsive &&
|
|
161
|
+
Object.values(responsive).some(
|
|
162
|
+
(override) => (override as VariantOverrides).content !== undefined
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if component has responsive children overrides
|
|
169
|
+
*/
|
|
170
|
+
function hasResponsiveChildrenOverrides(responsive: Component['responsive']): boolean {
|
|
171
|
+
return (
|
|
172
|
+
!!responsive &&
|
|
173
|
+
Object.values(responsive).some(
|
|
174
|
+
(override) => (override as VariantOverrides).children !== undefined
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Render component with responsive content variants
|
|
181
|
+
*/
|
|
182
|
+
function renderWithResponsiveContent(config: {
|
|
183
|
+
responsive: Component['responsive']
|
|
184
|
+
type: string
|
|
185
|
+
finalElementPropsWithType: Record<string, unknown>
|
|
186
|
+
finalElementPropsWithSpacingAndType: Record<string, unknown>
|
|
187
|
+
hoverData?: { styleContent: string }
|
|
188
|
+
}): ReactElement | null {
|
|
189
|
+
const responsiveVariants = buildResponsiveContentVariants(
|
|
190
|
+
config.responsive!,
|
|
191
|
+
config.type,
|
|
192
|
+
config.finalElementPropsWithType,
|
|
193
|
+
config.finalElementPropsWithSpacingAndType
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if (config.hoverData) {
|
|
197
|
+
return (
|
|
198
|
+
<Fragment>
|
|
199
|
+
<style>{config.hoverData.styleContent}</style>
|
|
200
|
+
{responsiveVariants}
|
|
201
|
+
</Fragment>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return responsiveVariants
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Build responsive children with variant rendering
|
|
210
|
+
*/
|
|
211
|
+
function buildResponsiveChildren(
|
|
212
|
+
responsive: Component['responsive'],
|
|
213
|
+
baseChildren: readonly ReactElement[],
|
|
214
|
+
props: ComponentRendererProps
|
|
215
|
+
): readonly ReactElement[] {
|
|
216
|
+
return buildResponsiveChildrenVariants({
|
|
217
|
+
responsive: responsive!,
|
|
218
|
+
baseChildren,
|
|
219
|
+
renderChild: (child, index, breakpoint, additionalClassName) => {
|
|
220
|
+
if (typeof child === 'string') {
|
|
221
|
+
const resolvedText = resolveChildTranslation(child, props.currentLang, props.languages)
|
|
222
|
+
return (
|
|
223
|
+
<span
|
|
224
|
+
key={`${breakpoint}-${index}`}
|
|
225
|
+
className={additionalClassName}
|
|
226
|
+
data-responsive-breakpoint={breakpoint}
|
|
227
|
+
>
|
|
228
|
+
{resolvedText}
|
|
229
|
+
</span>
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const childWithVisibility: Component = additionalClassName
|
|
234
|
+
? {
|
|
235
|
+
...child,
|
|
236
|
+
props: {
|
|
237
|
+
...(child.props || {}),
|
|
238
|
+
className: (child.props as { className?: string } | undefined)?.className
|
|
239
|
+
? `${(child.props as { className: string }).className} ${additionalClassName}`
|
|
240
|
+
: additionalClassName,
|
|
241
|
+
} as Record<string, unknown>,
|
|
242
|
+
}
|
|
243
|
+
: child
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<ComponentRenderer
|
|
247
|
+
key={`${breakpoint}-${index}`}
|
|
248
|
+
component={childWithVisibility}
|
|
249
|
+
pageVars={props.pageVars}
|
|
250
|
+
components={props.components}
|
|
251
|
+
theme={props.theme}
|
|
252
|
+
languages={props.languages}
|
|
253
|
+
currentLang={props.currentLang}
|
|
254
|
+
childIndex={index}
|
|
255
|
+
/>
|
|
256
|
+
)
|
|
257
|
+
},
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Renders direct component (non-reference)
|
|
263
|
+
*
|
|
264
|
+
* This is a React component (not a helper function) because it uses the useId hook.
|
|
265
|
+
* React components must start with an uppercase letter.
|
|
266
|
+
*
|
|
267
|
+
* @param component - Direct component
|
|
268
|
+
* @param props - Component renderer props
|
|
269
|
+
* @returns Rendered component
|
|
270
|
+
*/
|
|
271
|
+
function RenderDirectComponent({
|
|
272
|
+
component,
|
|
273
|
+
props,
|
|
274
|
+
}: {
|
|
275
|
+
component: Component
|
|
276
|
+
props: ComponentRendererProps
|
|
277
|
+
}): ReactElement | null {
|
|
278
|
+
// Apply page-level variable substitution if pageVars are provided
|
|
279
|
+
const substitutedComponent = applyVariableSubstitution(component, props.pageVars)
|
|
280
|
+
|
|
281
|
+
const {
|
|
282
|
+
type,
|
|
283
|
+
props: componentProps,
|
|
284
|
+
children,
|
|
285
|
+
content,
|
|
286
|
+
interactions,
|
|
287
|
+
i18n,
|
|
288
|
+
responsive,
|
|
289
|
+
} = substitutedComponent
|
|
290
|
+
const uniqueId = useId()
|
|
291
|
+
const currentBreakpoint = useBreakpoint()
|
|
292
|
+
|
|
293
|
+
// Merge responsive props using extracted module
|
|
294
|
+
const {
|
|
295
|
+
mergedProps: mergedPropsWithVisibility,
|
|
296
|
+
mergedChildren,
|
|
297
|
+
mergedContent,
|
|
298
|
+
} = mergeResponsiveProps(responsive, componentProps, children, content, currentBreakpoint)
|
|
299
|
+
|
|
300
|
+
const { elementProps, elementPropsWithSpacing } = buildComponentProps({
|
|
301
|
+
type,
|
|
302
|
+
props: mergedPropsWithVisibility,
|
|
303
|
+
children: mergedChildren,
|
|
304
|
+
content: typeof mergedContent === 'string' ? mergedContent : undefined,
|
|
305
|
+
componentName: props.componentName,
|
|
306
|
+
componentInstanceIndex: props.componentInstanceIndex,
|
|
307
|
+
theme: props.theme,
|
|
308
|
+
languages: props.languages,
|
|
309
|
+
currentLang: props.currentLang,
|
|
310
|
+
childIndex: props.childIndex,
|
|
311
|
+
interactions,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
// Build interaction props using extracted module
|
|
315
|
+
const {
|
|
316
|
+
finalElementProps: interactionElementProps,
|
|
317
|
+
finalElementPropsWithSpacing: interactionElementPropsWithSpacing,
|
|
318
|
+
hoverData,
|
|
319
|
+
} = buildInteractionProps(interactions, uniqueId, elementProps, elementPropsWithSpacing)
|
|
320
|
+
|
|
321
|
+
const baseRenderedChildren = renderChildren(mergedChildren, props)
|
|
322
|
+
|
|
323
|
+
// Resolve i18n content using extracted module
|
|
324
|
+
const { resolvedContent, finalElementProps, finalElementPropsWithSpacing } = resolveI18nContent(
|
|
325
|
+
mergedContent,
|
|
326
|
+
i18n,
|
|
327
|
+
props.currentLang,
|
|
328
|
+
props.languages,
|
|
329
|
+
interactionElementProps,
|
|
330
|
+
interactionElementPropsWithSpacing
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
// Add data-component-type attribute for testing
|
|
334
|
+
const finalElementPropsWithType = addComponentTypeAttribute(finalElementProps, type)
|
|
335
|
+
const finalElementPropsWithSpacingAndType = addComponentTypeAttribute(
|
|
336
|
+
finalElementPropsWithSpacing,
|
|
337
|
+
type
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
// Check if component has meta property with structured data
|
|
341
|
+
const meta = componentProps?.meta as ComponentMeta | undefined
|
|
342
|
+
const structuredDataScript = meta ? <StructuredDataFromComponent meta={meta} /> : undefined
|
|
343
|
+
|
|
344
|
+
// Check if component has responsive content overrides
|
|
345
|
+
if (hasResponsiveContentOverrides(responsive)) {
|
|
346
|
+
return renderWithResponsiveContent({
|
|
347
|
+
responsive,
|
|
348
|
+
type,
|
|
349
|
+
finalElementPropsWithType,
|
|
350
|
+
finalElementPropsWithSpacingAndType,
|
|
351
|
+
hoverData,
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Check if component has responsive children overrides
|
|
356
|
+
const finalRenderedChildren = hasResponsiveChildrenOverrides(responsive)
|
|
357
|
+
? buildResponsiveChildren(responsive, baseRenderedChildren, props)
|
|
358
|
+
: baseRenderedChildren
|
|
359
|
+
|
|
360
|
+
// Inject structured data script as first child if it exists
|
|
361
|
+
const finalChildren = structuredDataScript
|
|
362
|
+
? ([structuredDataScript, ...finalRenderedChildren] as readonly ReactElement[])
|
|
363
|
+
: finalRenderedChildren
|
|
364
|
+
|
|
365
|
+
// Default rendering without responsive content
|
|
366
|
+
const renderedComponent = dispatchComponentType({
|
|
367
|
+
type,
|
|
368
|
+
elementProps: finalElementPropsWithType,
|
|
369
|
+
elementPropsWithSpacing: finalElementPropsWithSpacingAndType,
|
|
370
|
+
content:
|
|
371
|
+
resolvedContent !== undefined
|
|
372
|
+
? resolvedContent
|
|
373
|
+
: typeof mergedContent === 'string'
|
|
374
|
+
? mergedContent
|
|
375
|
+
: undefined,
|
|
376
|
+
renderedChildren: finalChildren,
|
|
377
|
+
theme: props.theme,
|
|
378
|
+
languages: props.languages,
|
|
379
|
+
interactions,
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
if (hoverData) {
|
|
383
|
+
return (
|
|
384
|
+
<Fragment>
|
|
385
|
+
<style>{hoverData.styleContent}</style>
|
|
386
|
+
{renderedComponent}
|
|
387
|
+
</Fragment>
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return renderedComponent
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* ComponentRenderer - Renders a dynamic component based on its type
|
|
396
|
+
*
|
|
397
|
+
* This component handles the recursive rendering of sections, converting
|
|
398
|
+
* the declarative component configuration into React elements.
|
|
399
|
+
* Supports component references for reusable components and theme token substitution.
|
|
400
|
+
*
|
|
401
|
+
* @param props - Component props
|
|
402
|
+
* @param props.component - Component configuration from sections schema (can be a direct component or component reference)
|
|
403
|
+
* @param props.componentName - Optional component template name for data-component attribute
|
|
404
|
+
* @param props.componentInstanceIndex - Optional instance index for components used multiple times (for unique data-testid)
|
|
405
|
+
* @param props.components - Optional components array for resolving component references
|
|
406
|
+
* @param props.theme - Optional theme configuration for token substitution
|
|
407
|
+
* @param props.languages - Optional languages configuration for language-switcher components
|
|
408
|
+
* @param props.currentLang - Current page language (defaults to languages.default)
|
|
409
|
+
* @returns React element matching the component type
|
|
410
|
+
*/
|
|
411
|
+
export function ComponentRenderer(props: ComponentRendererProps): Readonly<ReactElement | null> {
|
|
412
|
+
const { component } = props
|
|
413
|
+
|
|
414
|
+
// Handle component references - supports both { component: 'name' } and { $ref: 'name' } syntaxes
|
|
415
|
+
if ('component' in component || '$ref' in component) {
|
|
416
|
+
return renderComponentReference(component, props)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Direct component rendering
|
|
420
|
+
return (
|
|
421
|
+
<RenderDirectComponent
|
|
422
|
+
component={component as Component}
|
|
423
|
+
props={props}
|
|
424
|
+
/>
|
|
425
|
+
)
|
|
426
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 {
|
|
9
|
+
ComponentReference,
|
|
10
|
+
SimpleComponentReference,
|
|
11
|
+
} from '@/domain/models/app/component/common/component-reference'
|
|
12
|
+
import type { Components } from '@/domain/models/app/components'
|
|
13
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
14
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
15
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ComponentRenderer Props
|
|
19
|
+
*/
|
|
20
|
+
export type ComponentRendererProps = {
|
|
21
|
+
readonly component: Component | SimpleComponentReference | ComponentReference
|
|
22
|
+
readonly componentName?: string
|
|
23
|
+
readonly componentInstanceIndex?: number
|
|
24
|
+
readonly components?: Components
|
|
25
|
+
readonly theme?: Theme
|
|
26
|
+
readonly languages?: Languages
|
|
27
|
+
readonly currentLang?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Component types that should receive role="group" when used as component references with children
|
|
32
|
+
*/
|
|
33
|
+
export const CONTAINER_TYPES = ['div', 'container', 'flex', 'grid', 'card', 'badge'] as const
|
|
@@ -0,0 +1,74 @@
|
|
|
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 {
|
|
9
|
+
ComponentReference,
|
|
10
|
+
SimpleComponentReference,
|
|
11
|
+
} from '@/domain/models/app/component/common/component-reference'
|
|
12
|
+
import type { Components } from '@/domain/models/app/components'
|
|
13
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
14
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
15
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
16
|
+
import type { ReactElement } from 'react'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for rendering a component reference error
|
|
20
|
+
*/
|
|
21
|
+
interface ComponentReferenceErrorProps {
|
|
22
|
+
readonly refName: string
|
|
23
|
+
readonly components: Components | undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Render an error message for missing component references
|
|
28
|
+
*/
|
|
29
|
+
export function renderComponentReferenceError({
|
|
30
|
+
refName,
|
|
31
|
+
components,
|
|
32
|
+
}: ComponentReferenceErrorProps): ReactElement {
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
style={{
|
|
36
|
+
padding: '1rem',
|
|
37
|
+
border: '2px dashed red',
|
|
38
|
+
color: 'red',
|
|
39
|
+
fontFamily: 'monospace',
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
Component not found: "{refName}"
|
|
43
|
+
<br />
|
|
44
|
+
<small>Available components: {components?.map((b) => b.name).join(', ') || 'none'}</small>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Extract reference name and vars from component reference
|
|
51
|
+
*/
|
|
52
|
+
export function extractComponentReference(
|
|
53
|
+
component: SimpleComponentReference | ComponentReference
|
|
54
|
+
): {
|
|
55
|
+
refName: string
|
|
56
|
+
vars: Record<string, string | number | boolean> | undefined
|
|
57
|
+
} {
|
|
58
|
+
const refName = 'component' in component ? component.component : component.$ref
|
|
59
|
+
const vars = 'vars' in component ? component.vars : undefined
|
|
60
|
+
return { refName, vars }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Props for component reference rendering
|
|
65
|
+
*/
|
|
66
|
+
export interface ComponentReferenceRenderProps {
|
|
67
|
+
readonly component: Component
|
|
68
|
+
readonly componentName: string
|
|
69
|
+
readonly componentInstanceIndex: number | undefined
|
|
70
|
+
readonly components: Components | undefined
|
|
71
|
+
readonly theme: Theme | undefined
|
|
72
|
+
readonly languages: Languages | undefined
|
|
73
|
+
readonly currentLang: string | undefined
|
|
74
|
+
}
|