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,147 @@
|
|
|
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 { generateClickAnimationCSS } from '@/infrastructure/css/styles/click-animations'
|
|
9
|
+
import type { Theme } from '@/domain/models/app/theme'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Build button classes with optional primary colors
|
|
13
|
+
*
|
|
14
|
+
* @param hasPrimaryColor - Whether theme defines primary color
|
|
15
|
+
* @param hasPrimaryHoverColor - Whether theme defines primary hover color
|
|
16
|
+
* @returns Array of CSS class names for button elements
|
|
17
|
+
*/
|
|
18
|
+
export function buildButtonClasses(
|
|
19
|
+
hasPrimaryColor: boolean,
|
|
20
|
+
hasPrimaryHoverColor: boolean
|
|
21
|
+
): readonly string[] {
|
|
22
|
+
const baseClasses = [
|
|
23
|
+
'inline-flex',
|
|
24
|
+
'items-center',
|
|
25
|
+
'justify-center',
|
|
26
|
+
'rounded-md',
|
|
27
|
+
'px-4',
|
|
28
|
+
'py-2',
|
|
29
|
+
'font-medium',
|
|
30
|
+
'transition-colors',
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
if (hasPrimaryColor && hasPrimaryHoverColor) {
|
|
34
|
+
return [...baseClasses, 'bg-primary', 'text-white', 'hover:bg-primary-hover']
|
|
35
|
+
}
|
|
36
|
+
if (hasPrimaryColor) {
|
|
37
|
+
return [...baseClasses, 'bg-primary', 'text-white']
|
|
38
|
+
}
|
|
39
|
+
return [...baseClasses, 'bg-blue-600', 'text-white', 'hover:bg-blue-700']
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Build button primary utility classes
|
|
44
|
+
*
|
|
45
|
+
* @param hasPrimaryColor - Whether theme defines primary color
|
|
46
|
+
* @param hasPrimaryHoverColor - Whether theme defines primary hover color
|
|
47
|
+
* @returns CSS class string for primary button variant
|
|
48
|
+
*/
|
|
49
|
+
export function buildButtonPrimaryClasses(
|
|
50
|
+
hasPrimaryColor: boolean,
|
|
51
|
+
hasPrimaryHoverColor: boolean
|
|
52
|
+
): string {
|
|
53
|
+
if (hasPrimaryColor && hasPrimaryHoverColor) {
|
|
54
|
+
return 'bg-primary text-white hover:bg-primary-hover'
|
|
55
|
+
}
|
|
56
|
+
if (hasPrimaryColor) {
|
|
57
|
+
return 'bg-primary text-white'
|
|
58
|
+
}
|
|
59
|
+
return 'bg-blue-600 text-white hover:bg-blue-700'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Build badge border-radius based on theme configuration
|
|
64
|
+
* Uses theme.borderRadius.full if defined, otherwise falls back to rounded-full
|
|
65
|
+
*
|
|
66
|
+
* @param theme - Optional theme configuration
|
|
67
|
+
* @returns CSS rule for badge border-radius
|
|
68
|
+
*/
|
|
69
|
+
export function buildBadgeBorderRadius(theme?: Theme): string {
|
|
70
|
+
const hasFullRadius = Boolean(theme?.borderRadius?.full)
|
|
71
|
+
return hasFullRadius ? 'border-radius: var(--radius-full);' : '@apply rounded-full;'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate components layer styles with theme color applications
|
|
76
|
+
* Applies theme colors to component classes and button elements
|
|
77
|
+
*
|
|
78
|
+
* @param theme - Optional theme configuration
|
|
79
|
+
* @returns CSS @layer components rule as string
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* generateComponentsLayer(theme)
|
|
83
|
+
* // => '@layer components { .container-page { ... } .card { ... } ... }'
|
|
84
|
+
*/
|
|
85
|
+
export function generateComponentsLayer(theme?: Theme): string {
|
|
86
|
+
const hasPrimaryColor = Boolean(theme?.colors?.primary)
|
|
87
|
+
const hasPrimaryHoverColor = Boolean(theme?.colors?.['primary-hover'])
|
|
88
|
+
|
|
89
|
+
const btnClasses = buildButtonClasses(hasPrimaryColor, hasPrimaryHoverColor)
|
|
90
|
+
const btnPrimaryClasses = buildButtonPrimaryClasses(hasPrimaryColor, hasPrimaryHoverColor)
|
|
91
|
+
const badgeBorderRadius = buildBadgeBorderRadius(theme)
|
|
92
|
+
|
|
93
|
+
return `@layer components {
|
|
94
|
+
.container-page {
|
|
95
|
+
@apply mx-auto max-w-4xl px-4 py-8;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.card {
|
|
99
|
+
@apply rounded-lg border border-gray-200 bg-white p-6 shadow-sm;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.badge {
|
|
103
|
+
@apply border border-gray-200 bg-white px-2 py-1 text-xs font-medium;
|
|
104
|
+
${badgeBorderRadius}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.btn {
|
|
108
|
+
@apply ${btnClasses.join(' ')};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.btn-primary {
|
|
112
|
+
@apply ${btnPrimaryClasses};
|
|
113
|
+
}
|
|
114
|
+
}`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Generate utilities layer styles
|
|
119
|
+
* Combines static utilities with click interaction animations
|
|
120
|
+
*
|
|
121
|
+
* @returns CSS @layer utilities rule as string
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* generateUtilitiesLayer()
|
|
125
|
+
* // => '@layer utilities { .text-balance { ... } ... }'
|
|
126
|
+
*/
|
|
127
|
+
export function generateUtilitiesLayer(): string {
|
|
128
|
+
const clickAnimations = generateClickAnimationCSS()
|
|
129
|
+
|
|
130
|
+
return `@layer utilities {
|
|
131
|
+
.text-balance {
|
|
132
|
+
text-wrap: balance;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Safelist: Ensure critical utility classes are always included */
|
|
136
|
+
.text-center {
|
|
137
|
+
text-align: center;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Override Tailwind v4's multi-layer shadow system for shadow-none */
|
|
141
|
+
.shadow-none {
|
|
142
|
+
box-shadow: none !important;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
${clickAnimations}
|
|
146
|
+
}`
|
|
147
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
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 { BorderRadiusConfig } from '@/domain/models/app/theme/border-radius'
|
|
9
|
+
import type { BreakpointsConfig } from '@/domain/models/app/theme/breakpoints'
|
|
10
|
+
import type { ColorsConfig } from '@/domain/models/app/theme/colors'
|
|
11
|
+
import type { FontsConfig } from '@/domain/models/app/theme/fonts'
|
|
12
|
+
import type { ShadowsConfig } from '@/domain/models/app/theme/shadows'
|
|
13
|
+
import type { SpacingConfig } from '@/domain/models/app/theme/spacing'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Generate Tailwind @theme colors from domain color config
|
|
17
|
+
* Uses hex format directly - Tailwind v4 handles color format conversion
|
|
18
|
+
*/
|
|
19
|
+
export function generateThemeColors(colors?: ColorsConfig): string {
|
|
20
|
+
if (!colors || Object.keys(colors).length === 0) return ''
|
|
21
|
+
|
|
22
|
+
const colorEntries = Object.entries(colors).map(([name, value]) => {
|
|
23
|
+
return ` --color-${name}: ${value};`
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return colorEntries.join('\n')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generate Tailwind @theme font families from domain font config
|
|
31
|
+
*/
|
|
32
|
+
export function generateThemeFonts(fonts?: FontsConfig): string {
|
|
33
|
+
if (!fonts || Object.keys(fonts).length === 0) return ''
|
|
34
|
+
|
|
35
|
+
const fontEntries = Object.entries(fonts).flatMap(([category, config]) => {
|
|
36
|
+
// Type assertion needed because Record values are unknown in TypeScript
|
|
37
|
+
const fontConfig = config as {
|
|
38
|
+
family: string
|
|
39
|
+
fallback?: string
|
|
40
|
+
style?: string
|
|
41
|
+
transform?: string
|
|
42
|
+
letterSpacing?: string
|
|
43
|
+
}
|
|
44
|
+
const fontStack = fontConfig.fallback
|
|
45
|
+
? `${fontConfig.family}, ${fontConfig.fallback}`
|
|
46
|
+
: fontConfig.family
|
|
47
|
+
|
|
48
|
+
const baseEntry = ` --font-${category}: ${fontStack};`
|
|
49
|
+
|
|
50
|
+
// Build entries array immutably
|
|
51
|
+
const styleEntry =
|
|
52
|
+
fontConfig.style && fontConfig.style !== 'normal'
|
|
53
|
+
? ` --font-${category}-style: ${fontConfig.style};`
|
|
54
|
+
: undefined
|
|
55
|
+
|
|
56
|
+
const transformEntry =
|
|
57
|
+
fontConfig.transform && fontConfig.transform !== 'none'
|
|
58
|
+
? ` --font-${category}-transform: ${fontConfig.transform};`
|
|
59
|
+
: undefined
|
|
60
|
+
|
|
61
|
+
const letterSpacingEntry = fontConfig.letterSpacing
|
|
62
|
+
? ` --font-${category}-letter-spacing: ${fontConfig.letterSpacing};`
|
|
63
|
+
: undefined
|
|
64
|
+
|
|
65
|
+
return [baseEntry, styleEntry, transformEntry, letterSpacingEntry].filter(
|
|
66
|
+
(entry): entry is string => entry !== undefined
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
return fontEntries.join('\n')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Generate Tailwind @theme spacing from domain spacing config
|
|
75
|
+
* Only includes raw CSS values (rem, px, em), not Tailwind classes
|
|
76
|
+
*/
|
|
77
|
+
export function generateThemeSpacing(spacing?: SpacingConfig): string {
|
|
78
|
+
if (!spacing || Object.keys(spacing).length === 0) return ''
|
|
79
|
+
|
|
80
|
+
const spacingEntries = Object.entries(spacing)
|
|
81
|
+
.filter(([_, value]) => {
|
|
82
|
+
// Only include raw CSS values (not Tailwind classes)
|
|
83
|
+
return /^[0-9.]+(?:rem|px|em|%)$/.test(value as string)
|
|
84
|
+
})
|
|
85
|
+
.map(([name, value]) => ` --spacing-${name}: ${value};`)
|
|
86
|
+
|
|
87
|
+
return spacingEntries.join('\n')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generate Tailwind @theme shadows from domain shadow config
|
|
92
|
+
*/
|
|
93
|
+
export function generateThemeShadows(shadows?: ShadowsConfig): string {
|
|
94
|
+
if (!shadows || Object.keys(shadows).length === 0) return ''
|
|
95
|
+
|
|
96
|
+
const shadowEntries = Object.entries(shadows).map(([name, value]) => {
|
|
97
|
+
// Preserve original shadow values as-is
|
|
98
|
+
// The .shadow-none utility class override handles the actual rendering
|
|
99
|
+
return ` --shadow-${name}: ${value};`
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return shadowEntries.join('\n')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Generate Tailwind @theme border radius from domain border radius config
|
|
107
|
+
*/
|
|
108
|
+
export function generateThemeBorderRadius(borderRadius?: BorderRadiusConfig): string {
|
|
109
|
+
if (!borderRadius || Object.keys(borderRadius).length === 0) return ''
|
|
110
|
+
|
|
111
|
+
const radiusEntries = Object.entries(borderRadius).map(([name, value]) => {
|
|
112
|
+
const key = name === 'DEFAULT' ? 'radius' : `radius-${name}`
|
|
113
|
+
return ` --${key}: ${value};`
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return radiusEntries.join('\n')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Generate Tailwind @theme breakpoints from domain breakpoints config
|
|
121
|
+
*/
|
|
122
|
+
export function generateThemeBreakpoints(breakpoints?: BreakpointsConfig): string {
|
|
123
|
+
if (!breakpoints || Object.keys(breakpoints).length === 0) return ''
|
|
124
|
+
|
|
125
|
+
const breakpointEntries = Object.entries(breakpoints).map(
|
|
126
|
+
([name, value]) => ` --breakpoint-${name}: ${value};`
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return breakpointEntries.join('\n')
|
|
130
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
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 { Theme } from '@/domain/models/app/theme'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Theme color flags extracted from theme configuration
|
|
12
|
+
*/
|
|
13
|
+
export interface ThemeColorFlags {
|
|
14
|
+
readonly hasTextColor: boolean
|
|
15
|
+
readonly hasPrimaryColor: boolean
|
|
16
|
+
readonly hasPrimaryHoverColor: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Theme font flags extracted from theme configuration
|
|
21
|
+
*/
|
|
22
|
+
export interface ThemeFontFlags {
|
|
23
|
+
readonly hasTitleFont: boolean
|
|
24
|
+
readonly hasBodyFont: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Title font configuration type
|
|
29
|
+
*/
|
|
30
|
+
export interface TitleFontConfig {
|
|
31
|
+
readonly style?: string
|
|
32
|
+
readonly transform?: string
|
|
33
|
+
readonly letterSpacing?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extract color availability flags from theme
|
|
38
|
+
* Returns flags indicating which colors are defined in the theme
|
|
39
|
+
*
|
|
40
|
+
* @param theme - Optional theme configuration
|
|
41
|
+
* @returns Object with color availability flags
|
|
42
|
+
*/
|
|
43
|
+
export function extractThemeColorFlags(theme?: Theme): ThemeColorFlags {
|
|
44
|
+
return {
|
|
45
|
+
hasTextColor: Boolean(theme?.colors?.text),
|
|
46
|
+
hasPrimaryColor: Boolean(theme?.colors?.primary),
|
|
47
|
+
hasPrimaryHoverColor: Boolean(theme?.colors?.['primary-hover']),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Extract font availability flags from theme
|
|
53
|
+
* Returns flags indicating which fonts are defined in the theme
|
|
54
|
+
*
|
|
55
|
+
* @param theme - Optional theme configuration
|
|
56
|
+
* @returns Object with font availability flags
|
|
57
|
+
*/
|
|
58
|
+
export function extractThemeFontFlags(theme?: Theme): ThemeFontFlags {
|
|
59
|
+
return {
|
|
60
|
+
hasTitleFont: Boolean(theme?.fonts?.title),
|
|
61
|
+
hasBodyFont: Boolean(theme?.fonts?.body),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Extract title font properties from theme fonts config
|
|
67
|
+
* Returns undefined if no title font is configured
|
|
68
|
+
*
|
|
69
|
+
* @param theme - Optional theme configuration
|
|
70
|
+
* @returns Title font configuration or undefined
|
|
71
|
+
*/
|
|
72
|
+
export function extractTitleFontProperties(theme?: Theme): TitleFontConfig | undefined {
|
|
73
|
+
if (!theme?.fonts?.title || typeof theme.fonts.title !== 'object') {
|
|
74
|
+
return undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return theme.fonts.title as TitleFontConfig
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Build body classes with optional text color and font
|
|
82
|
+
*
|
|
83
|
+
* @param hasTextColor - Whether theme defines text color
|
|
84
|
+
* @param hasBodyFont - Whether theme defines body font
|
|
85
|
+
* @returns Array of CSS class names for body element
|
|
86
|
+
*/
|
|
87
|
+
export function buildBodyClasses(hasTextColor: boolean, hasBodyFont: boolean): readonly string[] {
|
|
88
|
+
const fontClass = hasBodyFont ? 'font-body' : 'font-sans'
|
|
89
|
+
return hasTextColor ? [fontClass, 'antialiased', 'text-text'] : [fontClass, 'antialiased']
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Build heading classes with optional text color and font
|
|
94
|
+
*
|
|
95
|
+
* @param hasTextColor - Whether theme defines text color
|
|
96
|
+
* @param hasTitleFont - Whether theme defines title font
|
|
97
|
+
* @returns Array of CSS class names for heading elements
|
|
98
|
+
*/
|
|
99
|
+
export function buildHeadingClasses(
|
|
100
|
+
hasTextColor: boolean,
|
|
101
|
+
hasTitleFont: boolean
|
|
102
|
+
): readonly string[] {
|
|
103
|
+
const fontClass = hasTitleFont ? 'font-title' : 'font-sans'
|
|
104
|
+
const baseClasses = hasTextColor
|
|
105
|
+
? [fontClass, 'font-semibold', 'tracking-tight', 'text-text']
|
|
106
|
+
: [fontClass, 'font-semibold', 'tracking-tight']
|
|
107
|
+
return baseClasses
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Build link classes with optional primary colors
|
|
112
|
+
*
|
|
113
|
+
* @param hasPrimaryColor - Whether theme defines primary color
|
|
114
|
+
* @param hasPrimaryHoverColor - Whether theme defines primary hover color
|
|
115
|
+
* @returns Array of CSS class names for link elements
|
|
116
|
+
*/
|
|
117
|
+
export function buildLinkClasses(
|
|
118
|
+
hasPrimaryColor: boolean,
|
|
119
|
+
hasPrimaryHoverColor: boolean
|
|
120
|
+
): readonly string[] {
|
|
121
|
+
if (hasPrimaryColor && hasPrimaryHoverColor) {
|
|
122
|
+
return ['transition-colors', 'text-primary', 'hover:text-primary-hover']
|
|
123
|
+
}
|
|
124
|
+
if (hasPrimaryColor) {
|
|
125
|
+
return ['transition-colors', 'text-primary']
|
|
126
|
+
}
|
|
127
|
+
return ['transition-colors', 'text-blue-600', 'hover:text-blue-700']
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Build CSS property strings for heading styles
|
|
132
|
+
* Returns array of CSS properties based on title font configuration
|
|
133
|
+
*
|
|
134
|
+
* @param titleFont - Optional title font configuration
|
|
135
|
+
* @returns Array of CSS property strings
|
|
136
|
+
*/
|
|
137
|
+
export function buildHeadingStyleProperties(titleFont?: TitleFontConfig): readonly string[] {
|
|
138
|
+
if (!titleFont) return []
|
|
139
|
+
|
|
140
|
+
const styleProperty =
|
|
141
|
+
titleFont.style && titleFont.style !== 'normal'
|
|
142
|
+
? `font-style: var(--font-title-style);`
|
|
143
|
+
: undefined
|
|
144
|
+
|
|
145
|
+
const transformProperty =
|
|
146
|
+
titleFont.transform && titleFont.transform !== 'none'
|
|
147
|
+
? `text-transform: var(--font-title-transform);`
|
|
148
|
+
: undefined
|
|
149
|
+
|
|
150
|
+
const letterSpacingProperty = titleFont.letterSpacing
|
|
151
|
+
? `letter-spacing: var(--font-title-letter-spacing);`
|
|
152
|
+
: undefined
|
|
153
|
+
|
|
154
|
+
return [styleProperty, transformProperty, letterSpacingProperty].filter(
|
|
155
|
+
(prop): prop is string => prop !== undefined
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Generate heading CSS with base classes and optional style properties
|
|
161
|
+
* Combines heading classes with additional CSS properties
|
|
162
|
+
*
|
|
163
|
+
* @param headingClasses - Array of CSS class names
|
|
164
|
+
* @param styleProps - Array of CSS property strings
|
|
165
|
+
* @returns Complete CSS rule for headings
|
|
166
|
+
*/
|
|
167
|
+
export function generateHeadingStyles(
|
|
168
|
+
headingClasses: readonly string[],
|
|
169
|
+
styleProps: readonly string[]
|
|
170
|
+
): string {
|
|
171
|
+
const baseStyles = `@apply ${headingClasses.join(' ')};`
|
|
172
|
+
if (styleProps.length === 0) return baseStyles
|
|
173
|
+
|
|
174
|
+
return `${baseStyles}
|
|
175
|
+
${styleProps.join('\n ')}`
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Generate base layer styles with theme color and font applications
|
|
180
|
+
* Applies theme colors and fonts to base HTML elements if theme defines those tokens
|
|
181
|
+
*
|
|
182
|
+
* @param theme - Optional theme configuration
|
|
183
|
+
* @returns CSS @layer base rule as string
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* generateBaseLayer(theme)
|
|
187
|
+
* // => '@layer base { body { ... } h1, h2, ... { ... } a { ... } }'
|
|
188
|
+
*/
|
|
189
|
+
export function generateBaseLayer(theme?: Theme): string {
|
|
190
|
+
const colorFlags = extractThemeColorFlags(theme)
|
|
191
|
+
const fontFlags = extractThemeFontFlags(theme)
|
|
192
|
+
|
|
193
|
+
const bodyClasses = buildBodyClasses(colorFlags.hasTextColor, fontFlags.hasBodyFont)
|
|
194
|
+
const headingClasses = buildHeadingClasses(colorFlags.hasTextColor, fontFlags.hasTitleFont)
|
|
195
|
+
const linkClasses = buildLinkClasses(colorFlags.hasPrimaryColor, colorFlags.hasPrimaryHoverColor)
|
|
196
|
+
|
|
197
|
+
const titleFont = extractTitleFontProperties(theme)
|
|
198
|
+
const headingStyleProps = buildHeadingStyleProperties(titleFont)
|
|
199
|
+
const headingStyles = generateHeadingStyles(headingClasses, headingStyleProps)
|
|
200
|
+
|
|
201
|
+
return `@layer base {
|
|
202
|
+
body {
|
|
203
|
+
@apply ${bodyClasses.join(' ')};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
h1,
|
|
207
|
+
h2,
|
|
208
|
+
h3,
|
|
209
|
+
h4,
|
|
210
|
+
h5,
|
|
211
|
+
h6 {
|
|
212
|
+
${headingStyles}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
a {
|
|
216
|
+
@apply ${linkClasses.join(' ')};
|
|
217
|
+
}
|
|
218
|
+
}`
|
|
219
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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 { Theme } from '@/domain/models/app/theme'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolve color token reference
|
|
12
|
+
*
|
|
13
|
+
* @param tokenName - Name of the color token (e.g., 'primary', 'text')
|
|
14
|
+
* @param theme - Optional theme configuration
|
|
15
|
+
* @returns Resolved color value or undefined if token not found
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* resolveColorToken('primary', theme) // => '#ff5733'
|
|
19
|
+
* resolveColorToken('unknown', theme) // => undefined
|
|
20
|
+
*/
|
|
21
|
+
export function resolveColorToken(tokenName: string, theme?: Theme): string | undefined {
|
|
22
|
+
if (!theme?.colors || !(tokenName in theme.colors)) return undefined
|
|
23
|
+
const colorValue = theme.colors[tokenName]
|
|
24
|
+
return colorValue ? String(colorValue) : undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resolve easing token reference
|
|
29
|
+
*
|
|
30
|
+
* @param tokenName - Name of the easing token (e.g., 'smooth', 'bounce')
|
|
31
|
+
* @param theme - Optional theme configuration
|
|
32
|
+
* @returns Resolved easing value or undefined if token not found
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* resolveEasingToken('smooth', theme) // => 'cubic-bezier(0.4, 0, 0.2, 1)'
|
|
36
|
+
* resolveEasingToken('unknown', theme) // => undefined
|
|
37
|
+
*/
|
|
38
|
+
export function resolveEasingToken(tokenName: string, theme?: Theme): string | undefined {
|
|
39
|
+
if (!theme?.animations) return undefined
|
|
40
|
+
const animations = theme.animations as Record<string, unknown>
|
|
41
|
+
const easingTokens = animations.easing as Record<string, unknown> | undefined
|
|
42
|
+
if (!easingTokens || typeof easingTokens !== 'object' || !(tokenName in easingTokens))
|
|
43
|
+
return undefined
|
|
44
|
+
const easingValue = easingTokens[tokenName]
|
|
45
|
+
return easingValue ? String(easingValue) : undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve token references in a value
|
|
50
|
+
* Supports: $colors.primary, $easing.smooth, etc.
|
|
51
|
+
*
|
|
52
|
+
* @param value - Value to resolve (can be string with token reference or any other type)
|
|
53
|
+
* @param theme - Optional theme configuration
|
|
54
|
+
* @returns Resolved value as string
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* resolveTokenReference('$colors.primary', theme) // => '#ff5733'
|
|
58
|
+
* resolveTokenReference('$easing.smooth', theme) // => 'cubic-bezier(0.4, 0, 0.2, 1)'
|
|
59
|
+
* resolveTokenReference('plain-value', theme) // => 'plain-value'
|
|
60
|
+
* resolveTokenReference(42, theme) // => '42'
|
|
61
|
+
*/
|
|
62
|
+
export function resolveTokenReference(value: unknown, theme?: Theme): string {
|
|
63
|
+
if (typeof value !== 'string') return String(value)
|
|
64
|
+
|
|
65
|
+
const tokenMatch = value.match(/^\$(\w+)\.(\w+)$/)
|
|
66
|
+
if (!tokenMatch) return value
|
|
67
|
+
|
|
68
|
+
const [, category, tokenName] = tokenMatch
|
|
69
|
+
if (!category || !tokenName) return value
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
(category === 'colors' ? resolveColorToken(tokenName, theme) : undefined) ??
|
|
73
|
+
(category === 'easing' ? resolveEasingToken(tokenName, theme) : undefined) ??
|
|
74
|
+
value
|
|
75
|
+
)
|
|
76
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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 { eq } from 'drizzle-orm'
|
|
9
|
+
import { Effect } from 'effect'
|
|
10
|
+
import { Database, activityLogs, users } from '@/infrastructure/database'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Activity log with user metadata
|
|
14
|
+
*/
|
|
15
|
+
export interface ActivityLogWithUser {
|
|
16
|
+
readonly id: string
|
|
17
|
+
readonly userId: string
|
|
18
|
+
readonly action: string
|
|
19
|
+
readonly tableName: string
|
|
20
|
+
readonly recordId: number
|
|
21
|
+
readonly changes: Record<string, unknown> | null
|
|
22
|
+
readonly createdAt: Date
|
|
23
|
+
readonly user: {
|
|
24
|
+
readonly id: string
|
|
25
|
+
readonly name: string
|
|
26
|
+
readonly email: string
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Database error for activity queries
|
|
32
|
+
*/
|
|
33
|
+
export class ActivityDatabaseError {
|
|
34
|
+
readonly _tag = 'ActivityDatabaseError'
|
|
35
|
+
constructor(readonly cause: unknown) {}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Activity not found error
|
|
40
|
+
*/
|
|
41
|
+
export class ActivityNotFoundError {
|
|
42
|
+
readonly _tag = 'ActivityNotFoundError'
|
|
43
|
+
constructor(readonly activityId: string) {}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get activity log by ID with user metadata
|
|
48
|
+
*
|
|
49
|
+
* Fetches activity log details with a JOIN to the users table to include
|
|
50
|
+
* user information (name, email).
|
|
51
|
+
*
|
|
52
|
+
* @param activityId - Activity log ID (UUID string or numeric string)
|
|
53
|
+
* @returns Effect program that resolves to activity with user metadata or fails with error
|
|
54
|
+
*/
|
|
55
|
+
export const getActivityById = (activityId: string) =>
|
|
56
|
+
Effect.gen(function* () {
|
|
57
|
+
const db = yield* Database
|
|
58
|
+
|
|
59
|
+
const result = yield* Effect.tryPromise({
|
|
60
|
+
try: () =>
|
|
61
|
+
db
|
|
62
|
+
.select({
|
|
63
|
+
id: activityLogs.id,
|
|
64
|
+
userId: activityLogs.userId,
|
|
65
|
+
action: activityLogs.action,
|
|
66
|
+
tableName: activityLogs.tableName,
|
|
67
|
+
recordId: activityLogs.recordId,
|
|
68
|
+
changes: activityLogs.changes,
|
|
69
|
+
createdAt: activityLogs.createdAt,
|
|
70
|
+
userName: users.name,
|
|
71
|
+
userEmail: users.email,
|
|
72
|
+
userIdJoined: users.id,
|
|
73
|
+
})
|
|
74
|
+
.from(activityLogs)
|
|
75
|
+
.leftJoin(users, eq(activityLogs.userId, users.id))
|
|
76
|
+
.where(eq(activityLogs.id, activityId))
|
|
77
|
+
.limit(1),
|
|
78
|
+
catch: (error) => new ActivityDatabaseError(error),
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
if (result.length === 0 || !result[0]) {
|
|
82
|
+
return yield* Effect.fail(new ActivityNotFoundError(activityId))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const row = result[0]
|
|
86
|
+
|
|
87
|
+
// Parse recordId as integer (stored as text in DB)
|
|
88
|
+
const recordIdInt = parseInt(row.recordId, 10)
|
|
89
|
+
const recordId = isNaN(recordIdInt) ? 0 : recordIdInt
|
|
90
|
+
|
|
91
|
+
// Changes is already JSONB (parsed by Drizzle), cast to expected type
|
|
92
|
+
// eslint-disable-next-line unicorn/no-null -- Null is intentional for JSONB columns with no data
|
|
93
|
+
const changes = (row.changes as Record<string, unknown> | null) ?? null
|
|
94
|
+
|
|
95
|
+
const activity: ActivityLogWithUser = {
|
|
96
|
+
id: row.id,
|
|
97
|
+
userId: row.userId ?? '',
|
|
98
|
+
action: row.action,
|
|
99
|
+
tableName: row.tableName,
|
|
100
|
+
recordId,
|
|
101
|
+
changes,
|
|
102
|
+
createdAt: row.createdAt,
|
|
103
|
+
user: {
|
|
104
|
+
id: row.userIdJoined ?? '',
|
|
105
|
+
name: row.userName ?? '',
|
|
106
|
+
email: row.userEmail ?? '',
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return activity
|
|
111
|
+
})
|