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,198 @@
|
|
|
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 { resolveChildTranslation } from './translation-handler'
|
|
9
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds i18n content data attribute for client-side language switching (functional approach)
|
|
13
|
+
*
|
|
14
|
+
* Extracts content translations from i18n object and serializes to JSON.
|
|
15
|
+
* Includes default language content as fallback.
|
|
16
|
+
*
|
|
17
|
+
* @param i18n - Component i18n translations object
|
|
18
|
+
* @param defaultContent - Default content for base language
|
|
19
|
+
* @param defaultLang - Default language code
|
|
20
|
+
* @returns JSON-stringified i18n content data or undefined if no translations
|
|
21
|
+
*/
|
|
22
|
+
function buildI18nContentAttribute(
|
|
23
|
+
i18n: Record<string, unknown>,
|
|
24
|
+
defaultContent: string,
|
|
25
|
+
defaultLang: string | undefined
|
|
26
|
+
): string | undefined {
|
|
27
|
+
// Extract content from i18n object using functional approach (reduce instead of for loop)
|
|
28
|
+
const i18nContentData = Object.entries(i18n).reduce<Record<string, string>>(
|
|
29
|
+
(acc, [lang, value]) => {
|
|
30
|
+
if (typeof value === 'object' && value !== null && 'content' in value && value.content) {
|
|
31
|
+
return { ...acc, [lang]: value.content as string }
|
|
32
|
+
}
|
|
33
|
+
return acc
|
|
34
|
+
},
|
|
35
|
+
{}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
// Add default language content if not already present
|
|
39
|
+
const contentWithDefault =
|
|
40
|
+
defaultLang && !i18nContentData[defaultLang]
|
|
41
|
+
? { ...i18nContentData, [defaultLang]: defaultContent }
|
|
42
|
+
: i18nContentData
|
|
43
|
+
|
|
44
|
+
// Only return attribute if there are translations
|
|
45
|
+
return Object.keys(contentWithDefault).length > 0 ? JSON.stringify(contentWithDefault) : undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolves component content with i18n priority
|
|
50
|
+
*
|
|
51
|
+
* Priority: component.i18n[lang].content > $t: pattern > content
|
|
52
|
+
*
|
|
53
|
+
* @param content - Base content string
|
|
54
|
+
* @param i18n - Component i18n translations
|
|
55
|
+
* @param currentLang - Current language code
|
|
56
|
+
* @param languages - Languages configuration
|
|
57
|
+
* @returns Resolved content string
|
|
58
|
+
*/
|
|
59
|
+
function resolveComponentContent(
|
|
60
|
+
content: string | Record<string, unknown> | undefined,
|
|
61
|
+
i18n: Record<string, unknown> | undefined,
|
|
62
|
+
currentLang: string | undefined,
|
|
63
|
+
languages: Languages | undefined
|
|
64
|
+
): string | undefined {
|
|
65
|
+
// If content is an object (structured content like { button: {...} }), return undefined
|
|
66
|
+
// The component renderer will handle structured content directly
|
|
67
|
+
if (content && typeof content === 'object') {
|
|
68
|
+
return undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (i18n && currentLang) {
|
|
72
|
+
const langData = i18n[currentLang]
|
|
73
|
+
if (
|
|
74
|
+
langData &&
|
|
75
|
+
typeof langData === 'object' &&
|
|
76
|
+
'content' in langData &&
|
|
77
|
+
typeof langData.content === 'string'
|
|
78
|
+
) {
|
|
79
|
+
return langData.content
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (content) {
|
|
83
|
+
return resolveChildTranslation(content, currentLang, languages)
|
|
84
|
+
}
|
|
85
|
+
return content
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Builds final element props with i18n data attribute
|
|
90
|
+
*
|
|
91
|
+
* @param baseProps - Base element props
|
|
92
|
+
* @param i18nAttribute - Optional i18n content JSON string
|
|
93
|
+
* @returns Element props with i18n data merged if present
|
|
94
|
+
*/
|
|
95
|
+
function buildFinalElementProps(
|
|
96
|
+
baseProps: Record<string, unknown>,
|
|
97
|
+
i18nAttribute: string | undefined
|
|
98
|
+
): Record<string, unknown> {
|
|
99
|
+
return i18nAttribute ? { ...baseProps, 'data-i18n-content': i18nAttribute } : baseProps
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Configuration for resolving i18n content
|
|
104
|
+
*/
|
|
105
|
+
export interface ResolveI18nContentConfig {
|
|
106
|
+
readonly content: string | Record<string, unknown> | undefined
|
|
107
|
+
readonly i18n: Record<string, unknown> | undefined
|
|
108
|
+
readonly currentLang: string | undefined
|
|
109
|
+
readonly languages: Languages | undefined
|
|
110
|
+
readonly elementProps: Record<string, unknown>
|
|
111
|
+
readonly elementPropsWithSpacing: Record<string, unknown>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolves i18n content and builds element props with i18n data attribute (config object signature)
|
|
116
|
+
*/
|
|
117
|
+
export function resolveI18nContent(config: ResolveI18nContentConfig): {
|
|
118
|
+
readonly resolvedContent: string | undefined
|
|
119
|
+
readonly finalElementProps: Record<string, unknown>
|
|
120
|
+
readonly finalElementPropsWithSpacing: Record<string, unknown>
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolves i18n content and builds element props with i18n data attribute (individual parameters signature)
|
|
125
|
+
*/
|
|
126
|
+
// eslint-disable-next-line max-params -- Function overload signature
|
|
127
|
+
export function resolveI18nContent(
|
|
128
|
+
content: string | Record<string, unknown> | undefined,
|
|
129
|
+
i18n: Record<string, unknown> | undefined,
|
|
130
|
+
currentLang: string | undefined,
|
|
131
|
+
languages: Languages | undefined,
|
|
132
|
+
elementProps: Record<string, unknown>,
|
|
133
|
+
elementPropsWithSpacing: Record<string, unknown>
|
|
134
|
+
): {
|
|
135
|
+
readonly resolvedContent: string | undefined
|
|
136
|
+
readonly finalElementProps: Record<string, unknown>
|
|
137
|
+
readonly finalElementPropsWithSpacing: Record<string, unknown>
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Implementation
|
|
142
|
+
*/
|
|
143
|
+
// eslint-disable-next-line max-params -- Implementation handles both signatures
|
|
144
|
+
export function resolveI18nContent(
|
|
145
|
+
configOrContent: ResolveI18nContentConfig | string | Record<string, unknown> | undefined,
|
|
146
|
+
i18n?: Record<string, unknown>,
|
|
147
|
+
currentLang?: string,
|
|
148
|
+
languages?: Languages,
|
|
149
|
+
elementProps?: Record<string, unknown>,
|
|
150
|
+
elementPropsWithSpacing?: Record<string, unknown>
|
|
151
|
+
): {
|
|
152
|
+
readonly resolvedContent: string | undefined
|
|
153
|
+
readonly finalElementProps: Record<string, unknown>
|
|
154
|
+
readonly finalElementPropsWithSpacing: Record<string, unknown>
|
|
155
|
+
} {
|
|
156
|
+
// Support both config object and individual parameters
|
|
157
|
+
const config: ResolveI18nContentConfig =
|
|
158
|
+
configOrContent && typeof configOrContent === 'object' && 'content' in configOrContent
|
|
159
|
+
? (configOrContent as ResolveI18nContentConfig)
|
|
160
|
+
: {
|
|
161
|
+
content: configOrContent as string | Record<string, unknown> | undefined,
|
|
162
|
+
i18n: i18n!,
|
|
163
|
+
currentLang: currentLang!,
|
|
164
|
+
languages: languages!,
|
|
165
|
+
elementProps: elementProps!,
|
|
166
|
+
elementPropsWithSpacing: elementPropsWithSpacing!,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const {
|
|
170
|
+
content,
|
|
171
|
+
i18n: i18nConfig,
|
|
172
|
+
currentLang: lang,
|
|
173
|
+
languages: langs,
|
|
174
|
+
elementProps: props,
|
|
175
|
+
elementPropsWithSpacing: propsWithSpacing,
|
|
176
|
+
} = config
|
|
177
|
+
|
|
178
|
+
// Resolve content with i18n priority: component.i18n[lang].content > $t: pattern > content
|
|
179
|
+
const resolvedContent = resolveComponentContent(content, i18nConfig, lang, langs)
|
|
180
|
+
|
|
181
|
+
// Build i18n content data attribute and merge into element props (functional approach)
|
|
182
|
+
const i18nContentAttribute =
|
|
183
|
+
i18nConfig && content
|
|
184
|
+
? buildI18nContentAttribute(i18nConfig, content as string, langs?.default)
|
|
185
|
+
: undefined
|
|
186
|
+
|
|
187
|
+
const finalElementProps = buildFinalElementProps(props, i18nContentAttribute)
|
|
188
|
+
const finalElementPropsWithSpacing = buildFinalElementProps(
|
|
189
|
+
propsWithSpacing,
|
|
190
|
+
i18nContentAttribute
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
resolvedContent,
|
|
195
|
+
finalElementProps,
|
|
196
|
+
finalElementPropsWithSpacing,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -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 translation utilities
|
|
9
|
+
// Files will be added during migration
|
|
@@ -0,0 +1,143 @@
|
|
|
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 {
|
|
9
|
+
collectTranslationsForKey,
|
|
10
|
+
resolveTranslationPattern,
|
|
11
|
+
} from '@/presentation/translations/translation-resolver'
|
|
12
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
13
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Find first translation key in children
|
|
17
|
+
*/
|
|
18
|
+
export function findFirstTranslationKey(
|
|
19
|
+
children: readonly (Component | string)[] | undefined
|
|
20
|
+
): string | undefined {
|
|
21
|
+
return children
|
|
22
|
+
?.find(
|
|
23
|
+
(child: Component | string): child is string =>
|
|
24
|
+
typeof child === 'string' && child.startsWith('$t:')
|
|
25
|
+
)
|
|
26
|
+
?.slice(3) // Remove '$t:' prefix
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extract translation key from content string
|
|
31
|
+
* Returns the key portion after $t: prefix if content is a translation token
|
|
32
|
+
*/
|
|
33
|
+
export function extractTranslationKeyFromContent(content: string | undefined): string | undefined {
|
|
34
|
+
if (!content || typeof content !== 'string') return undefined
|
|
35
|
+
return content.startsWith('$t:') ? content.slice(3) : undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get current language with fallback
|
|
40
|
+
*/
|
|
41
|
+
export function getCurrentLanguage(
|
|
42
|
+
currentLang: string | undefined,
|
|
43
|
+
languages: Languages | undefined
|
|
44
|
+
): string {
|
|
45
|
+
return currentLang || languages?.default || 'en-US'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve translation pattern for a child element
|
|
50
|
+
*/
|
|
51
|
+
export function resolveChildTranslation(
|
|
52
|
+
child: string,
|
|
53
|
+
currentLang: string | undefined,
|
|
54
|
+
languages: Languages | undefined
|
|
55
|
+
): string {
|
|
56
|
+
const lang = getCurrentLanguage(currentLang, languages)
|
|
57
|
+
return resolveTranslationPattern(child, lang, languages)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Collect translation data for a key
|
|
62
|
+
*/
|
|
63
|
+
export function getTranslationData(
|
|
64
|
+
translationKey: string | undefined,
|
|
65
|
+
languages: Languages | undefined
|
|
66
|
+
): Record<string, string> | undefined {
|
|
67
|
+
return translationKey ? collectTranslationsForKey(translationKey, languages) : undefined
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Substitutes translation tokens in props recursively
|
|
72
|
+
*
|
|
73
|
+
* Walks through props object and replaces all $t:key patterns with actual translations.
|
|
74
|
+
* Handles nested objects (e.g., style props) recursively.
|
|
75
|
+
*
|
|
76
|
+
* @param props - Component props that may contain translation tokens
|
|
77
|
+
* @param currentLang - Current language code
|
|
78
|
+
* @param languages - Languages configuration
|
|
79
|
+
* @returns Props with translation tokens replaced
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const languages = {
|
|
84
|
+
* default: 'en',
|
|
85
|
+
* translations: { 'en': { 'close.label': 'Close dialog' } }
|
|
86
|
+
* }
|
|
87
|
+
* const props = {
|
|
88
|
+
* 'aria-label': '$t:close.label',
|
|
89
|
+
* title: 'Static text'
|
|
90
|
+
* }
|
|
91
|
+
* substitutePropsTranslationTokens(props, 'en-US', languages)
|
|
92
|
+
* // {
|
|
93
|
+
* // 'aria-label': 'Close dialog',
|
|
94
|
+
* // title: 'Static text'
|
|
95
|
+
* // }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function substitutePropsTranslationTokens(
|
|
99
|
+
props: Record<string, unknown> | undefined,
|
|
100
|
+
currentLang: string | undefined,
|
|
101
|
+
languages: Languages | undefined
|
|
102
|
+
): Record<string, unknown> | undefined {
|
|
103
|
+
if (!props || !languages) {
|
|
104
|
+
return props
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const lang = getCurrentLanguage(currentLang, languages)
|
|
108
|
+
|
|
109
|
+
// Use functional Object.entries + reduce for immutable transformation
|
|
110
|
+
return Object.entries(props).reduce<Record<string, unknown>>((acc, [key, value]) => {
|
|
111
|
+
if (typeof value === 'string') {
|
|
112
|
+
return { ...acc, [key]: resolveTranslationPattern(value, lang, languages) }
|
|
113
|
+
} else if (Array.isArray(value)) {
|
|
114
|
+
// Recursively handle arrays (like navigation links, footer columns)
|
|
115
|
+
return {
|
|
116
|
+
...acc,
|
|
117
|
+
[key]: value.map((item) =>
|
|
118
|
+
item && typeof item === 'object' && !Array.isArray(item)
|
|
119
|
+
? substitutePropsTranslationTokens(
|
|
120
|
+
item as Record<string, unknown>,
|
|
121
|
+
currentLang,
|
|
122
|
+
languages
|
|
123
|
+
)
|
|
124
|
+
: typeof item === 'string'
|
|
125
|
+
? resolveTranslationPattern(item, lang, languages)
|
|
126
|
+
: item
|
|
127
|
+
),
|
|
128
|
+
}
|
|
129
|
+
} else if (value && typeof value === 'object') {
|
|
130
|
+
// Recursively handle nested objects (like style props)
|
|
131
|
+
return {
|
|
132
|
+
...acc,
|
|
133
|
+
[key]: substitutePropsTranslationTokens(
|
|
134
|
+
value as Record<string, unknown>,
|
|
135
|
+
currentLang,
|
|
136
|
+
languages
|
|
137
|
+
),
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
return { ...acc, [key]: value }
|
|
141
|
+
}
|
|
142
|
+
}, {})
|
|
143
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
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
|
+
import type { Component } from '@/domain/models/app/page/sections'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Replaces variable placeholders in a string with actual values
|
|
13
|
+
*
|
|
14
|
+
* Uses regex with word boundary checking to avoid partial matches.
|
|
15
|
+
* For example, $icon will not match inside $iconColor.
|
|
16
|
+
*
|
|
17
|
+
* @param value - String that may contain $variable placeholders
|
|
18
|
+
* @param vars - Variables for substitution
|
|
19
|
+
* @returns String with all variables replaced
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* replaceVariables('$title', { title: 'Hello' }) // 'Hello'
|
|
24
|
+
* replaceVariables('$price/month', { price: '49' }) // '49/month'
|
|
25
|
+
* replaceVariables('box-$variant', { variant: 'primary' }) // 'box-primary'
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function replaceVariables(value: string, vars: Record<string, string | number | boolean>): string {
|
|
29
|
+
// Use regex with word boundary to avoid partial matches
|
|
30
|
+
// e.g., $icon should not match inside $iconColor
|
|
31
|
+
return Object.entries(vars).reduce<string>((str, [varName, varValue]) => {
|
|
32
|
+
// Create regex that matches $varName as a whole word
|
|
33
|
+
// Use negative lookahead to ensure we don't match if followed by alphanumeric or underscore
|
|
34
|
+
const regex = new RegExp(`\\$${varName}(?![a-zA-Z0-9_])`, 'g')
|
|
35
|
+
return str.replace(regex, String(varValue))
|
|
36
|
+
}, value)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Substitutes variable values in a value
|
|
41
|
+
*
|
|
42
|
+
* Replaces `$variableName` patterns with actual variable values.
|
|
43
|
+
* Supports both full replacement ($title → 'Welcome') and partial replacement
|
|
44
|
+
* within strings ($price/month → '49/month').
|
|
45
|
+
*
|
|
46
|
+
* @param value - Value that may contain variable placeholders
|
|
47
|
+
* @param vars - Variables for substitution
|
|
48
|
+
* @returns Value with variables replaced
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* substituteVariableValues('$title', { title: 'Hello' }) // 'Hello'
|
|
53
|
+
* substituteVariableValues('$price/month', { price: '49' }) // '49/month'
|
|
54
|
+
* substituteVariableValues('static', { title: 'Hello' }) // 'static'
|
|
55
|
+
* substituteVariableValues(123, { title: 'Hello' }) // 123
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function substituteVariableValues(
|
|
59
|
+
value: unknown,
|
|
60
|
+
vars?: Record<string, string | number | boolean>
|
|
61
|
+
): unknown {
|
|
62
|
+
if (typeof value !== 'string') {
|
|
63
|
+
return value
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!vars || !value.includes('$')) {
|
|
67
|
+
return value
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return replaceVariables(value, vars)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Substitutes variables in component children recursively
|
|
75
|
+
*
|
|
76
|
+
* Pure function that walks through the children tree and replaces $variable
|
|
77
|
+
* placeholders with actual values from the vars object.
|
|
78
|
+
*
|
|
79
|
+
* @param children - Array of children (can be strings or components)
|
|
80
|
+
* @param vars - Variables for substitution
|
|
81
|
+
* @returns Children with variables substituted
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* substituteChildrenVariables(
|
|
86
|
+
* [
|
|
87
|
+
* '$greeting',
|
|
88
|
+
* { type: 'span', content: '$name' }
|
|
89
|
+
* ],
|
|
90
|
+
* { greeting: 'Hello', name: 'World' }
|
|
91
|
+
* )
|
|
92
|
+
* // ['Hello', { type: 'span', content: 'World' }]
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export function substituteChildrenVariables(
|
|
96
|
+
children: ReadonlyArray<Component | string> | undefined,
|
|
97
|
+
vars?: Record<string, string | number | boolean>
|
|
98
|
+
): ReadonlyArray<Component | string> | undefined {
|
|
99
|
+
if (!children || !vars) {
|
|
100
|
+
return children
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return children.map((child) => {
|
|
104
|
+
// If child is a string, apply variable substitution
|
|
105
|
+
if (typeof child === 'string') {
|
|
106
|
+
const substituted = substituteVariableValues(child, vars)
|
|
107
|
+
return substituted as string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// If child is a component, recursively substitute in its props, children and content
|
|
111
|
+
const substitutedProps = substitutePropsVariables(child.props, vars)
|
|
112
|
+
const substitutedChildren = substituteChildrenVariables(child.children, vars)
|
|
113
|
+
const substitutedContent =
|
|
114
|
+
typeof child.content === 'string'
|
|
115
|
+
? (substituteVariableValues(child.content, vars) as string)
|
|
116
|
+
: child.content
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...child,
|
|
120
|
+
props: substitutedProps,
|
|
121
|
+
children: substitutedChildren,
|
|
122
|
+
content: substitutedContent,
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Converts camelCase prop names to kebab-case for HTML attributes
|
|
129
|
+
*
|
|
130
|
+
* React JSX expects certain attributes in kebab-case (aria-*, data-*),
|
|
131
|
+
* but our schema may define them in camelCase for convenience.
|
|
132
|
+
* This function normalizes prop names to the format React expects.
|
|
133
|
+
*
|
|
134
|
+
* Handles both camelCase (ariaLabel) and already-kebab-case (aria-label) inputs.
|
|
135
|
+
* If prop is already in kebab-case, it returns unchanged to avoid double-conversion.
|
|
136
|
+
*
|
|
137
|
+
* @param key - Property key (potentially in camelCase or kebab-case)
|
|
138
|
+
* @returns Normalized key (kebab-case for aria/data attributes)
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* normalizeAriaDataProps('ariaLabel') // 'aria-label'
|
|
143
|
+
* normalizeAriaDataProps('aria-label') // 'aria-label' (unchanged)
|
|
144
|
+
* normalizeAriaDataProps('dataTestId') // 'data-test-id'
|
|
145
|
+
* normalizeAriaDataProps('data-test-id') // 'data-test-id' (unchanged)
|
|
146
|
+
* normalizeAriaDataProps('className') // 'className' (unchanged)
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
function normalizeAriaDataProps(key: string): string {
|
|
150
|
+
// Convert ariaLabel → aria-label, dataTestId → data-test-id
|
|
151
|
+
// Check if fifth character is uppercase letter (not hyphen or other character)
|
|
152
|
+
// to avoid double-conversion (aria-label → aria--label)
|
|
153
|
+
if (key.startsWith('aria') && key.length > 4 && key[4] !== undefined && /[A-Z]/.test(key[4])) {
|
|
154
|
+
// ariaLabel → aria-label
|
|
155
|
+
const suffix = key.slice(4) // 'Label'
|
|
156
|
+
const kebabSuffix = toKebabCase(suffix) // 'label'
|
|
157
|
+
return `aria-${kebabSuffix}`
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (key.startsWith('data') && key.length > 4 && key[4] !== undefined && /[A-Z]/.test(key[4])) {
|
|
161
|
+
// dataTestId → data-test-id
|
|
162
|
+
const suffix = key.slice(4) // 'TestId'
|
|
163
|
+
const kebabSuffix = toKebabCase(suffix) // 'test-id'
|
|
164
|
+
return `data-${kebabSuffix}`
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return key
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Substitutes variables in props recursively
|
|
172
|
+
*
|
|
173
|
+
* Walks through props object and replaces all $variable strings with actual values.
|
|
174
|
+
* Handles nested objects (e.g., style props) recursively.
|
|
175
|
+
* Supports variable substitution in string values, including partial substitution
|
|
176
|
+
* within strings (e.g., 'box-$variant' → 'box-primary').
|
|
177
|
+
* Normalizes aria* and data* prop names to kebab-case for React compatibility.
|
|
178
|
+
*
|
|
179
|
+
* @param props - Component props that may contain variable placeholders
|
|
180
|
+
* @param vars - Variables for substitution
|
|
181
|
+
* @returns Props with variables replaced and prop names normalized
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const vars = { variant: 'primary', boxId: 'main-box', label: 'Main content' }
|
|
186
|
+
* const props = {
|
|
187
|
+
* className: 'box-$variant',
|
|
188
|
+
* id: '$boxId',
|
|
189
|
+
* ariaLabel: '$label'
|
|
190
|
+
* }
|
|
191
|
+
* substitutePropsVariables(props, vars)
|
|
192
|
+
* // {
|
|
193
|
+
* // className: 'box-primary',
|
|
194
|
+
* // id: 'main-box',
|
|
195
|
+
* // 'aria-label': 'Main content'
|
|
196
|
+
* // }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function substitutePropsVariables(
|
|
200
|
+
props: Record<string, unknown> | undefined,
|
|
201
|
+
vars?: Record<string, string | number | boolean>
|
|
202
|
+
): Record<string, unknown> | undefined {
|
|
203
|
+
if (!props || !vars) {
|
|
204
|
+
return props
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Use functional Object.entries + reduce for immutable transformation
|
|
208
|
+
return Object.entries(props).reduce<Record<string, unknown>>((acc, [key, value]) => {
|
|
209
|
+
// Normalize aria/data prop names (ariaLabel → aria-label)
|
|
210
|
+
const normalizedKey = normalizeAriaDataProps(key)
|
|
211
|
+
|
|
212
|
+
if (typeof value === 'string') {
|
|
213
|
+
// Handle partial substitution within strings (e.g., 'box-$variant' → 'box-primary')
|
|
214
|
+
return { ...acc, [normalizedKey]: replaceVariables(value, vars) }
|
|
215
|
+
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
216
|
+
// Recursively handle nested objects (like style props)
|
|
217
|
+
return {
|
|
218
|
+
...acc,
|
|
219
|
+
[normalizedKey]: substitutePropsVariables(value as Record<string, unknown>, vars),
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
return { ...acc, [normalizedKey]: value }
|
|
223
|
+
}
|
|
224
|
+
}, {})
|
|
225
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
* Time string parsing and formatting utilities
|
|
10
|
+
*
|
|
11
|
+
* Provides pure functions for converting between time strings (e.g., "100ms", "0.5s")
|
|
12
|
+
* and millisecond values. Used for animation timing calculations.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse time string to milliseconds
|
|
17
|
+
*
|
|
18
|
+
* @param timeStr - Time string (e.g., "100ms", "0.5s", "1s")
|
|
19
|
+
* @returns Time in milliseconds
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* parseTimeToMs('100ms') // => 100
|
|
23
|
+
* parseTimeToMs('0.5s') // => 500
|
|
24
|
+
* parseTimeToMs('1s') // => 1000
|
|
25
|
+
*/
|
|
26
|
+
export function parseTimeToMs(timeStr: string): number {
|
|
27
|
+
if (timeStr.endsWith('ms')) {
|
|
28
|
+
return parseInt(timeStr.slice(0, -2), 10)
|
|
29
|
+
}
|
|
30
|
+
if (timeStr.endsWith('s')) {
|
|
31
|
+
return parseFloat(timeStr.slice(0, -1)) * 1000
|
|
32
|
+
}
|
|
33
|
+
return 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Format milliseconds to time string
|
|
38
|
+
*
|
|
39
|
+
* @param ms - Time in milliseconds
|
|
40
|
+
* @returns Time string in milliseconds format
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* formatMsToTime(100) // => "100ms"
|
|
44
|
+
* formatMsToTime(500) // => "500ms"
|
|
45
|
+
* formatMsToTime(1000) // => "1000ms"
|
|
46
|
+
*/
|
|
47
|
+
export function formatMsToTime(ms: number): string {
|
|
48
|
+
return `${ms}ms`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Calculate total delay including stagger offset
|
|
53
|
+
*
|
|
54
|
+
* Adds stagger delay based on child index to create sequential animation effects.
|
|
55
|
+
* Commonly used for entrance animations of multiple child elements.
|
|
56
|
+
*
|
|
57
|
+
* @param delay - Base delay string (e.g., "100ms")
|
|
58
|
+
* @param stagger - Stagger delay per sibling (e.g., "50ms")
|
|
59
|
+
* @param childIndex - Current child index (0-based)
|
|
60
|
+
* @returns Total delay string or undefined if no stagger
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* calculateTotalDelay('100ms', '50ms', 0) // => "100ms"
|
|
64
|
+
* calculateTotalDelay('100ms', '50ms', 1) // => "150ms"
|
|
65
|
+
* calculateTotalDelay('100ms', '50ms', 2) // => "200ms"
|
|
66
|
+
* calculateTotalDelay('100ms', undefined, 2) // => "100ms"
|
|
67
|
+
*/
|
|
68
|
+
export function calculateTotalDelay(
|
|
69
|
+
delay: string | undefined,
|
|
70
|
+
stagger: string | undefined,
|
|
71
|
+
childIndex: number | undefined
|
|
72
|
+
): string | undefined {
|
|
73
|
+
if (!stagger || childIndex === undefined) {
|
|
74
|
+
return delay
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const baseDelayMs = delay ? parseTimeToMs(delay) : 0
|
|
78
|
+
const staggerMs = parseTimeToMs(stagger)
|
|
79
|
+
const totalDelayMs = baseDelayMs + staggerMs * childIndex
|
|
80
|
+
|
|
81
|
+
return formatMsToTime(totalDelayMs)
|
|
82
|
+
}
|