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,108 @@
|
|
|
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 { generateIndexStatements } from '../generators/index-generators'
|
|
10
|
+
import {
|
|
11
|
+
executeSQLStatements,
|
|
12
|
+
type TransactionLike,
|
|
13
|
+
type SQLExecutionError,
|
|
14
|
+
} from '../sql/sql-execution'
|
|
15
|
+
import type { Table } from '@/domain/models/app/table'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Helper to generate DROP INDEX statements for indexes that need to be removed
|
|
19
|
+
*/
|
|
20
|
+
const generateDropIndexStatements = (
|
|
21
|
+
table: Table,
|
|
22
|
+
previousTable:
|
|
23
|
+
| {
|
|
24
|
+
readonly name: string
|
|
25
|
+
readonly fields?: readonly { name?: string; indexed?: boolean }[]
|
|
26
|
+
readonly indexes?: readonly { name: string }[]
|
|
27
|
+
}
|
|
28
|
+
| undefined
|
|
29
|
+
): readonly string[] => {
|
|
30
|
+
if (!previousTable) return []
|
|
31
|
+
|
|
32
|
+
// Drop indexes for fields that no longer have indexed: true
|
|
33
|
+
const previousIndexedFields =
|
|
34
|
+
previousTable.fields
|
|
35
|
+
?.filter((f) => f.name && 'indexed' in f && f.indexed)
|
|
36
|
+
.map((f) => f.name!) ?? []
|
|
37
|
+
|
|
38
|
+
const currentIndexedFields = new Set(
|
|
39
|
+
table.fields.filter((f) => 'indexed' in f && f.indexed).map((f) => f.name)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const removedIndexedFields = previousIndexedFields.filter(
|
|
43
|
+
(fieldName) => !currentIndexedFields.has(fieldName)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
const fieldIndexDrops = removedIndexedFields.map((fieldName) => {
|
|
47
|
+
const indexName = `idx_${table.name}_${fieldName}`
|
|
48
|
+
return `DROP INDEX IF EXISTS ${indexName}`
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Drop indexes for fields that changed from indexed to unique
|
|
52
|
+
const currentUniqueFields = new Set(
|
|
53
|
+
table.fields.filter((f) => 'unique' in f && f.unique).map((f) => f.name)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const indexToUniqueFields = previousIndexedFields.filter((fieldName) =>
|
|
57
|
+
currentUniqueFields.has(fieldName)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const indexToUniqueDrops = indexToUniqueFields.map((fieldName) => {
|
|
61
|
+
const indexName = `idx_${table.name}_${fieldName}`
|
|
62
|
+
return `DROP INDEX IF EXISTS ${indexName}`
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Drop custom indexes that were removed
|
|
66
|
+
const previousCustomIndexes = previousTable.indexes?.map((idx) => idx.name) ?? []
|
|
67
|
+
const currentCustomIndexes = table.indexes?.map((idx) => idx.name) ?? []
|
|
68
|
+
|
|
69
|
+
const removedCustomIndexes = previousCustomIndexes.filter(
|
|
70
|
+
(name) => !currentCustomIndexes.includes(name)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const customIndexDrops = removedCustomIndexes.map((name) => `DROP INDEX IF EXISTS ${name}`)
|
|
74
|
+
|
|
75
|
+
return [...fieldIndexDrops, ...indexToUniqueDrops, ...customIndexDrops]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Sync indexes for existing table
|
|
80
|
+
* Drops indexes that are no longer needed and creates new indexes
|
|
81
|
+
* This is needed when field indexed property changes or custom indexes are added/removed
|
|
82
|
+
*/
|
|
83
|
+
export const syncIndexes = (
|
|
84
|
+
tx: TransactionLike,
|
|
85
|
+
table: Table,
|
|
86
|
+
previousSchema?: { readonly tables: readonly object[] }
|
|
87
|
+
): Effect.Effect<void, SQLExecutionError> =>
|
|
88
|
+
Effect.gen(function* () {
|
|
89
|
+
// Get previous table definition
|
|
90
|
+
const previousTable = previousSchema?.tables.find(
|
|
91
|
+
(t: object) => 'name' in t && t.name === table.name
|
|
92
|
+
) as
|
|
93
|
+
| {
|
|
94
|
+
name: string
|
|
95
|
+
fields?: readonly { name?: string; indexed?: boolean }[]
|
|
96
|
+
indexes?: readonly { name: string }[]
|
|
97
|
+
}
|
|
98
|
+
| undefined
|
|
99
|
+
|
|
100
|
+
// Determine which indexes should be dropped
|
|
101
|
+
const dropStatements = generateDropIndexStatements(table, previousTable)
|
|
102
|
+
|
|
103
|
+
// Generate CREATE INDEX statements for all current indexes
|
|
104
|
+
const createStatements = generateIndexStatements(table)
|
|
105
|
+
|
|
106
|
+
// Execute drop statements first, then create statements
|
|
107
|
+
yield* executeSQLStatements(tx, [...dropStatements, ...createStatements])
|
|
108
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
* Schema Migration Helpers
|
|
10
|
+
*
|
|
11
|
+
* This module provides utilities for database schema migrations:
|
|
12
|
+
* - Table operations (rename, drop obsolete)
|
|
13
|
+
* - Column detection (add, drop, modify)
|
|
14
|
+
* - Type conversions and nullability changes
|
|
15
|
+
* - Constraint synchronization (unique, foreign key, check)
|
|
16
|
+
* - Index synchronization
|
|
17
|
+
*
|
|
18
|
+
* All functions use Effect for type-safe error handling.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// Type exports
|
|
22
|
+
export type { ExistingColumnInfo } from './column-detection'
|
|
23
|
+
export { type TransactionLike as BunSQLTransaction } from '../sql/sql-execution'
|
|
24
|
+
|
|
25
|
+
// Constants
|
|
26
|
+
export { PROTECTED_SYSTEM_TABLES } from './constants'
|
|
27
|
+
|
|
28
|
+
// Rename detection
|
|
29
|
+
export { detectFieldRenames, detectTableRenames } from './rename-detection'
|
|
30
|
+
|
|
31
|
+
// Table operations
|
|
32
|
+
export { renameTablesIfNeeded, dropObsoleteTables } from './table-operations'
|
|
33
|
+
|
|
34
|
+
// Type utilities
|
|
35
|
+
export {
|
|
36
|
+
normalizeDataType,
|
|
37
|
+
doesColumnTypeMatch,
|
|
38
|
+
generateAlterColumnTypeStatement,
|
|
39
|
+
} from './type-utils'
|
|
40
|
+
|
|
41
|
+
// Column detection
|
|
42
|
+
export {
|
|
43
|
+
needsIdColumnRecreation,
|
|
44
|
+
findColumnsToAdd,
|
|
45
|
+
findColumnsToDrop,
|
|
46
|
+
filterModifiableFields,
|
|
47
|
+
findTypeChanges,
|
|
48
|
+
generateNotNullValidationQuery,
|
|
49
|
+
generateBackfillQuery,
|
|
50
|
+
findNullabilityChanges,
|
|
51
|
+
findDefaultValueChanges,
|
|
52
|
+
buildColumnStatements,
|
|
53
|
+
} from './column-detection'
|
|
54
|
+
|
|
55
|
+
// Migration statement generation
|
|
56
|
+
export { generateAlterTableStatements } from './migration-statements'
|
|
57
|
+
|
|
58
|
+
// Constraint synchronization
|
|
59
|
+
export {
|
|
60
|
+
syncUniqueConstraints,
|
|
61
|
+
syncForeignKeyConstraints,
|
|
62
|
+
syncCheckConstraints,
|
|
63
|
+
} from './constraint-sync'
|
|
64
|
+
|
|
65
|
+
// Index synchronization
|
|
66
|
+
export { syncIndexes } from './index-sync'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
needsIdColumnRecreation,
|
|
10
|
+
findColumnsToAdd,
|
|
11
|
+
findColumnsToDrop,
|
|
12
|
+
findTypeChanges,
|
|
13
|
+
findNullabilityChanges,
|
|
14
|
+
findDefaultValueChanges,
|
|
15
|
+
buildColumnStatements,
|
|
16
|
+
type ExistingColumnInfo,
|
|
17
|
+
} from './column-detection'
|
|
18
|
+
import { detectFieldRenames } from './rename-detection'
|
|
19
|
+
import type { Table } from '@/domain/models/app/table'
|
|
20
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
21
|
+
|
|
22
|
+
/** Generate statements for automatic timestamp fields (created_at, updated_at, deleted_at) */
|
|
23
|
+
const generateSpecialFieldStatements = (
|
|
24
|
+
table: Table,
|
|
25
|
+
existingColumns: ReadonlyMap<string, ExistingColumnInfo>
|
|
26
|
+
): readonly string[] => {
|
|
27
|
+
const fieldNames = new Set(table.fields.map((f) => f.name))
|
|
28
|
+
const needsCreatedAt = !fieldNames.has('created_at') && !existingColumns.has('created_at')
|
|
29
|
+
const needsUpdatedAt = !fieldNames.has('updated_at') && !existingColumns.has('updated_at')
|
|
30
|
+
const needsDeletedAt = !fieldNames.has('deleted_at') && !existingColumns.has('deleted_at')
|
|
31
|
+
|
|
32
|
+
return [
|
|
33
|
+
...(needsCreatedAt
|
|
34
|
+
? [`ALTER TABLE ${table.name} ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`]
|
|
35
|
+
: []),
|
|
36
|
+
...(needsUpdatedAt
|
|
37
|
+
? [`ALTER TABLE ${table.name} ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`]
|
|
38
|
+
: []),
|
|
39
|
+
...(needsDeletedAt ? [`ALTER TABLE ${table.name} ADD COLUMN deleted_at TIMESTAMPTZ`] : []),
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Validate destructive operations require explicit confirmation */
|
|
44
|
+
const validateDestructiveOps = (table: Table, columnsToDrop: readonly string[]): void => {
|
|
45
|
+
if (columnsToDrop.length > 0 && !table.allowDestructive) {
|
|
46
|
+
const droppedColumns = columnsToDrop.join(', ')
|
|
47
|
+
/* eslint-disable-next-line functional/no-throw-statements */
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Destructive operation detected: Dropping column(s) [${droppedColumns}] from table '${table.name}' requires confirmation. Set allowDestructive: true to proceed with data loss, or keep the field(s) in the schema to preserve data.`
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Generate ALTER TABLE statements for schema migrations */
|
|
55
|
+
export const generateAlterTableStatements = (
|
|
56
|
+
table: Table,
|
|
57
|
+
existingColumns: ReadonlyMap<string, ExistingColumnInfo>,
|
|
58
|
+
previousSchema?: { readonly tables: readonly object[] }
|
|
59
|
+
): readonly string[] => {
|
|
60
|
+
const primaryKeyFields =
|
|
61
|
+
table.primaryKey?.type === 'composite' ? (table.primaryKey.fields ?? []) : []
|
|
62
|
+
const hasIdField = table.fields.some((field) => field.name === 'id')
|
|
63
|
+
const shouldProtectIdColumn = !hasIdField && !(table.primaryKey && primaryKeyFields.length > 0)
|
|
64
|
+
|
|
65
|
+
if (needsIdColumnRecreation(existingColumns, shouldProtectIdColumn)) return []
|
|
66
|
+
|
|
67
|
+
const fieldRenames = detectFieldRenames(table.name, table.fields, previousSchema)
|
|
68
|
+
const renameStatements = Array.from(fieldRenames.entries()).map(
|
|
69
|
+
([oldName, newName]) => `ALTER TABLE ${table.name} RENAME COLUMN ${oldName} TO ${newName}`
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
const renamedOldNames = new Set(fieldRenames.keys())
|
|
73
|
+
const renamedNewNames = new Set(fieldRenames.values())
|
|
74
|
+
const schemaFieldsByName = new Map<string, Fields[number]>(
|
|
75
|
+
table.fields.map((field) => [field.name, field])
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
const columnsToAdd = findColumnsToAdd(table, existingColumns, renamedNewNames)
|
|
79
|
+
const columnsToDrop = findColumnsToDrop(
|
|
80
|
+
existingColumns,
|
|
81
|
+
schemaFieldsByName,
|
|
82
|
+
shouldProtectIdColumn,
|
|
83
|
+
renamedOldNames
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
validateDestructiveOps(table, columnsToDrop)
|
|
87
|
+
|
|
88
|
+
const { dropStatements, addStatements } = buildColumnStatements({
|
|
89
|
+
tableName: table.name,
|
|
90
|
+
columnsToDrop,
|
|
91
|
+
columnsToAdd,
|
|
92
|
+
primaryKeyFields,
|
|
93
|
+
allFields: table.fields,
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// ORDER: rename → drop → add → special fields → type changes → defaults → nullability
|
|
97
|
+
return [
|
|
98
|
+
...renameStatements,
|
|
99
|
+
...dropStatements,
|
|
100
|
+
...addStatements,
|
|
101
|
+
...generateSpecialFieldStatements(table, existingColumns),
|
|
102
|
+
...findTypeChanges(table, existingColumns, renamedNewNames),
|
|
103
|
+
...findDefaultValueChanges(table, existingColumns, renamedNewNames, previousSchema),
|
|
104
|
+
...findNullabilityChanges(table, existingColumns, renamedNewNames, primaryKeyFields),
|
|
105
|
+
]
|
|
106
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Table } from '@/domain/models/app/table'
|
|
9
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detect field renames by comparing field IDs between previous and current schema
|
|
13
|
+
* Returns a map of old field name to new field name for renamed fields
|
|
14
|
+
*/
|
|
15
|
+
export const detectFieldRenames = (
|
|
16
|
+
tableName: string,
|
|
17
|
+
currentFields: readonly Fields[number][],
|
|
18
|
+
previousSchema?: { readonly tables: readonly object[] }
|
|
19
|
+
): ReadonlyMap<string, string> => {
|
|
20
|
+
if (!previousSchema) return new Map()
|
|
21
|
+
|
|
22
|
+
// Find previous table definition
|
|
23
|
+
const previousTable = previousSchema.tables.find(
|
|
24
|
+
(t: object) => 'name' in t && t.name === tableName
|
|
25
|
+
) as { name: string; fields?: readonly { id?: number; name?: string }[] } | undefined
|
|
26
|
+
|
|
27
|
+
if (!previousTable || !previousTable.fields) return new Map()
|
|
28
|
+
|
|
29
|
+
// Build map of field ID to field name for both schemas
|
|
30
|
+
const previousFieldsById = new Map(
|
|
31
|
+
previousTable.fields
|
|
32
|
+
.filter((f) => f.id !== undefined && f.name !== undefined)
|
|
33
|
+
.map((f) => [f.id!, f.name!])
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const currentFieldsById = new Map(
|
|
37
|
+
currentFields.filter((f) => f.id !== undefined).map((f) => [f.id, f.name])
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
// Detect renames: same ID, different name (functional construction)
|
|
41
|
+
const renames = new Map<string, string>(
|
|
42
|
+
Array.from(currentFieldsById.entries())
|
|
43
|
+
.map(([fieldId, newName]) => {
|
|
44
|
+
const oldName = previousFieldsById.get(fieldId)
|
|
45
|
+
return oldName && oldName !== newName ? [oldName, newName] : undefined
|
|
46
|
+
})
|
|
47
|
+
.filter((entry): entry is [string, string] => entry !== undefined)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return renames
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Detect table renames by comparing table IDs between previous and current schema
|
|
55
|
+
* Returns a map of old table name to new table name for renamed tables
|
|
56
|
+
*/
|
|
57
|
+
export const detectTableRenames = (
|
|
58
|
+
currentTables: readonly Table[],
|
|
59
|
+
previousSchema?: { readonly tables: readonly object[] }
|
|
60
|
+
): ReadonlyMap<string, string> => {
|
|
61
|
+
if (!previousSchema) return new Map()
|
|
62
|
+
|
|
63
|
+
// Build map of table ID to table name for both schemas
|
|
64
|
+
const previousTablesById = new Map(
|
|
65
|
+
previousSchema.tables
|
|
66
|
+
.filter((t: object) => 'id' in t && 'name' in t && t.id !== undefined && t.name !== undefined)
|
|
67
|
+
.map((t: object) => [(t as { id: number }).id, (t as { name: string }).name])
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const currentTablesById = new Map(
|
|
71
|
+
currentTables
|
|
72
|
+
.filter((t): t is Table & { id: number } => t.id !== undefined)
|
|
73
|
+
.map((t) => [t.id, t.name])
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
// Detect renames: same ID, different name (functional construction)
|
|
77
|
+
const renames = new Map<string, string>(
|
|
78
|
+
Array.from(currentTablesById.entries())
|
|
79
|
+
.map(([tableId, newName]) => {
|
|
80
|
+
const oldName = previousTablesById.get(tableId)
|
|
81
|
+
return oldName && oldName !== newName ? [oldName, newName] : undefined
|
|
82
|
+
})
|
|
83
|
+
.filter((entry): entry is [string, string] => entry !== undefined)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return renames
|
|
87
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 {
|
|
10
|
+
getExistingTableNames,
|
|
11
|
+
executeSQLStatements,
|
|
12
|
+
type TransactionLike,
|
|
13
|
+
type SQLExecutionError,
|
|
14
|
+
} from '../sql/sql-execution'
|
|
15
|
+
import { PROTECTED_SYSTEM_TABLES } from './constants'
|
|
16
|
+
import { detectTableRenames } from './rename-detection'
|
|
17
|
+
import type { Table } from '@/domain/models/app/table'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Rename tables that have changed names (same table ID, different name)
|
|
21
|
+
* Uses ALTER TABLE RENAME TO to preserve data, indexes, and constraints
|
|
22
|
+
*/
|
|
23
|
+
export const renameTablesIfNeeded = (
|
|
24
|
+
tx: TransactionLike,
|
|
25
|
+
tables: readonly Table[],
|
|
26
|
+
previousSchema?: { readonly tables: readonly object[] }
|
|
27
|
+
): Effect.Effect<void, SQLExecutionError> =>
|
|
28
|
+
Effect.gen(function* () {
|
|
29
|
+
const tableRenames = detectTableRenames(tables, previousSchema)
|
|
30
|
+
|
|
31
|
+
if (tableRenames.size === 0) return
|
|
32
|
+
|
|
33
|
+
// Generate ALTER TABLE RENAME TO statements
|
|
34
|
+
const renameStatements = Array.from(tableRenames.entries()).map(
|
|
35
|
+
([oldName, newName]) => `ALTER TABLE ${oldName} RENAME TO ${newName}`
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
yield* executeSQLStatements(tx, renameStatements)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Drop tables that exist in database but are not defined in schema
|
|
43
|
+
*
|
|
44
|
+
* SECURITY NOTE: Table names are validated before reaching this function.
|
|
45
|
+
* This is SAFE because:
|
|
46
|
+
* 1. existingTableNames comes from pg_tables system catalog (trusted source)
|
|
47
|
+
* 2. schemaTableNames comes from validated Effect Schema objects
|
|
48
|
+
* 3. Only tables not in schema are dropped (explicit comparison)
|
|
49
|
+
* 4. Better Auth system tables are protected and never dropped
|
|
50
|
+
*/
|
|
51
|
+
export const dropObsoleteTables = (
|
|
52
|
+
tx: TransactionLike,
|
|
53
|
+
tables: readonly Table[]
|
|
54
|
+
): Effect.Effect<void, SQLExecutionError> =>
|
|
55
|
+
Effect.gen(function* () {
|
|
56
|
+
const existingTableNames = yield* getExistingTableNames(tx)
|
|
57
|
+
const schemaTableNames = new Set(tables.map((table) => table.name))
|
|
58
|
+
const tablesToDrop = existingTableNames.filter(
|
|
59
|
+
(tableName) => !schemaTableNames.has(tableName) && !PROTECTED_SYSTEM_TABLES.has(tableName)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
// Drop all obsolete tables sequentially
|
|
63
|
+
const dropStatements = tablesToDrop.map((tableName) => `DROP TABLE ${tableName} CASCADE`)
|
|
64
|
+
yield* executeSQLStatements(tx, dropStatements)
|
|
65
|
+
})
|
|
@@ -0,0 +1,98 @@
|
|
|
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 { mapFieldTypeToPostgres } from '../sql/sql-generators'
|
|
9
|
+
import type { Fields } from '@/domain/models/app/table/fields'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Normalize PostgreSQL data type for comparison
|
|
13
|
+
* Maps similar types to a canonical form (e.g., 'varchar' and 'character varying' both map to 'varchar')
|
|
14
|
+
* Strips length specifiers and precision for type matching
|
|
15
|
+
*/
|
|
16
|
+
export const normalizeDataType = (dataType: string): string => {
|
|
17
|
+
const normalized = dataType.toLowerCase().trim()
|
|
18
|
+
|
|
19
|
+
// Map 'character varying' to 'varchar' for easier comparison
|
|
20
|
+
if (normalized.startsWith('character varying')) return 'varchar'
|
|
21
|
+
if (normalized.startsWith('timestamp')) return 'timestamp'
|
|
22
|
+
if (normalized.startsWith('numeric') || normalized.startsWith('decimal')) return 'numeric'
|
|
23
|
+
|
|
24
|
+
// Map PostgreSQL ARRAY type to text[] for comparison with field type mappings
|
|
25
|
+
// information_schema.columns returns 'ARRAY' for all array columns
|
|
26
|
+
if (normalized === 'array') return 'text[]'
|
|
27
|
+
|
|
28
|
+
// Strip length specifiers for varchar, char, etc.
|
|
29
|
+
// varchar(255) → varchar, char(10) → char, numeric(10,2) → numeric
|
|
30
|
+
const withoutLength = normalized.replace(/\([^)]*\)/, '')
|
|
31
|
+
|
|
32
|
+
return withoutLength
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if column data type matches the expected type from schema
|
|
37
|
+
*/
|
|
38
|
+
export const doesColumnTypeMatch = (field: Fields[number], existingDataType: string): boolean => {
|
|
39
|
+
const expectedType = mapFieldTypeToPostgres(field)
|
|
40
|
+
const normalizedExpected = normalizeDataType(expectedType)
|
|
41
|
+
const normalizedExisting = normalizeDataType(existingDataType)
|
|
42
|
+
|
|
43
|
+
// For varchar/text types, check if both are string types
|
|
44
|
+
if (
|
|
45
|
+
(normalizedExpected === 'varchar' || normalizedExpected === 'text') &&
|
|
46
|
+
(normalizedExisting === 'varchar' || normalizedExisting === 'text')
|
|
47
|
+
) {
|
|
48
|
+
// Match if both are string types (varchar/text are interchangeable for our purposes)
|
|
49
|
+
return normalizedExpected === normalizedExisting
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// For other types, exact match required
|
|
53
|
+
return normalizedExpected === normalizedExisting
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generate ALTER COLUMN TYPE statement with USING clause if needed
|
|
58
|
+
* Handles type conversions that require explicit casting or transformation
|
|
59
|
+
*/
|
|
60
|
+
export const generateAlterColumnTypeStatement = (
|
|
61
|
+
tableName: string,
|
|
62
|
+
field: Fields[number],
|
|
63
|
+
existingDataType: string
|
|
64
|
+
): string => {
|
|
65
|
+
const targetType = mapFieldTypeToPostgres(field)
|
|
66
|
+
const normalizedTarget = normalizeDataType(targetType)
|
|
67
|
+
const normalizedExisting = normalizeDataType(existingDataType)
|
|
68
|
+
|
|
69
|
+
// Determine if USING clause is needed for type conversion
|
|
70
|
+
const usingClause = (() => {
|
|
71
|
+
// TEXT → VARCHAR requires LEFT() to truncate
|
|
72
|
+
if (normalizedExisting === 'text' && normalizedTarget === 'varchar') {
|
|
73
|
+
const lengthMatch = targetType.match(/VARCHAR\((\d+)\)/)
|
|
74
|
+
const length = lengthMatch ? lengthMatch[1] : '255'
|
|
75
|
+
return ` USING LEFT(${field.name}, ${length})`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// TEXT → INTEGER requires explicit cast
|
|
79
|
+
if (normalizedExisting === 'text' && normalizedTarget === 'integer') {
|
|
80
|
+
return ` USING ${field.name}::INTEGER`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// TEXT → TIMESTAMP requires explicit cast
|
|
84
|
+
if (normalizedExisting === 'text' && normalizedTarget === 'timestamp') {
|
|
85
|
+
return ` USING ${field.name}::TIMESTAMPTZ`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// INTEGER → NUMERIC conversion (automatic, no USING clause needed)
|
|
89
|
+
// PostgreSQL can implicitly convert INTEGER to NUMERIC
|
|
90
|
+
if (normalizedExisting === 'integer' && normalizedTarget === 'numeric') {
|
|
91
|
+
return ''
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return ''
|
|
95
|
+
})()
|
|
96
|
+
|
|
97
|
+
return `ALTER TABLE ${tableName} ALTER COLUMN ${field.name} TYPE ${targetType}${usingClause}`
|
|
98
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TransactionLike } from '../sql/sql-execution'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type definition for Bun SQL transaction
|
|
12
|
+
* Re-exported from sql-execution.ts for backward compatibility
|
|
13
|
+
*/
|
|
14
|
+
export type BunSQLTransaction = TransactionLike
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
* Schema Migration Helpers - Re-export Module
|
|
10
|
+
*
|
|
11
|
+
* This file re-exports all schema migration utilities from the split module structure.
|
|
12
|
+
* Maintained for backwards compatibility with existing imports.
|
|
13
|
+
*
|
|
14
|
+
* @see ./schema-migration/ for the actual implementations
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Type exports
|
|
18
|
+
export type { BunSQLTransaction, ExistingColumnInfo } from './schema-migration'
|
|
19
|
+
|
|
20
|
+
// All function exports
|
|
21
|
+
export {
|
|
22
|
+
// Constants
|
|
23
|
+
PROTECTED_SYSTEM_TABLES,
|
|
24
|
+
// Rename detection
|
|
25
|
+
detectFieldRenames,
|
|
26
|
+
detectTableRenames,
|
|
27
|
+
// Table operations
|
|
28
|
+
renameTablesIfNeeded,
|
|
29
|
+
dropObsoleteTables,
|
|
30
|
+
// Type utilities
|
|
31
|
+
normalizeDataType,
|
|
32
|
+
doesColumnTypeMatch,
|
|
33
|
+
generateAlterColumnTypeStatement,
|
|
34
|
+
// Column detection
|
|
35
|
+
needsIdColumnRecreation,
|
|
36
|
+
findColumnsToAdd,
|
|
37
|
+
findColumnsToDrop,
|
|
38
|
+
filterModifiableFields,
|
|
39
|
+
findTypeChanges,
|
|
40
|
+
generateNotNullValidationQuery,
|
|
41
|
+
generateBackfillQuery,
|
|
42
|
+
findNullabilityChanges,
|
|
43
|
+
findDefaultValueChanges,
|
|
44
|
+
buildColumnStatements,
|
|
45
|
+
// Migration statement generation
|
|
46
|
+
generateAlterTableStatements,
|
|
47
|
+
// Constraint synchronization
|
|
48
|
+
syncUniqueConstraints,
|
|
49
|
+
syncForeignKeyConstraints,
|
|
50
|
+
syncCheckConstraints,
|
|
51
|
+
// Index synchronization
|
|
52
|
+
syncIndexes,
|
|
53
|
+
} from './schema-migration'
|
|
@@ -0,0 +1,20 @@
|
|
|
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 domain error types for backward compatibility
|
|
10
|
+
*
|
|
11
|
+
* Error classes are now defined in @/domain/errors (the domain layer)
|
|
12
|
+
* where they belong. This file re-exports them so existing infrastructure
|
|
13
|
+
* imports continue to work without changes.
|
|
14
|
+
*/
|
|
15
|
+
export {
|
|
16
|
+
SessionContextError,
|
|
17
|
+
ForbiddenError,
|
|
18
|
+
UniqueConstraintViolationError,
|
|
19
|
+
ValidationError,
|
|
20
|
+
} from '@/domain/errors'
|