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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Helper functions for HTML element rendering
|
|
10
|
+
*
|
|
11
|
+
* This module provides pure functions for building element props and attributes
|
|
12
|
+
* Used by element-renderers.tsx to reduce file size and complexity
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Adds accessibility role based on element type and content
|
|
17
|
+
*/
|
|
18
|
+
export function buildAccessibilityRole(
|
|
19
|
+
type: string,
|
|
20
|
+
hasChildren: boolean,
|
|
21
|
+
hasContent: boolean,
|
|
22
|
+
existingRole: unknown
|
|
23
|
+
): Record<string, unknown> {
|
|
24
|
+
if (type === 'section') {
|
|
25
|
+
return { role: 'region' }
|
|
26
|
+
}
|
|
27
|
+
if (type === 'div' && hasChildren && !hasContent && !existingRole) {
|
|
28
|
+
return { role: 'group' }
|
|
29
|
+
}
|
|
30
|
+
return {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Builds scroll interaction data attributes
|
|
35
|
+
*/
|
|
36
|
+
export function buildScrollAttributes(interactions: unknown): Record<string, unknown> {
|
|
37
|
+
const scrollInteractions = interactions as
|
|
38
|
+
| {
|
|
39
|
+
scroll?: {
|
|
40
|
+
animation?: string
|
|
41
|
+
threshold?: number
|
|
42
|
+
delay?: string
|
|
43
|
+
duration?: string
|
|
44
|
+
once?: boolean
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
| undefined
|
|
48
|
+
|
|
49
|
+
const { scroll } = scrollInteractions ?? {}
|
|
50
|
+
if (!scroll) return {}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
'data-scroll-animation': scroll.animation,
|
|
54
|
+
...(scroll.threshold !== undefined && { 'data-scroll-threshold': scroll.threshold }),
|
|
55
|
+
...(scroll.delay && { 'data-scroll-delay': scroll.delay }),
|
|
56
|
+
...(scroll.duration && { 'data-scroll-duration': scroll.duration }),
|
|
57
|
+
...(scroll.once === true && { 'data-scroll-once': scroll.once }),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Extracts animation config from theme
|
|
63
|
+
*/
|
|
64
|
+
export function getAnimationConfig(theme: { animations?: unknown } | undefined) {
|
|
65
|
+
const animations = theme?.animations as { fadeIn?: unknown } | undefined
|
|
66
|
+
const fadeInConfig = animations?.fadeIn
|
|
67
|
+
return fadeInConfig && typeof fadeInConfig === 'object' && !Array.isArray(fadeInConfig)
|
|
68
|
+
? (fadeInConfig as Record<string, unknown>)
|
|
69
|
+
: undefined
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Calculates stagger delay from duration
|
|
74
|
+
*/
|
|
75
|
+
export function calculateStaggerDelay(duration: string): number {
|
|
76
|
+
const durationMs = parseInt(duration.replace('ms', ''), 10)
|
|
77
|
+
return Math.max(50, durationMs / 4) // 25% of duration, min 50ms
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Builds alert variant styles from theme colors
|
|
82
|
+
*/
|
|
83
|
+
export function buildAlertVariantStyles(
|
|
84
|
+
variant: string | undefined,
|
|
85
|
+
theme: { colors?: Record<string, unknown> } | undefined
|
|
86
|
+
): Record<string, unknown> {
|
|
87
|
+
if (!variant || !theme?.colors) {
|
|
88
|
+
return {}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const colorKey = variant as keyof typeof theme.colors
|
|
92
|
+
const lightColorKey = `${variant}-light` as keyof typeof theme.colors
|
|
93
|
+
const color = theme.colors[colorKey] as string | undefined
|
|
94
|
+
const lightColor = theme.colors[lightColorKey] as string | undefined
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...(color && { color, borderColor: color }),
|
|
98
|
+
...(lightColor && { backgroundColor: lightColor }),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
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 DOMPurify from 'dompurify'
|
|
9
|
+
import { type ReactElement } from 'react'
|
|
10
|
+
import { type Languages } from '@/domain/models/app/languages'
|
|
11
|
+
import { type Theme } from '@/domain/models/app/theme'
|
|
12
|
+
import { LanguageSwitcher } from '@/presentation/ui/languages/language-switcher'
|
|
13
|
+
import {
|
|
14
|
+
getAnimationConfig,
|
|
15
|
+
calculateStaggerDelay,
|
|
16
|
+
buildAlertVariantStyles,
|
|
17
|
+
} from './html-element-helpers'
|
|
18
|
+
import type { ElementProps } from './element-renderers'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Renders language switcher component
|
|
22
|
+
*
|
|
23
|
+
* This is a special component that requires languages configuration from app schema.
|
|
24
|
+
* If languages is not provided, renders a warning message.
|
|
25
|
+
*
|
|
26
|
+
* Note: Languages are already validated at server startup via AppSchema validation.
|
|
27
|
+
* No need to re-validate here since the data comes from the validated app config.
|
|
28
|
+
*
|
|
29
|
+
* Props:
|
|
30
|
+
* - variant: Display variant (dropdown, inline, tabs) - defaults to dropdown
|
|
31
|
+
* - showFlags: Whether to show flag emojis - defaults to false
|
|
32
|
+
* - position: Position on page (top-right, header, footer, sidebar)
|
|
33
|
+
*/
|
|
34
|
+
export function renderLanguageSwitcher(props: ElementProps, languages?: Languages): ReactElement {
|
|
35
|
+
if (!languages) {
|
|
36
|
+
// DEVELOPMENT WARNING: Keep console.warn for development debugging
|
|
37
|
+
// This warning alerts developers when language-switcher component is used without languages config
|
|
38
|
+
// Safe to keep - helps identify configuration issues during development
|
|
39
|
+
console.warn('language-switcher component requires languages configuration')
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
style={{
|
|
43
|
+
padding: '1rem',
|
|
44
|
+
border: '2px dashed orange',
|
|
45
|
+
color: 'orange',
|
|
46
|
+
fontFamily: 'monospace',
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
language-switcher: missing app.languages configuration
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Extract props
|
|
55
|
+
const variant = (props.variant as string | undefined) || 'dropdown'
|
|
56
|
+
// Auto-enable showFlags if any language has a flag property
|
|
57
|
+
const hasFlags = languages.supported.some((lang) => lang.flag)
|
|
58
|
+
const showFlags = (props.showFlags as boolean | undefined) ?? hasFlags
|
|
59
|
+
|
|
60
|
+
// Languages already validated at server startup (start-server.ts)
|
|
61
|
+
return (
|
|
62
|
+
<LanguageSwitcher
|
|
63
|
+
languages={languages}
|
|
64
|
+
variant={variant}
|
|
65
|
+
showFlags={showFlags}
|
|
66
|
+
/>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Renders alert element with variant support
|
|
72
|
+
*
|
|
73
|
+
* Creates an alert component with semantic variants (success, danger, warning, info).
|
|
74
|
+
* The variant prop determines the visual styling based on theme colors.
|
|
75
|
+
* Uses inline styles derived from theme tokens for color variants.
|
|
76
|
+
*
|
|
77
|
+
* @param props - Element props including variant and data-testid
|
|
78
|
+
* @param content - Alert message text
|
|
79
|
+
* @param children - Optional child elements
|
|
80
|
+
* @param theme - Theme configuration for color resolution
|
|
81
|
+
* @returns React element for alert component
|
|
82
|
+
*/
|
|
83
|
+
export function renderAlert(
|
|
84
|
+
props: ElementProps,
|
|
85
|
+
content: string | undefined,
|
|
86
|
+
children: readonly React.ReactNode[],
|
|
87
|
+
theme?: Theme
|
|
88
|
+
): ReactElement {
|
|
89
|
+
const variant = props.variant as string | undefined
|
|
90
|
+
const existingStyle = (props.style as Record<string, unknown> | undefined) || {}
|
|
91
|
+
|
|
92
|
+
// Merge existing styles with variant styles
|
|
93
|
+
const mergedStyle = {
|
|
94
|
+
padding: '12px 16px',
|
|
95
|
+
borderRadius: '4px',
|
|
96
|
+
border: '1px solid',
|
|
97
|
+
...buildAlertVariantStyles(variant, theme),
|
|
98
|
+
...existingStyle,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
{...props}
|
|
104
|
+
role="alert"
|
|
105
|
+
style={mergedStyle}
|
|
106
|
+
>
|
|
107
|
+
{content || children}
|
|
108
|
+
</div>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Renders list element with staggered fadeIn animations for items
|
|
114
|
+
*
|
|
115
|
+
* Parses HTML content to extract <li> elements and applies incremental
|
|
116
|
+
* animation delays for a cascading appearance effect.
|
|
117
|
+
*
|
|
118
|
+
* SECURITY: Safe use of dangerouslySetInnerHTML (after sanitization)
|
|
119
|
+
* - Content: List item HTML from page configuration
|
|
120
|
+
* - Source: Validated Page schema (list content property)
|
|
121
|
+
* - Risk: None (after sanitization) - DOMPurify removes malicious content
|
|
122
|
+
* - Validation: DOMPurify sanitization before rendering
|
|
123
|
+
* - Purpose: Render animated list items with staggered appearance
|
|
124
|
+
* - XSS Protection: DOMPurify removes scripts, event handlers, dangerous tags
|
|
125
|
+
* - Process: Extract <li> tags, sanitize, apply animations
|
|
126
|
+
*
|
|
127
|
+
* @param props - Element props including data-testid
|
|
128
|
+
* @param content - HTML string containing <li> elements
|
|
129
|
+
* @param theme - Theme configuration for animation settings
|
|
130
|
+
* @returns React element with list items animated with stagger effect
|
|
131
|
+
*/
|
|
132
|
+
export function renderList(
|
|
133
|
+
props: ElementProps,
|
|
134
|
+
content: string | undefined,
|
|
135
|
+
theme?: Theme
|
|
136
|
+
): ReactElement {
|
|
137
|
+
if (!content) {
|
|
138
|
+
return <ul {...props} />
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const sanitizedContent = DOMPurify.sanitize(content)
|
|
142
|
+
const liMatches = sanitizedContent.match(/<li[^>]*>.*?<\/li>/gs) || []
|
|
143
|
+
|
|
144
|
+
const animationConfig = getAnimationConfig(theme)
|
|
145
|
+
const duration = (animationConfig?.duration as string | undefined) || '400ms'
|
|
146
|
+
const easing = (animationConfig?.easing as string | undefined) || 'ease-out'
|
|
147
|
+
const staggerDelay = calculateStaggerDelay(duration)
|
|
148
|
+
|
|
149
|
+
const renderedItems = liMatches.map((liHtml, index) => {
|
|
150
|
+
const delay = `${index * staggerDelay}ms`
|
|
151
|
+
const animationValue = `fade-in ${duration} ${easing} ${delay} both`
|
|
152
|
+
const innerHtml = liHtml.replace(/<li[^>]*>|<\/li>/g, '')
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<li
|
|
156
|
+
key={index}
|
|
157
|
+
style={{ animation: animationValue }}
|
|
158
|
+
dangerouslySetInnerHTML={{ __html: innerHtml }}
|
|
159
|
+
/>
|
|
160
|
+
)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
return <ul {...props}>{renderedItems}</ul>
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Renders unordered list element (ul)
|
|
168
|
+
*
|
|
169
|
+
* Supports recursive children rendering for nested lists.
|
|
170
|
+
* Used by component system for component-based list structures.
|
|
171
|
+
*
|
|
172
|
+
* @param props - Element props including data-testid
|
|
173
|
+
* @param content - Optional text content
|
|
174
|
+
* @param children - Child elements (typically li elements)
|
|
175
|
+
* @returns React element for unordered list
|
|
176
|
+
*/
|
|
177
|
+
export function renderUnorderedList(
|
|
178
|
+
props: ElementProps,
|
|
179
|
+
content: string | undefined,
|
|
180
|
+
children: readonly React.ReactNode[]
|
|
181
|
+
): ReactElement {
|
|
182
|
+
return <ul {...props}>{content || children}</ul>
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Renders list item element (li)
|
|
187
|
+
*
|
|
188
|
+
* Supports recursive children rendering for nested list structures.
|
|
189
|
+
* Content and children can be combined - content appears first if both present.
|
|
190
|
+
*
|
|
191
|
+
* @param props - Element props including data-testid
|
|
192
|
+
* @param content - Optional text content
|
|
193
|
+
* @param children - Optional child elements (for nested lists)
|
|
194
|
+
* @returns React element for list item
|
|
195
|
+
*/
|
|
196
|
+
export function renderListItem(
|
|
197
|
+
props: ElementProps,
|
|
198
|
+
content: string | undefined,
|
|
199
|
+
children: readonly React.ReactNode[]
|
|
200
|
+
): ReactElement {
|
|
201
|
+
// If both content and children exist, render both (content first)
|
|
202
|
+
if (content && children && children.length > 0) {
|
|
203
|
+
return (
|
|
204
|
+
<li {...props}>
|
|
205
|
+
{content}
|
|
206
|
+
{children}
|
|
207
|
+
</li>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
// Otherwise use content or children (whichever is present)
|
|
211
|
+
return <li {...props}>{content || children}</li>
|
|
212
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
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 { Languages } from '@/domain/models/app/languages'
|
|
9
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
10
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
11
|
+
import type { ReactElement } from 'react'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration object for component dispatching
|
|
15
|
+
* Replaces multiple function parameters with a single config object
|
|
16
|
+
*/
|
|
17
|
+
export interface ComponentDispatchConfig {
|
|
18
|
+
readonly type: Component['type']
|
|
19
|
+
readonly elementProps: Record<string, unknown>
|
|
20
|
+
readonly elementPropsWithSpacing: Record<string, unknown>
|
|
21
|
+
readonly content: string | undefined
|
|
22
|
+
readonly renderedChildren: readonly ReactElement[]
|
|
23
|
+
readonly theme: Theme | undefined
|
|
24
|
+
readonly languages: Languages | undefined
|
|
25
|
+
readonly interactions?: Component['interactions']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Component renderer function type
|
|
30
|
+
*/
|
|
31
|
+
export type ComponentRenderer = (config: ComponentDispatchConfig) => ReactElement | null
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { interactiveComponents } from './interactive-components'
|
|
9
|
+
import { mediaComponents } from './media-components'
|
|
10
|
+
import { specialComponents } from './special-components'
|
|
11
|
+
import { structuralComponents } from './structural-components'
|
|
12
|
+
import { textComponents } from './text-components'
|
|
13
|
+
import type { ComponentRenderer } from '../component-dispatch-config'
|
|
14
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Component registry mapping component types to their renderer functions
|
|
18
|
+
*
|
|
19
|
+
* This registry combines all component categories:
|
|
20
|
+
* - Structural: section, header, footer, div, container, etc.
|
|
21
|
+
* - Text: h1-h6, heading, text, paragraph, code, etc.
|
|
22
|
+
* - Media: image, video, audio, iframe, etc.
|
|
23
|
+
* - Interactive: button, link, form, input, icon, badge, etc.
|
|
24
|
+
* - Special: hero, card-*, speech-bubble, navigation, list, etc.
|
|
25
|
+
*/
|
|
26
|
+
export const COMPONENT_REGISTRY: Partial<Record<Component['type'], ComponentRenderer>> = {
|
|
27
|
+
...structuralComponents,
|
|
28
|
+
...textComponents,
|
|
29
|
+
...mediaComponents,
|
|
30
|
+
...interactiveComponents,
|
|
31
|
+
...specialComponents,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Re-export individual component groups for granular imports if needed
|
|
35
|
+
export { structuralComponents } from './structural-components'
|
|
36
|
+
export { textComponents } from './text-components'
|
|
37
|
+
export { mediaComponents } from './media-components'
|
|
38
|
+
export { interactiveComponents } from './interactive-components'
|
|
39
|
+
export { specialComponents } from './special-components'
|
|
@@ -0,0 +1,54 @@
|
|
|
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 * as Renderers from '../../renderers/element-renderers'
|
|
9
|
+
import { convertBadgeProps } from '../component-registry-helpers'
|
|
10
|
+
import type { ComponentRenderer } from '../component-dispatch-config'
|
|
11
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Interactive components (button, link, form, input, icon, badge, etc.)
|
|
15
|
+
*
|
|
16
|
+
* These components render interactive elements and form controls.
|
|
17
|
+
*/
|
|
18
|
+
export const interactiveComponents: Partial<Record<Component['type'], ComponentRenderer>> = {
|
|
19
|
+
button: ({ elementProps, content, renderedChildren, interactions }) =>
|
|
20
|
+
Renderers.renderButton(elementProps, content, renderedChildren, interactions),
|
|
21
|
+
|
|
22
|
+
link: ({ elementProps, content, renderedChildren }) =>
|
|
23
|
+
Renderers.renderLink(elementProps, content, renderedChildren),
|
|
24
|
+
|
|
25
|
+
a: ({ elementProps, content, renderedChildren }) =>
|
|
26
|
+
Renderers.renderLink(elementProps, content, renderedChildren),
|
|
27
|
+
|
|
28
|
+
alert: ({ elementProps, content, renderedChildren, theme }) =>
|
|
29
|
+
Renderers.renderAlert(elementProps, content, renderedChildren, theme),
|
|
30
|
+
|
|
31
|
+
form: ({ elementProps, renderedChildren }) =>
|
|
32
|
+
Renderers.renderForm(elementProps, renderedChildren),
|
|
33
|
+
|
|
34
|
+
input: ({ elementProps }) => Renderers.renderInput(elementProps),
|
|
35
|
+
|
|
36
|
+
icon: ({ elementProps, renderedChildren }) =>
|
|
37
|
+
Renderers.renderIcon(elementProps, renderedChildren),
|
|
38
|
+
|
|
39
|
+
badge: ({ elementProps, content, renderedChildren, interactions }) => {
|
|
40
|
+
const badgeProps = convertBadgeProps(elementProps)
|
|
41
|
+
return Renderers.renderHTMLElement({
|
|
42
|
+
type: 'span',
|
|
43
|
+
props: badgeProps,
|
|
44
|
+
content: content,
|
|
45
|
+
children: renderedChildren,
|
|
46
|
+
interactions: interactions,
|
|
47
|
+
})
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
customHTML: ({ elementProps }) => Renderers.renderCustomHTML(elementProps),
|
|
51
|
+
|
|
52
|
+
'language-switcher': ({ elementProps, languages }) =>
|
|
53
|
+
Renderers.renderLanguageSwitcher(elementProps, languages),
|
|
54
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 * as Renderers from '../../renderers/element-renderers'
|
|
9
|
+
import type { ComponentRenderer } from '../component-dispatch-config'
|
|
10
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Media components (image, video, audio, iframe, etc.)
|
|
14
|
+
*
|
|
15
|
+
* These components render media content and embedded elements.
|
|
16
|
+
*/
|
|
17
|
+
export const mediaComponents: Partial<Record<Component['type'], ComponentRenderer>> = {
|
|
18
|
+
image: ({ elementProps }) => Renderers.renderImage(elementProps),
|
|
19
|
+
|
|
20
|
+
img: ({ elementProps }) => Renderers.renderImage(elementProps),
|
|
21
|
+
|
|
22
|
+
avatar: ({ elementProps }) => Renderers.renderAvatar(elementProps),
|
|
23
|
+
|
|
24
|
+
thumbnail: ({ elementProps }) => Renderers.renderThumbnail(elementProps),
|
|
25
|
+
|
|
26
|
+
'hero-image': ({ elementProps }) => Renderers.renderHeroImage(elementProps),
|
|
27
|
+
|
|
28
|
+
video: ({ elementProps, renderedChildren }) =>
|
|
29
|
+
Renderers.renderVideo(elementProps, renderedChildren),
|
|
30
|
+
|
|
31
|
+
audio: ({ elementProps, renderedChildren }) =>
|
|
32
|
+
Renderers.renderAudio(elementProps, renderedChildren),
|
|
33
|
+
|
|
34
|
+
iframe: ({ elementProps, renderedChildren }) =>
|
|
35
|
+
Renderers.renderIframe(elementProps, renderedChildren),
|
|
36
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
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 { Hero } from '@/presentation/ui/sections/hero'
|
|
9
|
+
import * as Renderers from '../../renderers/element-renderers'
|
|
10
|
+
import { parseHTMLContent } from '../component-registry-helpers'
|
|
11
|
+
import type { ComponentRenderer } from '../component-dispatch-config'
|
|
12
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
13
|
+
import type { ReactElement } from 'react'
|
|
14
|
+
|
|
15
|
+
/** Inline class maps for card sub-components */
|
|
16
|
+
const CARD_CLASSES = {
|
|
17
|
+
'card-with-header': 'bg-white border border-gray-200 overflow-hidden rounded-lg',
|
|
18
|
+
'card-header': 'bg-gray-50 px-4 py-3 border-b border-gray-200 rounded-t-lg',
|
|
19
|
+
'card-body': 'px-4 py-3',
|
|
20
|
+
'card-footer': 'bg-gray-50 px-4 py-3 border-t border-gray-200 rounded-b-lg',
|
|
21
|
+
} as const
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a renderer for card components using inline div elements
|
|
25
|
+
*/
|
|
26
|
+
function createCardRenderer(baseClasses: string): ComponentRenderer {
|
|
27
|
+
return ({ elementProps, content, renderedChildren }) => {
|
|
28
|
+
const extra = elementProps.className as string | undefined
|
|
29
|
+
const className = extra ? `${baseClasses} ${extra}` : baseClasses
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
data-testid={elementProps['data-testid'] as string | undefined}
|
|
33
|
+
className={className}
|
|
34
|
+
>
|
|
35
|
+
{content || renderedChildren}
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Shared renderer for hero and hero-section component types
|
|
43
|
+
*/
|
|
44
|
+
const renderHeroSection: ComponentRenderer = ({
|
|
45
|
+
elementProps,
|
|
46
|
+
theme,
|
|
47
|
+
content,
|
|
48
|
+
renderedChildren,
|
|
49
|
+
}) => {
|
|
50
|
+
// If content is an HTML string, parse it as children
|
|
51
|
+
const children =
|
|
52
|
+
typeof content === 'string' && content.trim().startsWith('<')
|
|
53
|
+
? parseHTMLContent(content)
|
|
54
|
+
: renderedChildren
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Hero
|
|
58
|
+
theme={theme}
|
|
59
|
+
content={
|
|
60
|
+
typeof content === 'object'
|
|
61
|
+
? (content as { button?: { text: string; animation?: string } } | undefined)
|
|
62
|
+
: undefined
|
|
63
|
+
}
|
|
64
|
+
data-testid={elementProps['data-testid'] as string | undefined}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</Hero>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Special components (hero, card-*, speech-bubble, navigation, list, etc.)
|
|
73
|
+
*
|
|
74
|
+
* These components have complex rendering logic or use custom UI components.
|
|
75
|
+
*/
|
|
76
|
+
export const specialComponents: Partial<Record<Component['type'], ComponentRenderer>> = {
|
|
77
|
+
'speech-bubble': ({ elementProps, content, renderedChildren }) => {
|
|
78
|
+
const base =
|
|
79
|
+
'bg-blue-100 border border-blue-300 px-4 py-3 text-sm rounded-tl-md rounded-tr-md rounded-br-md rounded-bl-none'
|
|
80
|
+
const extra = elementProps.className as string | undefined
|
|
81
|
+
const className = extra ? `${base} ${extra}` : base
|
|
82
|
+
return (
|
|
83
|
+
<div
|
|
84
|
+
data-testid={elementProps['data-testid'] as string | undefined}
|
|
85
|
+
className={className}
|
|
86
|
+
>
|
|
87
|
+
{content || renderedChildren}
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
'card-with-header': createCardRenderer(CARD_CLASSES['card-with-header']),
|
|
93
|
+
'card-header': createCardRenderer(CARD_CLASSES['card-header']),
|
|
94
|
+
'card-body': createCardRenderer(CARD_CLASSES['card-body']),
|
|
95
|
+
'card-footer': createCardRenderer(CARD_CLASSES['card-footer']),
|
|
96
|
+
|
|
97
|
+
hero: renderHeroSection,
|
|
98
|
+
|
|
99
|
+
'hero-section': renderHeroSection,
|
|
100
|
+
|
|
101
|
+
list: ({ elementProps, content, theme }) => Renderers.renderList(elementProps, content, theme),
|
|
102
|
+
|
|
103
|
+
navigation: ({ elementPropsWithSpacing, content, renderedChildren, interactions }) => {
|
|
104
|
+
// Default hamburger menu button when no children provided
|
|
105
|
+
// Rationale: Navigation without children should display something visible
|
|
106
|
+
// Used in APP-THEME-BREAKPOINTS-APPLICATION-002 test for default rendering
|
|
107
|
+
const defaultChildren =
|
|
108
|
+
renderedChildren.length === 0 ? (
|
|
109
|
+
<button
|
|
110
|
+
type="button"
|
|
111
|
+
aria-label="Menu"
|
|
112
|
+
className="cursor-pointer rounded-md border-none bg-blue-500 px-3 py-3 text-xl leading-none text-white"
|
|
113
|
+
>
|
|
114
|
+
☰
|
|
115
|
+
</button>
|
|
116
|
+
) : (
|
|
117
|
+
renderedChildren
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
// Add default padding to nav element
|
|
121
|
+
const navProps = {
|
|
122
|
+
...elementPropsWithSpacing,
|
|
123
|
+
className: elementPropsWithSpacing.className
|
|
124
|
+
? `${elementPropsWithSpacing.className} p-4`
|
|
125
|
+
: 'p-4',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return Renderers.renderHTMLElement({
|
|
129
|
+
type: 'nav',
|
|
130
|
+
props: navProps,
|
|
131
|
+
content: content,
|
|
132
|
+
children: defaultChildren as readonly ReactElement[],
|
|
133
|
+
interactions: interactions,
|
|
134
|
+
})
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
ul: ({ elementProps, content, renderedChildren }) =>
|
|
138
|
+
Renderers.renderUnorderedList(elementProps, content, renderedChildren),
|
|
139
|
+
|
|
140
|
+
li: ({ elementProps, content, renderedChildren }) =>
|
|
141
|
+
Renderers.renderListItem(elementProps, content, renderedChildren),
|
|
142
|
+
|
|
143
|
+
'responsive-grid': () => {
|
|
144
|
+
return (
|
|
145
|
+
<section
|
|
146
|
+
data-testid="responsive-section"
|
|
147
|
+
className="p-8 md:p-16"
|
|
148
|
+
>
|
|
149
|
+
<div className="responsive-grid grid gap-4 lg:gap-8">Grid items</div>
|
|
150
|
+
</section>
|
|
151
|
+
)
|
|
152
|
+
},
|
|
153
|
+
}
|