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,412 @@
|
|
|
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 { TableRepository } from '@/application/ports/repositories/table-repository'
|
|
10
|
+
import { ForbiddenError } from '@/domain/errors'
|
|
11
|
+
import {
|
|
12
|
+
isAdminRole,
|
|
13
|
+
hasPermission,
|
|
14
|
+
evaluateTablePermissions,
|
|
15
|
+
evaluateFieldPermissions,
|
|
16
|
+
} from './permissions/permissions'
|
|
17
|
+
import { processRecords } from './utils/list-helpers'
|
|
18
|
+
import type { UserSession } from '@/application/ports/models/user-session'
|
|
19
|
+
import type { SessionContextError } from '@/domain/errors'
|
|
20
|
+
import type { GetTableResponse } from '@/domain/models/api/tables'
|
|
21
|
+
import type { App } from '@/domain/models/app'
|
|
22
|
+
|
|
23
|
+
/* eslint-disable functional/no-expression-statements -- Error subclass requires super() and this.name assignment */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Error when table is not found
|
|
27
|
+
*/
|
|
28
|
+
export class TableNotFoundError extends Error {
|
|
29
|
+
readonly _tag = 'TableNotFoundError'
|
|
30
|
+
|
|
31
|
+
constructor(message: string) {
|
|
32
|
+
super(message)
|
|
33
|
+
this.name = 'TableNotFoundError'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* eslint-enable functional/no-expression-statements */
|
|
38
|
+
|
|
39
|
+
// Constants
|
|
40
|
+
const ALLOWED_ROLES_TO_LIST_TABLES: readonly string[] = ['admin', 'member'] as const
|
|
41
|
+
|
|
42
|
+
export function createListTablesProgram(
|
|
43
|
+
userRole: string,
|
|
44
|
+
app: App
|
|
45
|
+
): Effect.Effect<readonly unknown[], Error> {
|
|
46
|
+
// Global permission check: only admin/member can list tables
|
|
47
|
+
// Viewer role is explicitly denied from listing tables
|
|
48
|
+
if (
|
|
49
|
+
!ALLOWED_ROLES_TO_LIST_TABLES.includes(
|
|
50
|
+
userRole as (typeof ALLOWED_ROLES_TO_LIST_TABLES)[number]
|
|
51
|
+
)
|
|
52
|
+
) {
|
|
53
|
+
return Effect.fail(new ForbiddenError('You do not have permission to list tables'))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Filter tables based on user's read permissions
|
|
57
|
+
// Only return tables the user has permission to view
|
|
58
|
+
const tables = app.tables ?? []
|
|
59
|
+
|
|
60
|
+
const accessibleTables = tables.filter((table) => {
|
|
61
|
+
const readPermission = table.permissions?.read
|
|
62
|
+
|
|
63
|
+
// If no read permission configured, deny access by default (secure by default)
|
|
64
|
+
if (!readPermission) {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check permission using simplified 3-format system
|
|
69
|
+
if (readPermission === 'all') return true
|
|
70
|
+
if (readPermission === 'authenticated') return true
|
|
71
|
+
if (Array.isArray(readPermission)) return readPermission.includes(userRole)
|
|
72
|
+
|
|
73
|
+
return false
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Map tables to API response format
|
|
77
|
+
const result = accessibleTables.map((table) => ({
|
|
78
|
+
id: String(table.id),
|
|
79
|
+
name: table.name,
|
|
80
|
+
description: undefined, // Domain model doesn't have table description
|
|
81
|
+
createdAt: new Date().toISOString(),
|
|
82
|
+
updatedAt: new Date().toISOString(),
|
|
83
|
+
}))
|
|
84
|
+
|
|
85
|
+
return Effect.succeed(result)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function createGetTableProgram(
|
|
89
|
+
tableId: string,
|
|
90
|
+
app: App,
|
|
91
|
+
userRole: string
|
|
92
|
+
): Effect.Effect<GetTableResponse, Error> {
|
|
93
|
+
return Effect.gen(function* () {
|
|
94
|
+
// Find table by ID or name
|
|
95
|
+
const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
|
|
96
|
+
|
|
97
|
+
if (!table) {
|
|
98
|
+
return yield* Effect.fail(new TableNotFoundError('TABLE_NOT_FOUND'))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check table-level read permissions using simplified 3-format system
|
|
102
|
+
if (!hasPermission(table.permissions?.read, userRole)) {
|
|
103
|
+
return yield* Effect.fail(
|
|
104
|
+
new ForbiddenError('You do not have permission to access this table')
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Map table fields to API response format
|
|
109
|
+
const fields = table.fields.map((field) => ({
|
|
110
|
+
id: String(field.id),
|
|
111
|
+
name: field.name,
|
|
112
|
+
type: field.type,
|
|
113
|
+
required: field.required,
|
|
114
|
+
unique: field.unique,
|
|
115
|
+
indexed: field.indexed,
|
|
116
|
+
description: undefined, // Domain model doesn't have description field
|
|
117
|
+
}))
|
|
118
|
+
|
|
119
|
+
// Convert primaryKey object to string (field name) for API response
|
|
120
|
+
const primaryKeyField = table.primaryKey?.field || undefined
|
|
121
|
+
|
|
122
|
+
// Get views from table (or empty array if no views)
|
|
123
|
+
const views = table.views ?? []
|
|
124
|
+
const mappedViews = views.map(mapViewToResponse)
|
|
125
|
+
|
|
126
|
+
// Map permissions to API format
|
|
127
|
+
const permissions = table.permissions
|
|
128
|
+
? {
|
|
129
|
+
read: table.permissions.read,
|
|
130
|
+
create: table.permissions.create,
|
|
131
|
+
update: table.permissions.update,
|
|
132
|
+
// eslint-disable-next-line drizzle/enforce-delete-with-where -- False positive: accessing property, not calling Drizzle delete method
|
|
133
|
+
delete: table.permissions.delete,
|
|
134
|
+
}
|
|
135
|
+
: undefined
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
table: {
|
|
139
|
+
id: String(table.id),
|
|
140
|
+
name: table.name,
|
|
141
|
+
description: undefined, // Domain model doesn't have table description
|
|
142
|
+
fields,
|
|
143
|
+
primaryKey: primaryKeyField,
|
|
144
|
+
views: mappedViews,
|
|
145
|
+
permissions,
|
|
146
|
+
createdAt: new Date().toISOString(),
|
|
147
|
+
updatedAt: new Date().toISOString(),
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Evaluate table and field permissions for a user
|
|
155
|
+
*/
|
|
156
|
+
export function createGetPermissionsProgram(
|
|
157
|
+
tableId: string,
|
|
158
|
+
app: App,
|
|
159
|
+
userRole: string
|
|
160
|
+
): Effect.Effect<
|
|
161
|
+
{
|
|
162
|
+
readonly table: {
|
|
163
|
+
readonly read: boolean
|
|
164
|
+
readonly create: boolean
|
|
165
|
+
readonly update: boolean
|
|
166
|
+
readonly delete: boolean
|
|
167
|
+
}
|
|
168
|
+
readonly fields: Record<string, { readonly read: boolean; readonly write: boolean }>
|
|
169
|
+
},
|
|
170
|
+
Error
|
|
171
|
+
> {
|
|
172
|
+
return Effect.gen(function* () {
|
|
173
|
+
// Find table by ID or name
|
|
174
|
+
const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
|
|
175
|
+
|
|
176
|
+
if (!table) {
|
|
177
|
+
return yield* Effect.fail(new TableNotFoundError('TABLE_NOT_FOUND'))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Admin role gets all permissions as true (override)
|
|
181
|
+
const isAdmin = isAdminRole(userRole)
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
table: evaluateTablePermissions(table.permissions, userRole, isAdmin),
|
|
185
|
+
fields: evaluateFieldPermissions(table.permissions?.fields, userRole, isAdmin),
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Check if a view is accessible to a user based on permissions
|
|
192
|
+
*/
|
|
193
|
+
function isViewAccessible(view: { readonly permissions?: unknown }, userRole: string): boolean {
|
|
194
|
+
// No permissions configured - view is public
|
|
195
|
+
if (!view.permissions) {
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check if permissions is public type
|
|
200
|
+
if (typeof view.permissions === 'object' && 'public' in view.permissions) {
|
|
201
|
+
const publicPermissions = view.permissions as { readonly public: boolean }
|
|
202
|
+
return publicPermissions.public === true
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// At this point, permissions must be the read/write type
|
|
206
|
+
const permissions = view.permissions as {
|
|
207
|
+
readonly read?: readonly string[]
|
|
208
|
+
readonly write?: readonly string[]
|
|
209
|
+
}
|
|
210
|
+
const viewReadPermission = permissions.read
|
|
211
|
+
|
|
212
|
+
// No read permission configured - deny access (secure by default)
|
|
213
|
+
if (!viewReadPermission) {
|
|
214
|
+
return false
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Check if user's role is in allowed roles
|
|
218
|
+
return Array.isArray(viewReadPermission) && viewReadPermission.includes(userRole)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Map a view to response format
|
|
223
|
+
*/
|
|
224
|
+
function mapViewToResponse(view: {
|
|
225
|
+
readonly id: string | number
|
|
226
|
+
readonly name: string
|
|
227
|
+
readonly filters?: unknown
|
|
228
|
+
readonly sorts?: unknown
|
|
229
|
+
readonly fields?: unknown
|
|
230
|
+
readonly groupBy?: unknown
|
|
231
|
+
readonly isDefault?: boolean
|
|
232
|
+
}): unknown {
|
|
233
|
+
return {
|
|
234
|
+
id: view.id,
|
|
235
|
+
name: view.name,
|
|
236
|
+
...(view.filters !== undefined ? { filters: view.filters } : {}),
|
|
237
|
+
...(view.sorts !== undefined ? { sorts: view.sorts } : {}),
|
|
238
|
+
...(view.fields !== undefined ? { fields: view.fields } : {}),
|
|
239
|
+
...(view.groupBy !== undefined ? { groupBy: view.groupBy } : {}),
|
|
240
|
+
...(view.isDefault !== undefined ? { isDefault: view.isDefault } : {}),
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function listViewsProgram(
|
|
245
|
+
tableId: string,
|
|
246
|
+
app: App,
|
|
247
|
+
userRole: string
|
|
248
|
+
): Effect.Effect<readonly unknown[], TableNotFoundError | ForbiddenError> {
|
|
249
|
+
return Effect.gen(function* () {
|
|
250
|
+
// Find table by ID or name
|
|
251
|
+
const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
|
|
252
|
+
|
|
253
|
+
if (!table) {
|
|
254
|
+
return yield* Effect.fail(new TableNotFoundError('Table not found'))
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Check table-level read permissions using simplified 3-format system
|
|
258
|
+
const readPermission = table.permissions?.read
|
|
259
|
+
if (Array.isArray(readPermission) && !readPermission.includes(userRole)) {
|
|
260
|
+
return yield* Effect.fail(
|
|
261
|
+
new ForbiddenError('You do not have permission to access this table')
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Get views from table (or empty array if no views)
|
|
266
|
+
const views = table.views ?? []
|
|
267
|
+
|
|
268
|
+
// Filter views based on read permissions and map to response format
|
|
269
|
+
const accessibleViews = views.filter((view) => isViewAccessible(view, userRole))
|
|
270
|
+
return accessibleViews.map(mapViewToResponse)
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function getViewProgram(
|
|
275
|
+
tableId: string,
|
|
276
|
+
viewId: string,
|
|
277
|
+
app: App
|
|
278
|
+
): Effect.Effect<unknown, TableNotFoundError> {
|
|
279
|
+
return Effect.gen(function* () {
|
|
280
|
+
// Find table by ID or name
|
|
281
|
+
const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
|
|
282
|
+
|
|
283
|
+
if (!table) {
|
|
284
|
+
return yield* Effect.fail(new TableNotFoundError('Table not found'))
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Find view in table
|
|
288
|
+
const view = table.views?.find((v) => v.id === viewId)
|
|
289
|
+
|
|
290
|
+
if (!view) {
|
|
291
|
+
return yield* Effect.fail(new TableNotFoundError('View not found'))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Return view properties at root level
|
|
295
|
+
return {
|
|
296
|
+
id: view.id,
|
|
297
|
+
name: view.name,
|
|
298
|
+
...(view.filters !== undefined ? { filters: view.filters } : {}),
|
|
299
|
+
...(view.sorts !== undefined ? { sorts: view.sorts } : {}),
|
|
300
|
+
...(view.fields !== undefined ? { fields: view.fields } : {}),
|
|
301
|
+
...(view.groupBy !== undefined ? { groupBy: view.groupBy } : {}),
|
|
302
|
+
...(view.isDefault !== undefined ? { isDefault: view.isDefault } : {}),
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Build query parameters from view configuration
|
|
309
|
+
*/
|
|
310
|
+
function buildViewQueryParams(view: {
|
|
311
|
+
readonly filters?: unknown
|
|
312
|
+
readonly sorts?: readonly { readonly field: string; readonly direction: string }[]
|
|
313
|
+
readonly fields?: readonly string[] | unknown
|
|
314
|
+
}): {
|
|
315
|
+
readonly filter:
|
|
316
|
+
| {
|
|
317
|
+
readonly and?: readonly {
|
|
318
|
+
readonly field: string
|
|
319
|
+
readonly operator: string
|
|
320
|
+
readonly value: unknown
|
|
321
|
+
}[]
|
|
322
|
+
}
|
|
323
|
+
| undefined
|
|
324
|
+
readonly sort: string
|
|
325
|
+
readonly fields: string | undefined
|
|
326
|
+
} {
|
|
327
|
+
// Build filter from view filters
|
|
328
|
+
// View filters may be of type ViewFilterNode, need to extract the 'and' array if present
|
|
329
|
+
const filter = view.filters as
|
|
330
|
+
| {
|
|
331
|
+
readonly and?: readonly {
|
|
332
|
+
readonly field: string
|
|
333
|
+
readonly operator: string
|
|
334
|
+
readonly value: unknown
|
|
335
|
+
}[]
|
|
336
|
+
}
|
|
337
|
+
| undefined
|
|
338
|
+
|
|
339
|
+
// Build sort from view sorts
|
|
340
|
+
const sortArray = view.sorts || []
|
|
341
|
+
const sort = sortArray.map((s) => `${s.field}:${s.direction}`).join(',')
|
|
342
|
+
|
|
343
|
+
// Build fields list from view fields
|
|
344
|
+
const fieldsStr = Array.isArray(view.fields) ? view.fields.join(',') : undefined
|
|
345
|
+
|
|
346
|
+
return { filter, sort, fields: fieldsStr }
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function getViewRecordsProgram(config: {
|
|
350
|
+
readonly tableId: string
|
|
351
|
+
readonly viewId: string
|
|
352
|
+
readonly app: App
|
|
353
|
+
readonly userRole: string
|
|
354
|
+
readonly session: Readonly<UserSession>
|
|
355
|
+
}): Effect.Effect<
|
|
356
|
+
unknown,
|
|
357
|
+
TableNotFoundError | ForbiddenError | SessionContextError,
|
|
358
|
+
TableRepository
|
|
359
|
+
> {
|
|
360
|
+
return Effect.gen(function* () {
|
|
361
|
+
const repo = yield* TableRepository
|
|
362
|
+
const { tableId, viewId, app, userRole, session } = config
|
|
363
|
+
|
|
364
|
+
// Find table by ID or name
|
|
365
|
+
const table = app.tables?.find((t) => String(t.id) === tableId || t.name === tableId)
|
|
366
|
+
|
|
367
|
+
if (!table) {
|
|
368
|
+
return yield* Effect.fail(new TableNotFoundError('Table not found'))
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Find view in table
|
|
372
|
+
const view = table.views?.find((v) => v.id === viewId)
|
|
373
|
+
|
|
374
|
+
if (!view) {
|
|
375
|
+
return yield* Effect.fail(new TableNotFoundError('View not found'))
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Check view-level read permissions
|
|
379
|
+
if (!isViewAccessible(view, userRole)) {
|
|
380
|
+
return yield* Effect.fail(
|
|
381
|
+
new ForbiddenError('You do not have permission to access this view')
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Build query parameters from view configuration
|
|
386
|
+
const { filter, sort, fields } = buildViewQueryParams(view)
|
|
387
|
+
|
|
388
|
+
// Query records with view filters and sorts
|
|
389
|
+
const records = yield* repo.listRecords({
|
|
390
|
+
session,
|
|
391
|
+
tableName: table.name,
|
|
392
|
+
filter,
|
|
393
|
+
includeDeleted: false,
|
|
394
|
+
sort: sort || undefined,
|
|
395
|
+
app,
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
// Process records with field filtering
|
|
399
|
+
const processedRecords = processRecords({
|
|
400
|
+
records,
|
|
401
|
+
app,
|
|
402
|
+
tableName: table.name,
|
|
403
|
+
userRole,
|
|
404
|
+
userId: session.userId,
|
|
405
|
+
fields,
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
records: [...processedRecords],
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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 { AuthRepository } from '@/application/ports/repositories/auth-repository'
|
|
10
|
+
|
|
11
|
+
// Constants
|
|
12
|
+
const DEFAULT_ROLE = 'member'
|
|
13
|
+
|
|
14
|
+
/** Service shape for direct injection (used by tests to bypass Effect DI) */
|
|
15
|
+
export type AuthRoleService = {
|
|
16
|
+
readonly getUserRole: (userId: string) => Promise<string | undefined>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves the user's global role from the database
|
|
21
|
+
*
|
|
22
|
+
* Delegates to AuthRepository (infrastructure layer) for database access.
|
|
23
|
+
* This application layer function provides a convenient async interface
|
|
24
|
+
* for use in presentation layer middleware and routes.
|
|
25
|
+
*
|
|
26
|
+
* Role resolution:
|
|
27
|
+
* 1. Fetch global user role from users table via AuthRepository
|
|
28
|
+
* 2. Default: 'member'
|
|
29
|
+
*
|
|
30
|
+
* @param userId - The user ID to look up
|
|
31
|
+
* @param service - Optional direct service injection (for unit tests).
|
|
32
|
+
* Uses plain Promises to avoid Effect module contamination in Bun's shared process.
|
|
33
|
+
*/
|
|
34
|
+
export async function getUserRole(userId: string, service?: AuthRoleService): Promise<string> {
|
|
35
|
+
if (service) {
|
|
36
|
+
const role = await service.getUserRole(userId)
|
|
37
|
+
return role ?? DEFAULT_ROLE
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Lazy-load AuthRepositoryLive to avoid triggering database initialization at import time.
|
|
41
|
+
const { AuthRepositoryLive } =
|
|
42
|
+
await import('@/infrastructure/database/repositories/auth-repository-live')
|
|
43
|
+
|
|
44
|
+
const program = Effect.gen(function* () {
|
|
45
|
+
const repo = yield* AuthRepository
|
|
46
|
+
return yield* repo.getUserRole(userId)
|
|
47
|
+
}).pipe(Effect.provide(AuthRepositoryLive))
|
|
48
|
+
|
|
49
|
+
const role = await Effect.runPromise(program)
|
|
50
|
+
|
|
51
|
+
return role ?? DEFAULT_ROLE
|
|
52
|
+
}
|