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,179 @@
|
|
|
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 { CONTAINER_TYPES } from '../component-renderer.types'
|
|
9
|
+
import { buildFlexClasses, buildGridClasses } from '../styling/class-builders'
|
|
10
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build data-testid based on component name and instance index
|
|
14
|
+
*/
|
|
15
|
+
export function buildTestId(
|
|
16
|
+
componentName?: string,
|
|
17
|
+
componentInstanceIndex?: number,
|
|
18
|
+
type?: string,
|
|
19
|
+
substitutedProps?: Record<string, unknown>
|
|
20
|
+
): string | undefined {
|
|
21
|
+
if (componentName) {
|
|
22
|
+
return componentInstanceIndex !== undefined
|
|
23
|
+
? `component-${componentName}-${componentInstanceIndex}`
|
|
24
|
+
: `component-${componentName}`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const dataTestId = substitutedProps?.['data-testid']
|
|
28
|
+
if (typeof dataTestId === 'string') {
|
|
29
|
+
return dataTestId
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Auto-generate testid for common component types to support testing
|
|
33
|
+
if (type === 'container') return 'container'
|
|
34
|
+
if (type === 'flex') return 'flex'
|
|
35
|
+
if (type === 'text') return 'text'
|
|
36
|
+
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Component types that have corresponding CSS classes
|
|
42
|
+
* These types will automatically get their type name added as a CSS class
|
|
43
|
+
*/
|
|
44
|
+
const COMPONENT_TYPES_WITH_CSS_CLASSES = new Set(['card', 'badge'])
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Build final className based on component type
|
|
48
|
+
*/
|
|
49
|
+
export function buildClassName(
|
|
50
|
+
type: string,
|
|
51
|
+
substitutedProps?: Record<string, unknown>
|
|
52
|
+
): string | undefined {
|
|
53
|
+
if (type === 'flex') {
|
|
54
|
+
return [buildFlexClasses(substitutedProps), substitutedProps?.className]
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.join(' ')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (type === 'grid') {
|
|
60
|
+
return [buildGridClasses(substitutedProps), substitutedProps?.className]
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.join(' ')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Auto-apply component type as CSS class for types with CSS definitions
|
|
66
|
+
if (COMPONENT_TYPES_WITH_CSS_CLASSES.has(type)) {
|
|
67
|
+
return [type, substitutedProps?.className].filter(Boolean).join(' ')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return substitutedProps?.className as string | undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build component data attributes
|
|
75
|
+
*/
|
|
76
|
+
function buildComponentDataAttrs(componentName?: string, type?: string) {
|
|
77
|
+
if (!componentName) {
|
|
78
|
+
return {}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
'data-component': componentName,
|
|
82
|
+
'data-type': type,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build translation data attributes
|
|
88
|
+
*/
|
|
89
|
+
function buildTranslationDataAttrs(
|
|
90
|
+
firstTranslationKey?: string,
|
|
91
|
+
translationData?: Record<string, unknown>
|
|
92
|
+
) {
|
|
93
|
+
if (!firstTranslationKey || !translationData) {
|
|
94
|
+
return {}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
'data-translation-key': firstTranslationKey,
|
|
98
|
+
'data-translations': JSON.stringify(translationData),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Build empty content style
|
|
104
|
+
*/
|
|
105
|
+
function buildEmptyStyle(
|
|
106
|
+
componentName?: string,
|
|
107
|
+
type?: string,
|
|
108
|
+
hasContent?: boolean,
|
|
109
|
+
styleWithShadow?: Record<string, unknown>
|
|
110
|
+
) {
|
|
111
|
+
if (componentName && !hasContent) {
|
|
112
|
+
return {
|
|
113
|
+
...styleWithShadow,
|
|
114
|
+
minHeight: '1px',
|
|
115
|
+
minWidth: '1px',
|
|
116
|
+
display: 'inline-block',
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!componentName && type === 'grid' && !hasContent) {
|
|
120
|
+
return {
|
|
121
|
+
...styleWithShadow,
|
|
122
|
+
minHeight: '100px',
|
|
123
|
+
minWidth: '100px',
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return styleWithShadow
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build element props including data attributes, ARIA, and styling
|
|
131
|
+
*/
|
|
132
|
+
export function buildElementProps({
|
|
133
|
+
component,
|
|
134
|
+
substitutedProps,
|
|
135
|
+
finalClassName,
|
|
136
|
+
styleWithShadow,
|
|
137
|
+
testId,
|
|
138
|
+
componentName,
|
|
139
|
+
firstTranslationKey,
|
|
140
|
+
translationData,
|
|
141
|
+
hasScrollAnimation,
|
|
142
|
+
hasContent,
|
|
143
|
+
children,
|
|
144
|
+
}: {
|
|
145
|
+
readonly component: Component
|
|
146
|
+
readonly substitutedProps?: Record<string, unknown>
|
|
147
|
+
readonly finalClassName?: string
|
|
148
|
+
readonly styleWithShadow?: Record<string, unknown>
|
|
149
|
+
readonly testId?: string
|
|
150
|
+
readonly componentName?: string
|
|
151
|
+
readonly firstTranslationKey?: string
|
|
152
|
+
readonly translationData?: Record<string, unknown>
|
|
153
|
+
readonly hasScrollAnimation?: boolean
|
|
154
|
+
readonly hasContent?: boolean
|
|
155
|
+
readonly children?: readonly (Component | string)[]
|
|
156
|
+
}): Record<string, unknown> {
|
|
157
|
+
const { type } = component
|
|
158
|
+
const hasChildren = Boolean(children?.length)
|
|
159
|
+
const finalStyle = buildEmptyStyle(componentName, type, hasContent, styleWithShadow)
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
...substitutedProps,
|
|
163
|
+
className: finalClassName,
|
|
164
|
+
...(finalStyle && { style: finalStyle }),
|
|
165
|
+
...(testId && { 'data-testid': testId }),
|
|
166
|
+
...buildComponentDataAttrs(componentName, type),
|
|
167
|
+
...(componentName && hasChildren && CONTAINER_TYPES.includes(type) && { role: 'group' }),
|
|
168
|
+
...buildTranslationDataAttrs(firstTranslationKey, translationData),
|
|
169
|
+
...(hasScrollAnimation && { 'data-scroll-animation': 'scale-up' }),
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Convert custom props to data-* attributes for badge components
|
|
175
|
+
* Standard HTML attributes (className, style, id, etc.) pass through unchanged
|
|
176
|
+
*
|
|
177
|
+
* Re-exported from prop-conversion module for backward compatibility
|
|
178
|
+
*/
|
|
179
|
+
export { convertBadgeProps } from './prop-conversion'
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
// Barrel export for props building utilities
|
|
9
|
+
// Files will be added during migration
|
|
@@ -0,0 +1,171 @@
|
|
|
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 { toKebabCase } from '@/presentation/utils/string-utils'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* HTML/React props that should not be converted to data attributes
|
|
12
|
+
* This includes standard HTML attributes, React-specific props, ARIA attributes,
|
|
13
|
+
* event handlers, and existing data-* attributes
|
|
14
|
+
*/
|
|
15
|
+
export const RESERVED_PROPS = new Set([
|
|
16
|
+
// Standard HTML/React props
|
|
17
|
+
'className',
|
|
18
|
+
'style',
|
|
19
|
+
'children',
|
|
20
|
+
'ref',
|
|
21
|
+
'key',
|
|
22
|
+
'id',
|
|
23
|
+
'role',
|
|
24
|
+
'title',
|
|
25
|
+
'alt',
|
|
26
|
+
'src',
|
|
27
|
+
'href',
|
|
28
|
+
'type',
|
|
29
|
+
'value',
|
|
30
|
+
'placeholder',
|
|
31
|
+
'disabled',
|
|
32
|
+
'checked',
|
|
33
|
+
'selected',
|
|
34
|
+
'multiple',
|
|
35
|
+
'autoFocus',
|
|
36
|
+
'autoComplete',
|
|
37
|
+
'readOnly',
|
|
38
|
+
'required',
|
|
39
|
+
'maxLength',
|
|
40
|
+
'minLength',
|
|
41
|
+
'pattern',
|
|
42
|
+
'name',
|
|
43
|
+
'tabIndex',
|
|
44
|
+
// ARIA attributes
|
|
45
|
+
'aria-label',
|
|
46
|
+
'aria-labelledby',
|
|
47
|
+
'aria-describedby',
|
|
48
|
+
// Event handlers
|
|
49
|
+
'onClick',
|
|
50
|
+
'onChange',
|
|
51
|
+
'onSubmit',
|
|
52
|
+
'onFocus',
|
|
53
|
+
'onBlur',
|
|
54
|
+
'onKeyDown',
|
|
55
|
+
'onKeyUp',
|
|
56
|
+
'onKeyPress',
|
|
57
|
+
'onMouseEnter',
|
|
58
|
+
'onMouseLeave',
|
|
59
|
+
// Application-specific props
|
|
60
|
+
'level', // For text elements (h1-h6, p, label)
|
|
61
|
+
'animation',
|
|
62
|
+
'data-testid',
|
|
63
|
+
'data-component',
|
|
64
|
+
'data-type',
|
|
65
|
+
'data-translation-key',
|
|
66
|
+
'data-translations',
|
|
67
|
+
'data-scroll-animation',
|
|
68
|
+
'data-scroll-threshold',
|
|
69
|
+
'data-scroll-delay',
|
|
70
|
+
'data-scroll-duration',
|
|
71
|
+
'data-scroll-once',
|
|
72
|
+
'data-i18n-content',
|
|
73
|
+
])
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a prop should be skipped during conversion
|
|
77
|
+
*/
|
|
78
|
+
function shouldSkipProp(key: string, _value: unknown): boolean {
|
|
79
|
+
return RESERVED_PROPS.has(key) || key.startsWith('data-') || key.startsWith('aria-')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Converts a value to a data attribute string
|
|
84
|
+
*/
|
|
85
|
+
function valueToDataAttributeString(value: unknown): string | undefined {
|
|
86
|
+
if (typeof value === 'string') {
|
|
87
|
+
return value
|
|
88
|
+
}
|
|
89
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
90
|
+
return value.toString()
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(value)) {
|
|
93
|
+
return JSON.stringify(value)
|
|
94
|
+
}
|
|
95
|
+
if (typeof value === 'object' && value !== null) {
|
|
96
|
+
return JSON.stringify(value)
|
|
97
|
+
}
|
|
98
|
+
return undefined
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Converts a single prop value to a data attribute value
|
|
103
|
+
*
|
|
104
|
+
* @param key - Prop key
|
|
105
|
+
* @param value - Prop value
|
|
106
|
+
* @returns Data attribute entry or undefined if should be skipped
|
|
107
|
+
*/
|
|
108
|
+
function convertPropToDataAttribute(
|
|
109
|
+
key: string,
|
|
110
|
+
value: unknown
|
|
111
|
+
): readonly [string, string] | undefined {
|
|
112
|
+
// Skip reserved props, data-*, aria-*, strings, and style objects
|
|
113
|
+
if (shouldSkipProp(key, value) || key === 'style') return undefined
|
|
114
|
+
|
|
115
|
+
const stringValue = valueToDataAttributeString(value)
|
|
116
|
+
return stringValue ? ([`data-${toKebabCase(key)}`, stringValue] as const) : undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Converts custom props to data attributes
|
|
121
|
+
* Handles numeric, boolean, array, and object values
|
|
122
|
+
*
|
|
123
|
+
* This is the comprehensive version that handles all prop types.
|
|
124
|
+
* Use this for components that need full prop conversion (e.g., dynamic components).
|
|
125
|
+
*
|
|
126
|
+
* @param props - Props object to convert
|
|
127
|
+
* @returns Object with data attributes for custom props
|
|
128
|
+
*/
|
|
129
|
+
export function convertCustomPropsToDataAttributes(
|
|
130
|
+
props: Record<string, unknown> | undefined
|
|
131
|
+
): Record<string, string> {
|
|
132
|
+
if (!props) return {}
|
|
133
|
+
|
|
134
|
+
return Object.entries(props).reduce<Record<string, string>>((acc, [key, value]) => {
|
|
135
|
+
const dataAttr = convertPropToDataAttribute(key, value)
|
|
136
|
+
return dataAttr ? { ...acc, [dataAttr[0]]: dataAttr[1] } : acc
|
|
137
|
+
}, {})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Convert custom props to data-* attributes (simplified version for badges)
|
|
142
|
+
* Standard HTML attributes (className, style, id, etc.) pass through unchanged
|
|
143
|
+
* String values are converted to data attributes (unlike the comprehensive version)
|
|
144
|
+
*
|
|
145
|
+
* This is used for badge components where all custom props should become data attributes.
|
|
146
|
+
*
|
|
147
|
+
* @param elementProps - Element props to convert
|
|
148
|
+
* @returns Props with custom values converted to data attributes
|
|
149
|
+
*/
|
|
150
|
+
export function convertBadgeProps(elementProps: Record<string, unknown>): Record<string, unknown> {
|
|
151
|
+
const standardHtmlAttrs = new Set([
|
|
152
|
+
'className',
|
|
153
|
+
'style',
|
|
154
|
+
'id',
|
|
155
|
+
'role',
|
|
156
|
+
'data-testid',
|
|
157
|
+
'data-component',
|
|
158
|
+
'data-type',
|
|
159
|
+
'data-translation-key',
|
|
160
|
+
'data-translations',
|
|
161
|
+
])
|
|
162
|
+
|
|
163
|
+
return Object.entries(elementProps).reduce<Record<string, unknown>>((acc, [key, value]) => {
|
|
164
|
+
// Keep standard HTML attrs, data-*, and aria-* unchanged
|
|
165
|
+
if (standardHtmlAttrs.has(key) || key.startsWith('data-') || key.startsWith('aria-')) {
|
|
166
|
+
return { ...acc, [key]: value }
|
|
167
|
+
}
|
|
168
|
+
// Convert custom props to data-* attributes (including strings)
|
|
169
|
+
return { ...acc, [`data-${toKebabCase(key)}`]: value }
|
|
170
|
+
}, {})
|
|
171
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
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 { Interactions } from '@/domain/models/app/page/common/interactions/interactions'
|
|
9
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
10
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for building test IDs
|
|
14
|
+
* Replaces 5 parameters with a single config object
|
|
15
|
+
*/
|
|
16
|
+
export interface TestIdConfig {
|
|
17
|
+
readonly type: Component['type']
|
|
18
|
+
readonly componentName?: string
|
|
19
|
+
readonly componentInstanceIndex?: number
|
|
20
|
+
readonly substitutedProps?: Record<string, unknown>
|
|
21
|
+
readonly childIndex?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for building element props
|
|
26
|
+
* Replaces 12 parameters with a single config object
|
|
27
|
+
*/
|
|
28
|
+
export interface ElementPropsConfig {
|
|
29
|
+
readonly type: Component['type']
|
|
30
|
+
readonly substitutedProps: Record<string, unknown> | undefined
|
|
31
|
+
readonly finalClassName: string | undefined
|
|
32
|
+
readonly styleWithShadow: Record<string, unknown> | undefined
|
|
33
|
+
readonly componentName: string | undefined
|
|
34
|
+
readonly componentInstanceIndex: number | undefined
|
|
35
|
+
readonly firstTranslationKey: string | undefined
|
|
36
|
+
readonly translationData: Record<string, string> | undefined
|
|
37
|
+
readonly hasContent: boolean
|
|
38
|
+
readonly hasChildren: boolean
|
|
39
|
+
readonly theme: Theme | undefined
|
|
40
|
+
readonly childIndex?: number
|
|
41
|
+
readonly interactions?: Interactions
|
|
42
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
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 { calculateTotalDelay } from '../utils/time-parser'
|
|
9
|
+
import { convertCustomPropsToDataAttributes } from './prop-conversion'
|
|
10
|
+
import type { ElementPropsConfig, TestIdConfig } from './props-builder-config'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Component types that should receive role="group" when used as component references with children
|
|
14
|
+
*/
|
|
15
|
+
const CONTAINER_TYPES = ['div', 'container', 'flex', 'grid', 'card', 'badge'] as const
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Builds test ID for component references
|
|
19
|
+
*/
|
|
20
|
+
function buildComponentTestId(
|
|
21
|
+
componentName: string,
|
|
22
|
+
componentInstanceIndex: number | undefined
|
|
23
|
+
): string {
|
|
24
|
+
return componentInstanceIndex !== undefined
|
|
25
|
+
? `component-${componentName}-${componentInstanceIndex}`
|
|
26
|
+
: `component-${componentName}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Auto-generates test ID for common component types
|
|
31
|
+
*/
|
|
32
|
+
function buildDefaultTestId(type: string): string | undefined {
|
|
33
|
+
const typeMap: Record<string, string> = {
|
|
34
|
+
container: 'container',
|
|
35
|
+
flex: 'flex',
|
|
36
|
+
'hero-section': 'hero-section',
|
|
37
|
+
hero: 'hero',
|
|
38
|
+
text: 'text',
|
|
39
|
+
icon: 'icon',
|
|
40
|
+
}
|
|
41
|
+
return typeMap[type]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build test ID for component using config object
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
function buildTestId(config: TestIdConfig): string | undefined {
|
|
49
|
+
const { type, componentName, componentInstanceIndex, substitutedProps, childIndex } = config
|
|
50
|
+
|
|
51
|
+
if (componentName) {
|
|
52
|
+
return buildComponentTestId(componentName, componentInstanceIndex)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (substitutedProps?.['data-testid']) {
|
|
56
|
+
return substitutedProps['data-testid'] as string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (childIndex !== undefined) {
|
|
60
|
+
return `child-${childIndex}`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return buildDefaultTestId(type)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Build element props with all attributes using config object
|
|
68
|
+
* Complexity reduced by extracting helper functions
|
|
69
|
+
*/
|
|
70
|
+
export function buildElementProps(config: ElementPropsConfig): Record<string, unknown> {
|
|
71
|
+
return buildElementPropsFromConfig(config)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Build element props from config object
|
|
76
|
+
*/
|
|
77
|
+
function buildElementPropsFromConfig(config: ElementPropsConfig): Record<string, unknown> {
|
|
78
|
+
const hasScrollAnimation = config.type === 'card' && Boolean(config.theme?.animations?.scaleUp)
|
|
79
|
+
const testId = buildTestId({
|
|
80
|
+
type: config.type,
|
|
81
|
+
componentName: config.componentName,
|
|
82
|
+
componentInstanceIndex: config.componentInstanceIndex,
|
|
83
|
+
substitutedProps: config.substitutedProps,
|
|
84
|
+
childIndex: config.childIndex,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Build all props
|
|
88
|
+
const coreProps = buildCoreProps(config, testId)
|
|
89
|
+
const componentDataProps = buildComponentDataProps(config)
|
|
90
|
+
const translationProps = buildTranslationProps(config)
|
|
91
|
+
const animationProps = buildAnimationProps(hasScrollAnimation)
|
|
92
|
+
const entranceProps = buildEntranceInteractionProps(config)
|
|
93
|
+
const scrollProps = buildScrollInteractionProps(config)
|
|
94
|
+
const emptyStyleProps = buildEmptyElementStyles(config)
|
|
95
|
+
|
|
96
|
+
// Merge all style objects to prevent overwrites
|
|
97
|
+
const mergedStyle = {
|
|
98
|
+
...(coreProps.style as Record<string, unknown> | undefined),
|
|
99
|
+
...(entranceProps.style as Record<string, unknown> | undefined),
|
|
100
|
+
...(scrollProps.style as Record<string, unknown> | undefined),
|
|
101
|
+
...(emptyStyleProps.style as Record<string, unknown> | undefined),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Remove style from individual prop objects
|
|
105
|
+
const { style: _coreStyle, ...corePropsWithoutStyle } = coreProps
|
|
106
|
+
const { style: _entranceStyle, ...entrancePropsWithoutStyle } = entranceProps
|
|
107
|
+
const { style: _scrollStyle, ...scrollPropsWithoutStyle } = scrollProps
|
|
108
|
+
const { style: _emptyStyle, ...emptyStylePropsWithoutStyle } = emptyStyleProps
|
|
109
|
+
|
|
110
|
+
// Remove animation and style props from substitutedProps (already applied to style object)
|
|
111
|
+
const {
|
|
112
|
+
animation: _animation,
|
|
113
|
+
style: _style,
|
|
114
|
+
...substitutedPropsWithoutAnimation
|
|
115
|
+
} = config.substitutedProps || {}
|
|
116
|
+
|
|
117
|
+
// Convert custom props to data attributes
|
|
118
|
+
const customDataAttributes = convertCustomPropsToDataAttributes(substitutedPropsWithoutAnimation)
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
...substitutedPropsWithoutAnimation,
|
|
122
|
+
...corePropsWithoutStyle,
|
|
123
|
+
...componentDataProps,
|
|
124
|
+
...translationProps,
|
|
125
|
+
...animationProps,
|
|
126
|
+
...entrancePropsWithoutStyle,
|
|
127
|
+
...scrollPropsWithoutStyle,
|
|
128
|
+
...emptyStylePropsWithoutStyle,
|
|
129
|
+
...customDataAttributes,
|
|
130
|
+
...(Object.keys(mergedStyle).length > 0 && { style: mergedStyle }),
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Build core props (className, style, data-testid)
|
|
136
|
+
* Handles animation prop by extracting it from substitutedProps and merging into style
|
|
137
|
+
*
|
|
138
|
+
* Note: data-component-type removed for clean production HTML
|
|
139
|
+
* This debug attribute was useful during development but adds unnecessary
|
|
140
|
+
* markup to static sites and production builds
|
|
141
|
+
*/
|
|
142
|
+
function buildCoreProps(
|
|
143
|
+
config: ElementPropsConfig,
|
|
144
|
+
testId: string | undefined
|
|
145
|
+
): Record<string, unknown> {
|
|
146
|
+
// Extract animation prop if present (after theme token substitution)
|
|
147
|
+
const animationProp = config.substitutedProps?.animation
|
|
148
|
+
const hasAnimationProp = typeof animationProp === 'string'
|
|
149
|
+
|
|
150
|
+
// Merge animation into style object if present
|
|
151
|
+
const styleWithAnimation = hasAnimationProp
|
|
152
|
+
? { ...config.styleWithShadow, animation: animationProp }
|
|
153
|
+
: config.styleWithShadow
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
className: config.finalClassName,
|
|
157
|
+
...(styleWithAnimation && { style: styleWithAnimation }),
|
|
158
|
+
...(testId && { 'data-testid': testId }),
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Build component-related data props (data-component, data-type, role)
|
|
164
|
+
*/
|
|
165
|
+
function buildComponentDataProps(config: ElementPropsConfig): Record<string, unknown> {
|
|
166
|
+
if (!config.componentName) return {}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
'data-component': config.componentName,
|
|
170
|
+
'data-type': config.type,
|
|
171
|
+
...(config.hasChildren &&
|
|
172
|
+
CONTAINER_TYPES.includes(config.type) && {
|
|
173
|
+
role: 'group',
|
|
174
|
+
}),
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Build translation props (data-translation-key, data-translations)
|
|
180
|
+
*/
|
|
181
|
+
function buildTranslationProps(config: ElementPropsConfig): Record<string, unknown> {
|
|
182
|
+
if (!config.firstTranslationKey || !config.translationData) return {}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
'data-translation-key': config.firstTranslationKey,
|
|
186
|
+
'data-translations': JSON.stringify(config.translationData),
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Build animation props (data-scroll-animation)
|
|
192
|
+
*/
|
|
193
|
+
function buildAnimationProps(hasScrollAnimation: boolean): Record<string, unknown> {
|
|
194
|
+
if (!hasScrollAnimation) return {}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
'data-scroll-animation': 'scale-up',
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Build entrance interaction props (style for animations)
|
|
203
|
+
*/
|
|
204
|
+
function buildEntranceInteractionProps(config: ElementPropsConfig): Record<string, unknown> {
|
|
205
|
+
if (!config.interactions?.entrance) return {}
|
|
206
|
+
|
|
207
|
+
const { delay, duration, stagger } = config.interactions.entrance
|
|
208
|
+
|
|
209
|
+
// Calculate total delay including stagger
|
|
210
|
+
const totalDelay = calculateTotalDelay(delay, stagger, config.childIndex)
|
|
211
|
+
|
|
212
|
+
// Build animation styles immutably
|
|
213
|
+
const delayStyle = totalDelay ? { animationDelay: totalDelay } : {}
|
|
214
|
+
const durationStyle = duration ? { animationDuration: duration } : {}
|
|
215
|
+
const animationStyles = { ...delayStyle, ...durationStyle }
|
|
216
|
+
|
|
217
|
+
// Combine all props immutably
|
|
218
|
+
const hasAnimationStyles = Object.keys(animationStyles).length > 0
|
|
219
|
+
const styleProps = hasAnimationStyles
|
|
220
|
+
? { style: { ...config.styleWithShadow, ...animationStyles } }
|
|
221
|
+
: {}
|
|
222
|
+
|
|
223
|
+
return styleProps
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Build scroll interaction props (data-scroll-*, style for animations)
|
|
228
|
+
*/
|
|
229
|
+
function buildScrollInteractionProps(config: ElementPropsConfig): Record<string, unknown> {
|
|
230
|
+
if (!config.interactions?.scroll) return {}
|
|
231
|
+
|
|
232
|
+
const { animation, threshold, delay, duration, once } = config.interactions.scroll
|
|
233
|
+
|
|
234
|
+
// Build base data attributes immutably
|
|
235
|
+
const baseProps: Record<string, unknown> = {
|
|
236
|
+
'data-scroll-animation': animation,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const thresholdProps =
|
|
240
|
+
threshold !== undefined ? { 'data-scroll-threshold': threshold.toString() } : {}
|
|
241
|
+
const delayProps = delay ? { 'data-scroll-delay': delay } : {}
|
|
242
|
+
const durationProps = duration ? { 'data-scroll-duration': duration } : {}
|
|
243
|
+
const onceProps = once === true ? { 'data-scroll-once': once.toString() } : {}
|
|
244
|
+
|
|
245
|
+
// Build animation styles immutably
|
|
246
|
+
const delayStyle = delay ? { animationDelay: delay } : {}
|
|
247
|
+
const durationStyle = duration ? { animationDuration: duration } : {}
|
|
248
|
+
const animationStyles = { ...delayStyle, ...durationStyle }
|
|
249
|
+
|
|
250
|
+
// Combine all props immutably
|
|
251
|
+
const hasAnimationStyles = Object.keys(animationStyles).length > 0
|
|
252
|
+
const styleProps = hasAnimationStyles
|
|
253
|
+
? { style: { ...config.styleWithShadow, ...animationStyles } }
|
|
254
|
+
: {}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
...baseProps,
|
|
258
|
+
...thresholdProps,
|
|
259
|
+
...delayProps,
|
|
260
|
+
...durationProps,
|
|
261
|
+
...onceProps,
|
|
262
|
+
...styleProps,
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Build styles for empty elements (components and grids without content)
|
|
268
|
+
*/
|
|
269
|
+
function buildEmptyElementStyles(config: ElementPropsConfig): Record<string, unknown> {
|
|
270
|
+
if (config.hasContent) return {}
|
|
271
|
+
|
|
272
|
+
// Component reference or child without content
|
|
273
|
+
if (config.componentName || config.childIndex !== undefined) {
|
|
274
|
+
return {
|
|
275
|
+
style: {
|
|
276
|
+
...config.styleWithShadow,
|
|
277
|
+
minHeight: '1px',
|
|
278
|
+
minWidth: '1px',
|
|
279
|
+
display: 'inline-block',
|
|
280
|
+
},
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Grid without content and not a component reference
|
|
285
|
+
if (!config.componentName && config.type === 'grid') {
|
|
286
|
+
return {
|
|
287
|
+
style: {
|
|
288
|
+
...config.styleWithShadow,
|
|
289
|
+
minHeight: '100px',
|
|
290
|
+
minWidth: '100px',
|
|
291
|
+
},
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {}
|
|
296
|
+
}
|