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,436 @@
|
|
|
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 { Effect } from 'effect'
|
|
9
|
+
import { CommentRepository } from '@/application/ports/repositories/comment-repository'
|
|
10
|
+
import { SessionContextError } from '@/domain/errors'
|
|
11
|
+
import type { UserMetadataWithOptionalImage } from '@/application/ports/models/user-metadata'
|
|
12
|
+
import type { UserSession } from '@/application/ports/models/user-session'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create comment on a record
|
|
16
|
+
*/
|
|
17
|
+
interface CreateCommentConfig {
|
|
18
|
+
readonly session: Readonly<UserSession>
|
|
19
|
+
readonly tableId: string
|
|
20
|
+
readonly recordId: string
|
|
21
|
+
readonly tableName: string
|
|
22
|
+
readonly content: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Format comment with user data
|
|
27
|
+
*/
|
|
28
|
+
function formatCommentResponse(comment: {
|
|
29
|
+
readonly id: string
|
|
30
|
+
readonly tableId: string
|
|
31
|
+
readonly recordId: string
|
|
32
|
+
readonly userId: string
|
|
33
|
+
readonly content: string
|
|
34
|
+
readonly createdAt: Date
|
|
35
|
+
readonly updatedAt?: Date
|
|
36
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
37
|
+
}) {
|
|
38
|
+
return {
|
|
39
|
+
comment: {
|
|
40
|
+
id: comment.id,
|
|
41
|
+
tableId: comment.tableId,
|
|
42
|
+
recordId: comment.recordId,
|
|
43
|
+
userId: comment.userId,
|
|
44
|
+
content: comment.content,
|
|
45
|
+
createdAt: comment.createdAt.toISOString(),
|
|
46
|
+
updatedAt: comment.updatedAt?.toISOString() ?? comment.createdAt.toISOString(),
|
|
47
|
+
user: comment.user,
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createCommentProgram(config: CreateCommentConfig): Effect.Effect<
|
|
53
|
+
{
|
|
54
|
+
readonly comment: {
|
|
55
|
+
readonly id: string
|
|
56
|
+
readonly tableId: string
|
|
57
|
+
readonly recordId: string
|
|
58
|
+
readonly userId: string
|
|
59
|
+
readonly content: string
|
|
60
|
+
readonly createdAt: string
|
|
61
|
+
readonly updatedAt: string
|
|
62
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
SessionContextError,
|
|
66
|
+
CommentRepository
|
|
67
|
+
> {
|
|
68
|
+
return Effect.gen(function* () {
|
|
69
|
+
const comments = yield* CommentRepository
|
|
70
|
+
const { session, tableId, recordId, tableName, content } = config
|
|
71
|
+
|
|
72
|
+
// Check if record exists
|
|
73
|
+
const hasAccess = yield* comments.checkRecordExists({ session, tableName, recordId })
|
|
74
|
+
if (!hasAccess) {
|
|
75
|
+
return yield* Effect.fail(new SessionContextError('Record not found'))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create comment
|
|
79
|
+
const comment = yield* comments.create({ session, tableId, recordId, content })
|
|
80
|
+
|
|
81
|
+
// Fetch comment with user metadata
|
|
82
|
+
const commentWithUser = yield* comments.getWithUser({ session, commentId: comment.id })
|
|
83
|
+
|
|
84
|
+
// Format response
|
|
85
|
+
return formatCommentResponse(commentWithUser ?? comment)
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Delete comment configuration
|
|
91
|
+
*/
|
|
92
|
+
interface DeleteCommentConfig {
|
|
93
|
+
readonly session: Readonly<UserSession>
|
|
94
|
+
readonly commentId: string
|
|
95
|
+
readonly tableName: string
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Delete comment program
|
|
100
|
+
*
|
|
101
|
+
* Authorization:
|
|
102
|
+
* - Comment author can delete their own comments
|
|
103
|
+
* - Admins can delete any comment
|
|
104
|
+
* - Returns 404 for non-existent comments, already deleted comments, or unauthorized access
|
|
105
|
+
*/
|
|
106
|
+
export function deleteCommentProgram(
|
|
107
|
+
config: DeleteCommentConfig
|
|
108
|
+
): Effect.Effect<void, SessionContextError, CommentRepository> {
|
|
109
|
+
return Effect.gen(function* () {
|
|
110
|
+
const comments = yield* CommentRepository
|
|
111
|
+
const { session, commentId, tableName } = config
|
|
112
|
+
|
|
113
|
+
// Get comment for authorization check
|
|
114
|
+
const comment = yield* comments.getForAuth({ session, commentId })
|
|
115
|
+
|
|
116
|
+
if (!comment) {
|
|
117
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get current user to check role
|
|
121
|
+
const currentUser = yield* comments.getUserById({ session, userId: session.userId })
|
|
122
|
+
|
|
123
|
+
if (!currentUser) {
|
|
124
|
+
return yield* Effect.fail(new SessionContextError('User not found'))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check authorization: user is comment author OR user is admin
|
|
128
|
+
const isAuthor = comment.userId === session.userId
|
|
129
|
+
const isAdmin = currentUser.role === 'admin'
|
|
130
|
+
|
|
131
|
+
// Check record exists (admins can access all records, non-admins only their own)
|
|
132
|
+
const hasRecordAccess = yield* comments.checkRecordExists({
|
|
133
|
+
session,
|
|
134
|
+
tableName,
|
|
135
|
+
recordId: comment.recordId,
|
|
136
|
+
isAdmin,
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
if (!hasRecordAccess) {
|
|
140
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!isAuthor && !isAdmin) {
|
|
144
|
+
// User has record access but is not the comment author and not an admin
|
|
145
|
+
// Return 403 Forbidden to explicitly deny the operation
|
|
146
|
+
return yield* Effect.fail(new SessionContextError('Forbidden'))
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Delete comment (soft delete)
|
|
150
|
+
yield* comments.remove({ session, commentId })
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get comment by ID configuration
|
|
156
|
+
*/
|
|
157
|
+
interface GetCommentConfig {
|
|
158
|
+
readonly session: Readonly<UserSession>
|
|
159
|
+
readonly commentId: string
|
|
160
|
+
readonly tableName: string
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get comment by ID program
|
|
165
|
+
*/
|
|
166
|
+
export function getCommentProgram(config: GetCommentConfig): Effect.Effect<
|
|
167
|
+
{
|
|
168
|
+
readonly comment: {
|
|
169
|
+
readonly id: string
|
|
170
|
+
readonly tableId: string
|
|
171
|
+
readonly recordId: string
|
|
172
|
+
readonly userId: string
|
|
173
|
+
readonly content: string
|
|
174
|
+
readonly createdAt: string
|
|
175
|
+
readonly updatedAt: string
|
|
176
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
SessionContextError,
|
|
180
|
+
CommentRepository
|
|
181
|
+
> {
|
|
182
|
+
return Effect.gen(function* () {
|
|
183
|
+
const comments = yield* CommentRepository
|
|
184
|
+
const { session, commentId, tableName } = config
|
|
185
|
+
|
|
186
|
+
// Get comment with user metadata
|
|
187
|
+
const comment = yield* comments.getWithUser({ session, commentId })
|
|
188
|
+
|
|
189
|
+
if (!comment) {
|
|
190
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check record exists (isAdmin: true because table-level read permission already validated by handler)
|
|
194
|
+
const recordExists = yield* comments.checkRecordExists({
|
|
195
|
+
session,
|
|
196
|
+
tableName,
|
|
197
|
+
recordId: comment.recordId,
|
|
198
|
+
isAdmin: true,
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
if (!recordExists) {
|
|
202
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Format response
|
|
206
|
+
return formatCommentResponse(comment)
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* List comments configuration
|
|
212
|
+
*/
|
|
213
|
+
interface ListCommentsConfig {
|
|
214
|
+
readonly session: Readonly<UserSession>
|
|
215
|
+
readonly recordId: string
|
|
216
|
+
readonly tableName: string
|
|
217
|
+
readonly limit?: number
|
|
218
|
+
readonly offset?: number
|
|
219
|
+
readonly sortOrder?: 'asc' | 'desc'
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Format list of comments
|
|
224
|
+
*/
|
|
225
|
+
function formatCommentsList(
|
|
226
|
+
comments: readonly {
|
|
227
|
+
readonly id: string
|
|
228
|
+
readonly tableId: string
|
|
229
|
+
readonly recordId: string
|
|
230
|
+
readonly userId: string
|
|
231
|
+
readonly content: string
|
|
232
|
+
readonly createdAt: Date
|
|
233
|
+
readonly updatedAt: Date
|
|
234
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
235
|
+
}[]
|
|
236
|
+
): readonly {
|
|
237
|
+
readonly id: string
|
|
238
|
+
readonly tableId: string
|
|
239
|
+
readonly recordId: string
|
|
240
|
+
readonly userId: string
|
|
241
|
+
readonly content: string
|
|
242
|
+
readonly createdAt: string
|
|
243
|
+
readonly updatedAt: string
|
|
244
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
245
|
+
}[] {
|
|
246
|
+
return comments.map((comment) => ({
|
|
247
|
+
id: comment.id,
|
|
248
|
+
tableId: comment.tableId,
|
|
249
|
+
recordId: comment.recordId,
|
|
250
|
+
userId: comment.userId,
|
|
251
|
+
content: comment.content,
|
|
252
|
+
createdAt: comment.createdAt.toISOString(),
|
|
253
|
+
updatedAt: comment.updatedAt.toISOString(),
|
|
254
|
+
user: comment.user,
|
|
255
|
+
}))
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Calculate pagination metadata if limit is provided
|
|
260
|
+
*/
|
|
261
|
+
function calculatePagination(params: {
|
|
262
|
+
readonly limit: number | undefined
|
|
263
|
+
readonly offset: number | undefined
|
|
264
|
+
readonly total: number
|
|
265
|
+
}):
|
|
266
|
+
| {
|
|
267
|
+
readonly total: number
|
|
268
|
+
readonly limit: number
|
|
269
|
+
readonly offset: number
|
|
270
|
+
readonly hasMore: boolean
|
|
271
|
+
}
|
|
272
|
+
| undefined {
|
|
273
|
+
const { limit, offset, total } = params
|
|
274
|
+
if (limit === undefined) {
|
|
275
|
+
return undefined
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const actualOffset = offset ?? 0
|
|
279
|
+
return {
|
|
280
|
+
total,
|
|
281
|
+
limit,
|
|
282
|
+
offset: actualOffset,
|
|
283
|
+
hasMore: actualOffset + limit < total,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Verify user has access to record
|
|
289
|
+
*/
|
|
290
|
+
function verifyRecordAccess(params: {
|
|
291
|
+
readonly session: Readonly<UserSession>
|
|
292
|
+
readonly tableName: string
|
|
293
|
+
readonly recordId: string
|
|
294
|
+
}): Effect.Effect<void, SessionContextError, CommentRepository> {
|
|
295
|
+
return Effect.gen(function* () {
|
|
296
|
+
const comments = yield* CommentRepository
|
|
297
|
+
const hasAccess = yield* comments.checkRecordExists(params)
|
|
298
|
+
if (!hasAccess) {
|
|
299
|
+
return yield* Effect.fail(new SessionContextError('Record not found'))
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Update comment configuration
|
|
306
|
+
*/
|
|
307
|
+
interface UpdateCommentConfig {
|
|
308
|
+
readonly session: Readonly<UserSession>
|
|
309
|
+
readonly commentId: string
|
|
310
|
+
readonly tableName: string
|
|
311
|
+
readonly content: string
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Update comment program
|
|
316
|
+
*
|
|
317
|
+
* Authorization:
|
|
318
|
+
* - Only the comment author can edit their own comments
|
|
319
|
+
* - Admins cannot edit other users' comments (respect authorship)
|
|
320
|
+
* - Returns 404 for non-existent comments, already deleted comments, or unauthorized access
|
|
321
|
+
* - Returns 403 for different user attempting to edit (even if they have record access)
|
|
322
|
+
*/
|
|
323
|
+
export function updateCommentProgram(config: UpdateCommentConfig): Effect.Effect<
|
|
324
|
+
{
|
|
325
|
+
readonly comment: {
|
|
326
|
+
readonly id: string
|
|
327
|
+
readonly tableId: string
|
|
328
|
+
readonly recordId: string
|
|
329
|
+
readonly userId: string
|
|
330
|
+
readonly content: string
|
|
331
|
+
readonly createdAt: string
|
|
332
|
+
readonly updatedAt: string
|
|
333
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
SessionContextError,
|
|
337
|
+
CommentRepository
|
|
338
|
+
> {
|
|
339
|
+
return Effect.gen(function* () {
|
|
340
|
+
const comments = yield* CommentRepository
|
|
341
|
+
const { session, commentId, tableName, content } = config
|
|
342
|
+
|
|
343
|
+
// Get comment for authorization check
|
|
344
|
+
const comment = yield* comments.getForAuth({ session, commentId })
|
|
345
|
+
|
|
346
|
+
if (!comment) {
|
|
347
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Check authorization: user must be comment author
|
|
351
|
+
const isAuthor = comment.userId === session.userId
|
|
352
|
+
|
|
353
|
+
// Check record exists
|
|
354
|
+
const hasRecordAccess = yield* comments.checkRecordExists({
|
|
355
|
+
session,
|
|
356
|
+
tableName,
|
|
357
|
+
recordId: comment.recordId,
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
if (!hasRecordAccess) {
|
|
361
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!isAuthor) {
|
|
365
|
+
// User has record access but is not the comment author
|
|
366
|
+
// Return 403 Forbidden to explicitly deny the operation
|
|
367
|
+
return yield* Effect.fail(new SessionContextError('Forbidden'))
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Update comment
|
|
371
|
+
yield* comments.update({ session, commentId, content })
|
|
372
|
+
|
|
373
|
+
// Fetch updated comment with user metadata
|
|
374
|
+
const updatedComment = yield* comments.getWithUser({ session, commentId })
|
|
375
|
+
|
|
376
|
+
if (!updatedComment) {
|
|
377
|
+
return yield* Effect.fail(new SessionContextError('Comment not found'))
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Format response
|
|
381
|
+
return formatCommentResponse(updatedComment)
|
|
382
|
+
})
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* List comments program
|
|
387
|
+
*/
|
|
388
|
+
export function listCommentsProgram(config: ListCommentsConfig): Effect.Effect<
|
|
389
|
+
{
|
|
390
|
+
readonly comments: readonly {
|
|
391
|
+
readonly id: string
|
|
392
|
+
readonly tableId: string
|
|
393
|
+
readonly recordId: string
|
|
394
|
+
readonly userId: string
|
|
395
|
+
readonly content: string
|
|
396
|
+
readonly createdAt: string
|
|
397
|
+
readonly updatedAt: string
|
|
398
|
+
readonly user?: UserMetadataWithOptionalImage | undefined
|
|
399
|
+
}[]
|
|
400
|
+
readonly pagination?: {
|
|
401
|
+
readonly total: number
|
|
402
|
+
readonly limit: number
|
|
403
|
+
readonly offset: number
|
|
404
|
+
readonly hasMore: boolean
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
SessionContextError,
|
|
408
|
+
CommentRepository
|
|
409
|
+
> {
|
|
410
|
+
return Effect.gen(function* () {
|
|
411
|
+
const comments = yield* CommentRepository
|
|
412
|
+
const { session, recordId, tableName, limit, offset, sortOrder } = config
|
|
413
|
+
|
|
414
|
+
// Check record exists
|
|
415
|
+
yield* verifyRecordAccess({ session, tableName, recordId })
|
|
416
|
+
|
|
417
|
+
// List comments
|
|
418
|
+
const commentsList = yield* comments.list({ session, recordId, limit, offset, sortOrder })
|
|
419
|
+
|
|
420
|
+
// Get total count and pagination if requested
|
|
421
|
+
const pagination =
|
|
422
|
+
limit !== undefined
|
|
423
|
+
? calculatePagination({
|
|
424
|
+
limit,
|
|
425
|
+
offset,
|
|
426
|
+
total: yield* comments.getCount({ session, recordId }),
|
|
427
|
+
})
|
|
428
|
+
: undefined
|
|
429
|
+
|
|
430
|
+
// Format response
|
|
431
|
+
return {
|
|
432
|
+
comments: formatCommentsList(commentsList),
|
|
433
|
+
...(pagination && { pagination }),
|
|
434
|
+
}
|
|
435
|
+
})
|
|
436
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
* Re-export all permission functions from domain layer.
|
|
10
|
+
*
|
|
11
|
+
* The canonical implementation lives in the domain layer at
|
|
12
|
+
* `@/domain/models/app/table/permissions/permission-evaluator`.
|
|
13
|
+
* This file re-exports for backward compatibility with existing consumers.
|
|
14
|
+
*/
|
|
15
|
+
export {
|
|
16
|
+
hasPermission,
|
|
17
|
+
isAdminRole,
|
|
18
|
+
checkPermissionWithAdminOverride,
|
|
19
|
+
evaluateTablePermissions,
|
|
20
|
+
evaluateFieldPermissions,
|
|
21
|
+
hasCreatePermission,
|
|
22
|
+
hasDeletePermission,
|
|
23
|
+
hasUpdatePermission,
|
|
24
|
+
hasReadPermission,
|
|
25
|
+
} from '@/domain/models/app/table/permissions'
|