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,374 @@
|
|
|
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 fs from 'node:fs/promises'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import { Effect, Console } from 'effect'
|
|
11
|
+
import { StaticGenerationError } from '@/application/errors/static-generation-error'
|
|
12
|
+
import { copyDirectory } from '@/infrastructure/filesystem/copy-directory'
|
|
13
|
+
import {
|
|
14
|
+
formatHtmlWithPrettier,
|
|
15
|
+
generateClientHydrationScript,
|
|
16
|
+
generateRobotsContent,
|
|
17
|
+
generateSitemapContent,
|
|
18
|
+
type HreflangConfig,
|
|
19
|
+
} from './static-content-generators'
|
|
20
|
+
import {
|
|
21
|
+
injectHydrationScript,
|
|
22
|
+
isGitHubPagesUrl,
|
|
23
|
+
rewriteBasePathInHtml,
|
|
24
|
+
} from './static-url-rewriter'
|
|
25
|
+
import * as translationReplacer from './translation-replacer'
|
|
26
|
+
import type { GenerateStaticOptions } from './generate-static'
|
|
27
|
+
import type { App } from '@/domain/models/app'
|
|
28
|
+
|
|
29
|
+
// Re-export static modules for callers that previously used the import helpers
|
|
30
|
+
export { fs, path, translationReplacer }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Minimal filesystem interface for static generation
|
|
34
|
+
*
|
|
35
|
+
* Compatible with Node.js fs/promises, Bun's filesystem APIs, and test mocks.
|
|
36
|
+
* Only includes methods actually used by static generation functions.
|
|
37
|
+
*/
|
|
38
|
+
export interface FileSystemLike {
|
|
39
|
+
readonly mkdir: (
|
|
40
|
+
path: string,
|
|
41
|
+
options?: { readonly recursive?: boolean }
|
|
42
|
+
) => Promise<string | undefined>
|
|
43
|
+
readonly writeFile: (path: string, data: string, encoding?: BufferEncoding) => Promise<void>
|
|
44
|
+
readonly readFile: (path: string, encoding: BufferEncoding) => Promise<string>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Minimal path module interface for static generation
|
|
49
|
+
*
|
|
50
|
+
* Compatible with Node.js path module, Bun's path APIs, and test mocks.
|
|
51
|
+
*/
|
|
52
|
+
export interface PathModuleLike {
|
|
53
|
+
readonly join: (...paths: readonly string[]) => string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Write CSS file to output directory
|
|
58
|
+
*
|
|
59
|
+
* @param outputDir - Output directory path
|
|
60
|
+
* @param css - Compiled CSS content
|
|
61
|
+
* @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
62
|
+
*/
|
|
63
|
+
export function writeCssFile(outputDir: string, css: string, fs: FileSystemLike) {
|
|
64
|
+
return Effect.gen(function* () {
|
|
65
|
+
yield* Console.log('🎨 Writing compiled CSS...')
|
|
66
|
+
|
|
67
|
+
yield* Effect.tryPromise({
|
|
68
|
+
try: () => fs.mkdir(`${outputDir}/assets`, { recursive: true }),
|
|
69
|
+
catch: (error) =>
|
|
70
|
+
new StaticGenerationError({
|
|
71
|
+
message: `Failed to create assets directory`,
|
|
72
|
+
cause: error,
|
|
73
|
+
}),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
yield* Effect.tryPromise({
|
|
77
|
+
try: () => fs.writeFile(`${outputDir}/assets/output.css`, css, 'utf-8'),
|
|
78
|
+
catch: (error) =>
|
|
79
|
+
new StaticGenerationError({
|
|
80
|
+
message: 'Failed to write CSS file',
|
|
81
|
+
cause: error,
|
|
82
|
+
}),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return 'assets/output.css'
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate client-side hydration script if enabled
|
|
91
|
+
*
|
|
92
|
+
* @param outputDir - Output directory path
|
|
93
|
+
* @param enabled - Whether hydration is enabled
|
|
94
|
+
* @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
95
|
+
*/
|
|
96
|
+
export function generateHydrationFiles(outputDir: string, enabled: boolean, fs: FileSystemLike) {
|
|
97
|
+
return Effect.if(enabled, {
|
|
98
|
+
onTrue: () =>
|
|
99
|
+
Effect.gen(function* () {
|
|
100
|
+
yield* Console.log('💧 Generating client-side hydration script...')
|
|
101
|
+
const clientJS = generateClientHydrationScript()
|
|
102
|
+
yield* Effect.tryPromise({
|
|
103
|
+
try: () => fs.writeFile(`${outputDir}/assets/client.js`, clientJS, 'utf-8'),
|
|
104
|
+
catch: (error) =>
|
|
105
|
+
new StaticGenerationError({
|
|
106
|
+
message: 'Failed to write client.js',
|
|
107
|
+
cause: error,
|
|
108
|
+
}),
|
|
109
|
+
})
|
|
110
|
+
return ['assets/client.js'] as const
|
|
111
|
+
}),
|
|
112
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Copy static assets from public directory if provided
|
|
118
|
+
*/
|
|
119
|
+
export function copyPublicAssets(publicDir: string | undefined, outputDir: string) {
|
|
120
|
+
return Effect.if(publicDir !== undefined, {
|
|
121
|
+
onTrue: () =>
|
|
122
|
+
Effect.gen(function* () {
|
|
123
|
+
yield* Console.log(`📁 Copying assets from ${publicDir}...`)
|
|
124
|
+
return yield* copyDirectory(publicDir!, outputDir)
|
|
125
|
+
}),
|
|
126
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Format HTML files with Prettier
|
|
132
|
+
*
|
|
133
|
+
* @param generatedFiles - List of generated file paths
|
|
134
|
+
* @param outputDir - Output directory path
|
|
135
|
+
* @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
136
|
+
* @param path - Path module (Node.js path or Bun's equivalent)
|
|
137
|
+
*/
|
|
138
|
+
export function formatHtmlFiles(
|
|
139
|
+
generatedFiles: readonly string[],
|
|
140
|
+
outputDir: string,
|
|
141
|
+
fs: FileSystemLike,
|
|
142
|
+
path: PathModuleLike
|
|
143
|
+
) {
|
|
144
|
+
return Effect.gen(function* () {
|
|
145
|
+
yield* Console.log('📝 Formatting HTML files with Prettier...')
|
|
146
|
+
|
|
147
|
+
yield* Effect.forEach(
|
|
148
|
+
generatedFiles.filter((f) => f.endsWith('.html') && !f.endsWith('.js.html')),
|
|
149
|
+
(file) =>
|
|
150
|
+
Effect.gen(function* () {
|
|
151
|
+
const filePath = file.startsWith('/') ? file : path.join(outputDir, file)
|
|
152
|
+
const content = yield* Effect.tryPromise({
|
|
153
|
+
try: () => fs.readFile(filePath, 'utf-8') as Promise<string>,
|
|
154
|
+
catch: (error) =>
|
|
155
|
+
new StaticGenerationError({
|
|
156
|
+
message: `Failed to read HTML file for formatting: ${file}`,
|
|
157
|
+
cause: error,
|
|
158
|
+
}),
|
|
159
|
+
})
|
|
160
|
+
const formatted = yield* Effect.tryPromise({
|
|
161
|
+
try: () => formatHtmlWithPrettier(content),
|
|
162
|
+
catch: (error) =>
|
|
163
|
+
new StaticGenerationError({
|
|
164
|
+
message: `Failed to format HTML with Prettier: ${file}`,
|
|
165
|
+
cause: error,
|
|
166
|
+
}),
|
|
167
|
+
})
|
|
168
|
+
yield* Effect.tryPromise({
|
|
169
|
+
try: () => fs.writeFile(filePath, formatted, 'utf-8'),
|
|
170
|
+
catch: (error) =>
|
|
171
|
+
new StaticGenerationError({
|
|
172
|
+
message: `Failed to write formatted HTML file: ${file}`,
|
|
173
|
+
cause: error,
|
|
174
|
+
}),
|
|
175
|
+
})
|
|
176
|
+
}),
|
|
177
|
+
{ concurrency: 'unbounded' }
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Apply optimizations to generated HTML files
|
|
184
|
+
*
|
|
185
|
+
* @param config - Configuration object
|
|
186
|
+
* @param config.generatedFiles - List of generated file paths
|
|
187
|
+
* @param config.outputDir - Output directory path
|
|
188
|
+
* @param config.options - Static generation options
|
|
189
|
+
* @param config.fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
190
|
+
* @param config.path - Path module (Node.js path or Bun's equivalent)
|
|
191
|
+
*/
|
|
192
|
+
export function applyHtmlOptimizations(config: {
|
|
193
|
+
readonly generatedFiles: readonly string[]
|
|
194
|
+
readonly outputDir: string
|
|
195
|
+
readonly options: GenerateStaticOptions
|
|
196
|
+
readonly fs: FileSystemLike
|
|
197
|
+
readonly path: PathModuleLike
|
|
198
|
+
}) {
|
|
199
|
+
return Effect.gen(function* () {
|
|
200
|
+
// Step 1: Apply base path rewriting if basePath is configured
|
|
201
|
+
yield* Effect.if(config.options.basePath !== undefined && config.options.basePath !== '', {
|
|
202
|
+
onTrue: () =>
|
|
203
|
+
rewriteBasePathInHtml(
|
|
204
|
+
config.generatedFiles,
|
|
205
|
+
config.outputDir,
|
|
206
|
+
config.options.basePath!,
|
|
207
|
+
config.options.baseUrl,
|
|
208
|
+
config.fs
|
|
209
|
+
),
|
|
210
|
+
onFalse: () => Effect.void,
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
// Step 2: Inject hydration script into HTML if enabled
|
|
214
|
+
yield* Effect.if(config.options.hydration ?? false, {
|
|
215
|
+
onTrue: () =>
|
|
216
|
+
injectHydrationScript(
|
|
217
|
+
config.generatedFiles,
|
|
218
|
+
config.outputDir,
|
|
219
|
+
config.options.basePath || '',
|
|
220
|
+
config.fs,
|
|
221
|
+
config.path
|
|
222
|
+
),
|
|
223
|
+
onFalse: () => Effect.void,
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Build HreflangConfig from app languages when multi-language mode is active
|
|
230
|
+
*/
|
|
231
|
+
const buildHreflangConfig = (
|
|
232
|
+
app: App,
|
|
233
|
+
options: GenerateStaticOptions
|
|
234
|
+
): HreflangConfig | undefined => {
|
|
235
|
+
if (!app.languages || !options.languages) return undefined
|
|
236
|
+
return {
|
|
237
|
+
localeMap: Object.fromEntries(
|
|
238
|
+
app.languages.supported.map((lang) => [lang.code, lang.locale ?? lang.code])
|
|
239
|
+
),
|
|
240
|
+
defaultLanguage: options.defaultLanguage ?? app.languages.default,
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Generate sitemap.xml if enabled
|
|
246
|
+
*/
|
|
247
|
+
export function generateSitemapFile(
|
|
248
|
+
app: App,
|
|
249
|
+
outputDir: string,
|
|
250
|
+
options: GenerateStaticOptions,
|
|
251
|
+
fs: FileSystemLike
|
|
252
|
+
) {
|
|
253
|
+
return Effect.if(options.generateSitemap ?? false, {
|
|
254
|
+
onTrue: () =>
|
|
255
|
+
Effect.gen(function* () {
|
|
256
|
+
yield* Console.log('🗺️ Generating sitemap.xml...')
|
|
257
|
+
const pages = app.pages || []
|
|
258
|
+
const languages = app.languages && options.languages ? options.languages : undefined
|
|
259
|
+
const hreflangConfig = buildHreflangConfig(app, options)
|
|
260
|
+
|
|
261
|
+
const sitemap = generateSitemapContent(
|
|
262
|
+
pages,
|
|
263
|
+
options.baseUrl || 'https://example.com',
|
|
264
|
+
options.basePath || '',
|
|
265
|
+
languages || hreflangConfig ? { languages, hreflangConfig } : undefined
|
|
266
|
+
)
|
|
267
|
+
yield* Effect.tryPromise({
|
|
268
|
+
try: () => fs.writeFile(`${outputDir}/sitemap.xml`, sitemap, 'utf-8'),
|
|
269
|
+
catch: (error) =>
|
|
270
|
+
new StaticGenerationError({
|
|
271
|
+
message: 'Failed to write sitemap.xml',
|
|
272
|
+
cause: error,
|
|
273
|
+
}),
|
|
274
|
+
})
|
|
275
|
+
return ['sitemap.xml'] as const
|
|
276
|
+
}),
|
|
277
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Generate robots.txt if enabled
|
|
283
|
+
*
|
|
284
|
+
* @param app - Application configuration
|
|
285
|
+
* @param outputDir - Output directory path
|
|
286
|
+
* @param options - Static generation options
|
|
287
|
+
* @param fs - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
288
|
+
*/
|
|
289
|
+
export function generateRobotsFile(
|
|
290
|
+
app: App,
|
|
291
|
+
outputDir: string,
|
|
292
|
+
options: GenerateStaticOptions,
|
|
293
|
+
fs: FileSystemLike
|
|
294
|
+
) {
|
|
295
|
+
return Effect.if(options.generateRobotsTxt ?? false, {
|
|
296
|
+
onTrue: () =>
|
|
297
|
+
Effect.gen(function* () {
|
|
298
|
+
yield* Console.log('🤖 Generating robots.txt...')
|
|
299
|
+
const pages = app.pages || []
|
|
300
|
+
const basePath = options.basePath || ''
|
|
301
|
+
const robots = generateRobotsContent(
|
|
302
|
+
pages,
|
|
303
|
+
options.baseUrl || 'https://example.com',
|
|
304
|
+
basePath,
|
|
305
|
+
options.generateSitemap
|
|
306
|
+
)
|
|
307
|
+
yield* Effect.tryPromise({
|
|
308
|
+
try: () => fs.writeFile(`${outputDir}/robots.txt`, robots, 'utf-8'),
|
|
309
|
+
catch: (error) =>
|
|
310
|
+
new StaticGenerationError({
|
|
311
|
+
message: 'Failed to write robots.txt',
|
|
312
|
+
cause: error,
|
|
313
|
+
}),
|
|
314
|
+
})
|
|
315
|
+
return ['robots.txt'] as const
|
|
316
|
+
}),
|
|
317
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Generate GitHub Pages specific files
|
|
323
|
+
*/
|
|
324
|
+
export function generateGitHubPagesFiles(
|
|
325
|
+
outputDir: string,
|
|
326
|
+
options: GenerateStaticOptions,
|
|
327
|
+
fs: FileSystemLike
|
|
328
|
+
) {
|
|
329
|
+
return Effect.gen(function* () {
|
|
330
|
+
// Create .nojekyll file
|
|
331
|
+
const nojekyllFiles = yield* Effect.if(options.deployment === 'github-pages', {
|
|
332
|
+
onTrue: () =>
|
|
333
|
+
Effect.gen(function* () {
|
|
334
|
+
yield* Console.log('📄 Creating .nojekyll file for GitHub Pages...')
|
|
335
|
+
yield* Effect.tryPromise({
|
|
336
|
+
try: () => fs.writeFile(`${outputDir}/.nojekyll`, '', 'utf-8'),
|
|
337
|
+
catch: (error) =>
|
|
338
|
+
new StaticGenerationError({
|
|
339
|
+
message: 'Failed to write .nojekyll',
|
|
340
|
+
cause: error,
|
|
341
|
+
}),
|
|
342
|
+
})
|
|
343
|
+
return ['.nojekyll'] as const
|
|
344
|
+
}),
|
|
345
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
// Generate CNAME file for custom domains
|
|
349
|
+
const cnameFiles = yield* Effect.if(
|
|
350
|
+
options.deployment === 'github-pages' &&
|
|
351
|
+
options.baseUrl !== undefined &&
|
|
352
|
+
!isGitHubPagesUrl(options.baseUrl),
|
|
353
|
+
{
|
|
354
|
+
onTrue: () =>
|
|
355
|
+
Effect.gen(function* () {
|
|
356
|
+
const domain = new URL(options.baseUrl!).hostname
|
|
357
|
+
yield* Console.log(`📄 Creating CNAME file for custom domain: ${domain}...`)
|
|
358
|
+
yield* Effect.tryPromise({
|
|
359
|
+
try: () => fs.writeFile(`${outputDir}/CNAME`, domain, 'utf-8'),
|
|
360
|
+
catch: (error) =>
|
|
361
|
+
new StaticGenerationError({
|
|
362
|
+
message: 'Failed to write CNAME',
|
|
363
|
+
cause: error,
|
|
364
|
+
}),
|
|
365
|
+
})
|
|
366
|
+
return ['CNAME'] as const
|
|
367
|
+
}),
|
|
368
|
+
onFalse: () => Effect.succeed([] as readonly string[]),
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
return [...nojekyllFiles, ...cnameFiles] as readonly string[]
|
|
373
|
+
})
|
|
374
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
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, Console, Schema, type Context } from 'effect'
|
|
9
|
+
import { AppValidationError } from '@/application/errors/app-validation-error'
|
|
10
|
+
import {
|
|
11
|
+
CSSCompiler as CSSCompilerService,
|
|
12
|
+
type CSSCompilationError,
|
|
13
|
+
} from '@/application/ports/services/css-compiler'
|
|
14
|
+
import { PageRenderer as PageRendererService } from '@/application/ports/services/page-renderer'
|
|
15
|
+
import { ServerFactory as ServerFactoryService } from '@/application/ports/services/server-factory'
|
|
16
|
+
import {
|
|
17
|
+
StaticSiteGenerator as StaticSiteGeneratorService,
|
|
18
|
+
type SSGGenerationError,
|
|
19
|
+
} from '@/application/ports/services/static-site-generator'
|
|
20
|
+
import { AppSchema } from '@/domain/models/app'
|
|
21
|
+
import {
|
|
22
|
+
fs,
|
|
23
|
+
path,
|
|
24
|
+
translationReplacer,
|
|
25
|
+
writeCssFile,
|
|
26
|
+
generateHydrationFiles,
|
|
27
|
+
copyPublicAssets,
|
|
28
|
+
formatHtmlFiles,
|
|
29
|
+
applyHtmlOptimizations,
|
|
30
|
+
generateSitemapFile,
|
|
31
|
+
generateRobotsFile,
|
|
32
|
+
generateGitHubPagesFiles,
|
|
33
|
+
type FileSystemLike,
|
|
34
|
+
} from './generate-static-helpers'
|
|
35
|
+
import {
|
|
36
|
+
generateMultiLanguageFiles,
|
|
37
|
+
generateSingleLanguageFiles,
|
|
38
|
+
} from './static-language-generators'
|
|
39
|
+
import type { StaticGenerationError } from '@/application/errors/static-generation-error'
|
|
40
|
+
import type { App } from '@/domain/models/app'
|
|
41
|
+
import type { AuthConfigRequiredForUserFields } from '@/infrastructure/errors/auth-config-required-error'
|
|
42
|
+
import type { SchemaInitializationError } from '@/infrastructure/errors/schema-initialization-error'
|
|
43
|
+
import type { ServerCreationError } from '@/infrastructure/errors/server-creation-error'
|
|
44
|
+
import type { FileCopyError } from '@/infrastructure/filesystem/copy-directory'
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Options for static site generation
|
|
48
|
+
*/
|
|
49
|
+
export interface GenerateStaticOptions {
|
|
50
|
+
readonly outputDir?: string // default: './static'
|
|
51
|
+
readonly baseUrl?: string
|
|
52
|
+
readonly basePath?: string
|
|
53
|
+
readonly deployment?: 'github-pages' | 'generic'
|
|
54
|
+
readonly languages?: readonly string[]
|
|
55
|
+
readonly defaultLanguage?: string
|
|
56
|
+
readonly generateSitemap?: boolean
|
|
57
|
+
readonly generateRobotsTxt?: boolean
|
|
58
|
+
readonly hydration?: boolean
|
|
59
|
+
readonly generateManifest?: boolean
|
|
60
|
+
readonly bundleOptimization?: 'split' | 'none'
|
|
61
|
+
readonly publicDir?: string // Directory containing static assets to copy
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Result of static site generation
|
|
66
|
+
*/
|
|
67
|
+
export interface GenerateStaticResult {
|
|
68
|
+
readonly outputDir: string
|
|
69
|
+
readonly files: readonly string[]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Validate app schema handling multi-language apps
|
|
74
|
+
*/
|
|
75
|
+
function validateAppSchema(app: unknown): Effect.Effect<App, AppValidationError, never> {
|
|
76
|
+
const rawApp = app as Record<string, unknown>
|
|
77
|
+
const hasLanguages = rawApp.languages !== undefined
|
|
78
|
+
|
|
79
|
+
return hasLanguages && rawApp.pages
|
|
80
|
+
? Effect.gen(function* () {
|
|
81
|
+
const appWithoutPages = { ...rawApp, pages: undefined }
|
|
82
|
+
const baseApp = yield* Effect.try({
|
|
83
|
+
try: (): App => Schema.decodeUnknownSync(AppSchema)(appWithoutPages),
|
|
84
|
+
catch: (error) => new AppValidationError(error),
|
|
85
|
+
})
|
|
86
|
+
return { ...baseApp, pages: rawApp.pages as App['pages'] }
|
|
87
|
+
})
|
|
88
|
+
: Effect.gen(function* () {
|
|
89
|
+
yield* Console.log('🔍 Validating app schema...')
|
|
90
|
+
return yield* Effect.try({
|
|
91
|
+
try: (): App => Schema.decodeUnknownSync(AppSchema)(app),
|
|
92
|
+
catch: (error) => new AppValidationError(error),
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get required services from Effect context
|
|
99
|
+
*/
|
|
100
|
+
function getServicesFromContext() {
|
|
101
|
+
return Effect.gen(function* () {
|
|
102
|
+
return {
|
|
103
|
+
serverFactory: yield* ServerFactoryService,
|
|
104
|
+
pageRenderer: yield* PageRendererService,
|
|
105
|
+
cssCompiler: yield* CSSCompilerService,
|
|
106
|
+
staticSiteGenerator: yield* StaticSiteGeneratorService,
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Generate HTML files for single or multi-language apps
|
|
113
|
+
*/
|
|
114
|
+
function generateHtmlFiles(
|
|
115
|
+
app: App,
|
|
116
|
+
outputDir: string,
|
|
117
|
+
replaceAppTokens: (app: App, lang: string) => App,
|
|
118
|
+
serverFactory: Context.Tag.Service<ServerFactoryService>,
|
|
119
|
+
pageRenderer: Context.Tag.Service<PageRendererService>,
|
|
120
|
+
staticSiteGenerator: Context.Tag.Service<StaticSiteGeneratorService>
|
|
121
|
+
) {
|
|
122
|
+
return app.languages && app.pages
|
|
123
|
+
? generateMultiLanguageFiles(
|
|
124
|
+
app,
|
|
125
|
+
outputDir,
|
|
126
|
+
replaceAppTokens,
|
|
127
|
+
serverFactory,
|
|
128
|
+
pageRenderer,
|
|
129
|
+
staticSiteGenerator
|
|
130
|
+
)
|
|
131
|
+
: generateSingleLanguageFiles(app, outputDir, serverFactory, pageRenderer, staticSiteGenerator)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Generate and write CSS file
|
|
136
|
+
*/
|
|
137
|
+
function generateCssFile(
|
|
138
|
+
outputDir: string,
|
|
139
|
+
app: App,
|
|
140
|
+
cssCompiler: Context.Tag.Service<CSSCompilerService>,
|
|
141
|
+
fs: FileSystemLike
|
|
142
|
+
) {
|
|
143
|
+
return Effect.gen(function* () {
|
|
144
|
+
yield* Console.log('🎨 Getting compiled CSS...')
|
|
145
|
+
const { css } = yield* cssCompiler.compile(app)
|
|
146
|
+
return yield* writeCssFile(outputDir, css, fs)
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Optimize HTML files with formatting and transformations
|
|
152
|
+
*
|
|
153
|
+
* @param generatedFiles - List of generated file paths
|
|
154
|
+
* @param outputDir - Output directory path
|
|
155
|
+
* @param options - Static generation options
|
|
156
|
+
* @param fsModule - Filesystem module (Node.js fs/promises or Bun's equivalent)
|
|
157
|
+
*/
|
|
158
|
+
function optimizeHtmlFiles(
|
|
159
|
+
generatedFiles: readonly string[],
|
|
160
|
+
outputDir: string,
|
|
161
|
+
options: GenerateStaticOptions,
|
|
162
|
+
fsModule: FileSystemLike
|
|
163
|
+
) {
|
|
164
|
+
return Effect.gen(function* () {
|
|
165
|
+
yield* formatHtmlFiles(generatedFiles, outputDir, fsModule, path)
|
|
166
|
+
yield* applyHtmlOptimizations({
|
|
167
|
+
generatedFiles,
|
|
168
|
+
outputDir,
|
|
169
|
+
options,
|
|
170
|
+
fs: fsModule,
|
|
171
|
+
path,
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Generate all supporting files (sitemap, robots.txt, GitHub Pages files)
|
|
178
|
+
*/
|
|
179
|
+
function generateSupportingFiles(
|
|
180
|
+
app: App,
|
|
181
|
+
outputDir: string,
|
|
182
|
+
options: GenerateStaticOptions,
|
|
183
|
+
fs: FileSystemLike
|
|
184
|
+
) {
|
|
185
|
+
return Effect.gen(function* () {
|
|
186
|
+
const sitemapFiles = yield* generateSitemapFile(app, outputDir, options, fs)
|
|
187
|
+
const robotsFiles = yield* generateRobotsFile(app, outputDir, options, fs)
|
|
188
|
+
const githubFiles = yield* generateGitHubPagesFiles(outputDir, options, fs)
|
|
189
|
+
|
|
190
|
+
return [...sitemapFiles, ...robotsFiles, ...githubFiles] as readonly string[]
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Generate static site from app configuration
|
|
196
|
+
*
|
|
197
|
+
* This use case:
|
|
198
|
+
* 1. Validates the app schema
|
|
199
|
+
* 2. Creates a Hono app instance
|
|
200
|
+
* 3. Generates static HTML files
|
|
201
|
+
* 4. Creates supporting files (sitemap, robots.txt, etc.)
|
|
202
|
+
*
|
|
203
|
+
* @param app - The app configuration (unknown type, will be validated)
|
|
204
|
+
* @param options - Static generation options
|
|
205
|
+
* @returns Effect with output directory and generated files
|
|
206
|
+
*/
|
|
207
|
+
export const generateStatic = (
|
|
208
|
+
app: unknown,
|
|
209
|
+
options: GenerateStaticOptions = {}
|
|
210
|
+
): Effect.Effect<
|
|
211
|
+
GenerateStaticResult,
|
|
212
|
+
| AppValidationError
|
|
213
|
+
| StaticGenerationError
|
|
214
|
+
| SSGGenerationError
|
|
215
|
+
| CSSCompilationError
|
|
216
|
+
| ServerCreationError
|
|
217
|
+
| FileCopyError
|
|
218
|
+
| AuthConfigRequiredForUserFields
|
|
219
|
+
| SchemaInitializationError
|
|
220
|
+
| Error,
|
|
221
|
+
ServerFactoryService | PageRendererService | CSSCompilerService | StaticSiteGeneratorService
|
|
222
|
+
> => {
|
|
223
|
+
const program = Effect.gen(function* () {
|
|
224
|
+
// Step 1: Dependencies are statically imported
|
|
225
|
+
const { replaceAppTokens } = translationReplacer
|
|
226
|
+
|
|
227
|
+
// Step 2: Validate app schema
|
|
228
|
+
const validatedApp = yield* validateAppSchema(app)
|
|
229
|
+
|
|
230
|
+
// Step 3: Get services and initialize
|
|
231
|
+
const services = yield* getServicesFromContext()
|
|
232
|
+
const outputDir = options.outputDir || './static'
|
|
233
|
+
|
|
234
|
+
// Step 4: Generate HTML files
|
|
235
|
+
const htmlFiles = yield* generateHtmlFiles(
|
|
236
|
+
validatedApp,
|
|
237
|
+
outputDir,
|
|
238
|
+
replaceAppTokens,
|
|
239
|
+
services.serverFactory,
|
|
240
|
+
services.pageRenderer,
|
|
241
|
+
services.staticSiteGenerator
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
// Step 5: Generate CSS and assets
|
|
245
|
+
const cssFile = yield* generateCssFile(outputDir, validatedApp, services.cssCompiler, fs)
|
|
246
|
+
const hydrationFiles = yield* generateHydrationFiles(outputDir, options.hydration ?? false, fs)
|
|
247
|
+
const assetFiles = yield* copyPublicAssets(options.publicDir, outputDir)
|
|
248
|
+
|
|
249
|
+
// Collect all generated files
|
|
250
|
+
const generatedFiles = [
|
|
251
|
+
...htmlFiles,
|
|
252
|
+
cssFile,
|
|
253
|
+
...hydrationFiles,
|
|
254
|
+
...assetFiles,
|
|
255
|
+
] as readonly string[]
|
|
256
|
+
|
|
257
|
+
// Step 6: Optimize HTML files
|
|
258
|
+
yield* optimizeHtmlFiles(generatedFiles, outputDir, options, fs)
|
|
259
|
+
|
|
260
|
+
// Step 7: Generate supporting files
|
|
261
|
+
const supportingFiles = yield* generateSupportingFiles(validatedApp, outputDir, options, fs)
|
|
262
|
+
|
|
263
|
+
// Combine all files immutably
|
|
264
|
+
const allFiles = [...generatedFiles, ...supportingFiles] as readonly string[]
|
|
265
|
+
|
|
266
|
+
yield* Console.log(`✅ Generated ${allFiles.length} files to ${outputDir}`)
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
outputDir,
|
|
270
|
+
files: allFiles,
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
return program as Effect.Effect<
|
|
275
|
+
GenerateStaticResult,
|
|
276
|
+
| AppValidationError
|
|
277
|
+
| StaticGenerationError
|
|
278
|
+
| SSGGenerationError
|
|
279
|
+
| CSSCompilationError
|
|
280
|
+
| ServerCreationError
|
|
281
|
+
| FileCopyError
|
|
282
|
+
| AuthConfigRequiredForUserFields
|
|
283
|
+
| SchemaInitializationError
|
|
284
|
+
| Error,
|
|
285
|
+
ServerFactoryService | PageRendererService | CSSCompilerService | StaticSiteGeneratorService
|
|
286
|
+
>
|
|
287
|
+
}
|