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,67 @@
|
|
|
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, Runtime } from 'effect'
|
|
9
|
+
import type { ServerInstance } from '@/application/models/server'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets up graceful server shutdown on SIGINT (Ctrl+C)
|
|
13
|
+
*
|
|
14
|
+
* This utility registers a SIGINT handler that gracefully stops the server
|
|
15
|
+
* when the user presses Ctrl+C. The server's stop Effect is executed before
|
|
16
|
+
* process termination.
|
|
17
|
+
*
|
|
18
|
+
* @param server - Server instance with stop capability
|
|
19
|
+
* @returns Effect that never completes (keeps process alive until SIGINT)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { Effect } from 'effect'
|
|
24
|
+
* import { start } from '@/index'
|
|
25
|
+
* import { withGracefulShutdown } from '@/utils/server-lifecycle'
|
|
26
|
+
*
|
|
27
|
+
* const program = Effect.gen(function* () {
|
|
28
|
+
* const server = yield* start(myApp)
|
|
29
|
+
* yield* withGracefulShutdown(server)
|
|
30
|
+
* })
|
|
31
|
+
*
|
|
32
|
+
* Effect.runPromise(program)
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const withGracefulShutdown = (server: ServerInstance): Effect.Effect<never> =>
|
|
36
|
+
Effect.gen(function* () {
|
|
37
|
+
// Extract runtime to use in signal handler (avoids Effect.runPromise inside Effect)
|
|
38
|
+
const runtime = yield* Effect.runtime<never>()
|
|
39
|
+
|
|
40
|
+
// Setup SIGINT handler for graceful shutdown
|
|
41
|
+
// Wrap process.on() side effect in Effect.sync for testability
|
|
42
|
+
yield* Effect.sync(() =>
|
|
43
|
+
process.on('SIGINT', () => {
|
|
44
|
+
Runtime.runPromise(runtime)(
|
|
45
|
+
Effect.gen(function* () {
|
|
46
|
+
yield* Console.log('\nReceived SIGINT, stopping server...')
|
|
47
|
+
yield* server.stop
|
|
48
|
+
// Terminate process - imperative statement required for graceful shutdown
|
|
49
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
50
|
+
process.exit(0)
|
|
51
|
+
})
|
|
52
|
+
).catch((error) => {
|
|
53
|
+
Runtime.runSync(runtime)(Console.error('Failed to stop server:', error))
|
|
54
|
+
// Terminate process - imperative statement required for error handling
|
|
55
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
56
|
+
process.exit(1)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Log shutdown instructions
|
|
62
|
+
yield* Console.log('')
|
|
63
|
+
yield* Console.log('Press Ctrl+C to stop the server')
|
|
64
|
+
|
|
65
|
+
// Keep the process alive indefinitely
|
|
66
|
+
return yield* Effect.never
|
|
67
|
+
})
|
|
@@ -0,0 +1,310 @@
|
|
|
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, Data } from 'effect'
|
|
9
|
+
import { healthResponseSchema, type HealthResponse } from '@/domain/models/api/health'
|
|
10
|
+
import { createAuthInstance } from '@/infrastructure/auth/better-auth/auth'
|
|
11
|
+
import { authMiddleware, requireAuth } from '@/presentation/api/middleware/auth'
|
|
12
|
+
import {
|
|
13
|
+
chainTableRoutes,
|
|
14
|
+
chainAuthRoutes,
|
|
15
|
+
chainActivityRoutes,
|
|
16
|
+
chainAnalyticsRoutes,
|
|
17
|
+
} from '@/presentation/api/routes'
|
|
18
|
+
import {
|
|
19
|
+
extractClientIp,
|
|
20
|
+
isTablesRateLimitExceeded,
|
|
21
|
+
recordTablesRateLimitRequest,
|
|
22
|
+
getTablesRateLimitRetryAfter,
|
|
23
|
+
isActivityRateLimitExceeded,
|
|
24
|
+
recordActivityRateLimitRequest,
|
|
25
|
+
getActivityRateLimitRetryAfter,
|
|
26
|
+
} from './auth-route-utils'
|
|
27
|
+
import type { App } from '@/domain/models/app'
|
|
28
|
+
import type { Hono } from 'hono'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Error when health response validation fails
|
|
32
|
+
*/
|
|
33
|
+
class HealthResponseValidationError extends Data.TaggedError('HealthResponseValidationError')<{
|
|
34
|
+
readonly message: string
|
|
35
|
+
readonly cause?: unknown
|
|
36
|
+
}> {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Apply rate limiting middleware for table API endpoints
|
|
40
|
+
* Returns a Hono app with rate limiting middleware applied
|
|
41
|
+
*/
|
|
42
|
+
// eslint-disable-next-line functional/prefer-immutable-types -- Hono types are mutable by library design
|
|
43
|
+
const applyTablesRateLimitMiddleware = (honoApp: Hono): Hono => {
|
|
44
|
+
return honoApp
|
|
45
|
+
.use('/api/tables', async (c, next) => {
|
|
46
|
+
const ip = extractClientIp(c.req.header('x-forwarded-for'))
|
|
47
|
+
const { method } = c.req
|
|
48
|
+
const path = '/api/tables'
|
|
49
|
+
|
|
50
|
+
if (isTablesRateLimitExceeded(method, path, ip)) {
|
|
51
|
+
const retryAfter = getTablesRateLimitRetryAfter(method, path, ip)
|
|
52
|
+
return c.json(
|
|
53
|
+
{
|
|
54
|
+
success: false,
|
|
55
|
+
message: 'Too many requests. Please try again later.',
|
|
56
|
+
code: 'RATE_LIMITED',
|
|
57
|
+
},
|
|
58
|
+
429,
|
|
59
|
+
{ 'Retry-After': retryAfter.toString() }
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
recordTablesRateLimitRequest(method, path, ip) // eslint-disable-line functional/no-expression-statements -- Rate limiting state update
|
|
64
|
+
|
|
65
|
+
// eslint-disable-next-line functional/no-expression-statements -- Hono middleware requires calling next()
|
|
66
|
+
await next()
|
|
67
|
+
})
|
|
68
|
+
.use('/api/tables/*', async (c, next) => {
|
|
69
|
+
const ip = extractClientIp(c.req.header('x-forwarded-for'))
|
|
70
|
+
const { method } = c.req
|
|
71
|
+
const { path } = c.req
|
|
72
|
+
|
|
73
|
+
if (isTablesRateLimitExceeded(method, path, ip)) {
|
|
74
|
+
const retryAfter = getTablesRateLimitRetryAfter(method, path, ip)
|
|
75
|
+
return c.json(
|
|
76
|
+
{
|
|
77
|
+
success: false,
|
|
78
|
+
message: 'Too many requests. Please try again later.',
|
|
79
|
+
code: 'RATE_LIMITED',
|
|
80
|
+
},
|
|
81
|
+
429,
|
|
82
|
+
{ 'Retry-After': retryAfter.toString() }
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
recordTablesRateLimitRequest(method, path, ip) // eslint-disable-line functional/no-expression-statements -- Rate limiting state update
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line functional/no-expression-statements -- Hono middleware requires calling next()
|
|
89
|
+
await next()
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Apply rate limiting middleware for activity API endpoints
|
|
95
|
+
* Returns a Hono app with rate limiting middleware applied
|
|
96
|
+
*/
|
|
97
|
+
// eslint-disable-next-line functional/prefer-immutable-types -- Hono types are mutable by library design
|
|
98
|
+
const applyActivityRateLimitMiddleware = (honoApp: Hono): Hono => {
|
|
99
|
+
return honoApp
|
|
100
|
+
.use('/api/activity', async (c, next) => {
|
|
101
|
+
const ip = extractClientIp(c.req.header('x-forwarded-for'))
|
|
102
|
+
const { method } = c.req
|
|
103
|
+
const path = '/api/activity'
|
|
104
|
+
|
|
105
|
+
if (isActivityRateLimitExceeded(method, path, ip)) {
|
|
106
|
+
const retryAfter = getActivityRateLimitRetryAfter(method, path, ip)
|
|
107
|
+
return c.json(
|
|
108
|
+
{
|
|
109
|
+
success: false,
|
|
110
|
+
message: 'Too many requests. Please try again later.',
|
|
111
|
+
code: 'RATE_LIMITED',
|
|
112
|
+
},
|
|
113
|
+
429,
|
|
114
|
+
{ 'Retry-After': retryAfter.toString() }
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
recordActivityRateLimitRequest(method, path, ip) // eslint-disable-line functional/no-expression-statements -- Rate limiting state update
|
|
119
|
+
|
|
120
|
+
// eslint-disable-next-line functional/no-expression-statements -- Hono middleware requires calling next()
|
|
121
|
+
await next()
|
|
122
|
+
})
|
|
123
|
+
.use('/api/activity/*', async (c, next) => {
|
|
124
|
+
const ip = extractClientIp(c.req.header('x-forwarded-for'))
|
|
125
|
+
const { method } = c.req
|
|
126
|
+
const { path } = c.req
|
|
127
|
+
|
|
128
|
+
if (isActivityRateLimitExceeded(method, path, ip)) {
|
|
129
|
+
const retryAfter = getActivityRateLimitRetryAfter(method, path, ip)
|
|
130
|
+
return c.json(
|
|
131
|
+
{
|
|
132
|
+
success: false,
|
|
133
|
+
message: 'Too many requests. Please try again later.',
|
|
134
|
+
code: 'RATE_LIMITED',
|
|
135
|
+
},
|
|
136
|
+
429,
|
|
137
|
+
{ 'Retry-After': retryAfter.toString() }
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
recordActivityRateLimitRequest(method, path, ip) // eslint-disable-line functional/no-expression-statements -- Rate limiting state update
|
|
142
|
+
|
|
143
|
+
// eslint-disable-next-line functional/no-expression-statements -- Hono middleware requires calling next()
|
|
144
|
+
await next()
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create API routes using method chaining pattern
|
|
150
|
+
*
|
|
151
|
+
* Located in Infrastructure layer because this is route composition/wiring
|
|
152
|
+
* (infrastructure concern), not route handler logic (presentation concern).
|
|
153
|
+
*
|
|
154
|
+
* **Why Chaining?**
|
|
155
|
+
* Hono RPC requires method chaining (not .route() mounting) for proper type inference.
|
|
156
|
+
* This allows the RPC client to extract route types automatically.
|
|
157
|
+
*
|
|
158
|
+
* **Pattern**:
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const app = new Hono()
|
|
161
|
+
* .get('/api/health', handler)
|
|
162
|
+
* .get('/api/users/:id', handler)
|
|
163
|
+
* .post('/api/users', handler)
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* **Why Not .route()?**
|
|
167
|
+
* ```typescript
|
|
168
|
+
* // ❌ This breaks RPC type inference
|
|
169
|
+
* app.route('/api', subApp)
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* See: https://hono.dev/docs/guides/best-practices#building-a-larger-application
|
|
173
|
+
*
|
|
174
|
+
* @param app - Validated application configuration from AppSchema
|
|
175
|
+
* @param honoApp - Hono instance to chain routes onto
|
|
176
|
+
* @returns Hono app with all API routes chained
|
|
177
|
+
*/
|
|
178
|
+
// eslint-disable-next-line functional/prefer-immutable-types, max-lines-per-function -- Hono types are mutable by library design; function composes middleware chain and requires activity auth setup
|
|
179
|
+
export const createApiRoutes = <T extends Hono>(app: App, honoApp: T) => {
|
|
180
|
+
// Create Better Auth instance for middleware
|
|
181
|
+
const auth = createAuthInstance(app.auth)
|
|
182
|
+
|
|
183
|
+
// Create health check endpoint
|
|
184
|
+
const honoWithHealth = honoApp.get('/api/health', async (c) => {
|
|
185
|
+
// Use Effect.gen for functional composition
|
|
186
|
+
const program = Effect.gen(function* () {
|
|
187
|
+
// Build health response (explicitly typed for Zod validation)
|
|
188
|
+
// eslint-disable-next-line functional/prefer-immutable-types -- Required for Zod schema validation
|
|
189
|
+
const response: HealthResponse = {
|
|
190
|
+
status: 'ok',
|
|
191
|
+
timestamp: new Date().toISOString(),
|
|
192
|
+
app: {
|
|
193
|
+
name: app.name,
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Validate response against schema (ensures type safety)
|
|
198
|
+
const validated = yield* Effect.try({
|
|
199
|
+
try: () => healthResponseSchema.parse(response),
|
|
200
|
+
catch: (error) =>
|
|
201
|
+
new HealthResponseValidationError({
|
|
202
|
+
message: `Health response validation failed: ${error}`,
|
|
203
|
+
cause: error,
|
|
204
|
+
}),
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
return validated
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
// Run Effect program and return result
|
|
212
|
+
const data = await Effect.runPromise(program)
|
|
213
|
+
return c.json(data, 200)
|
|
214
|
+
} catch {
|
|
215
|
+
// Handle errors gracefully
|
|
216
|
+
return c.json(
|
|
217
|
+
{
|
|
218
|
+
error: 'Internal server error',
|
|
219
|
+
code: 'HEALTH_CHECK_FAILED',
|
|
220
|
+
},
|
|
221
|
+
500
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
// Apply rate limiting middleware BEFORE auth middleware
|
|
227
|
+
// This prevents auth bypass by rate limiting all requests first
|
|
228
|
+
// Middleware order: rate limiting → authMiddleware (extracts session) → requireAuth (enforces auth)
|
|
229
|
+
const honoWithTablesRateLimit = applyTablesRateLimitMiddleware(honoWithHealth)
|
|
230
|
+
const honoWithActivityRateLimit = applyActivityRateLimitMiddleware(honoWithTablesRateLimit)
|
|
231
|
+
|
|
232
|
+
// Apply auth middleware to protected routes
|
|
233
|
+
// This extracts session from Better Auth and attaches to context
|
|
234
|
+
// Activity endpoints ALWAYS require authentication (even when app.auth is not configured)
|
|
235
|
+
// Table endpoints only require authentication if auth is configured
|
|
236
|
+
// Analytics query endpoints require authentication; collect endpoint is public
|
|
237
|
+
const honoWithAuth = app.auth
|
|
238
|
+
? honoWithActivityRateLimit
|
|
239
|
+
.use('/api/tables', authMiddleware(auth))
|
|
240
|
+
.use('/api/tables', requireAuth())
|
|
241
|
+
.use('/api/tables/*', authMiddleware(auth))
|
|
242
|
+
.use('/api/tables/*', requireAuth())
|
|
243
|
+
.use('/api/activity', authMiddleware(auth))
|
|
244
|
+
.use('/api/activity', requireAuth())
|
|
245
|
+
.use('/api/activity/*', authMiddleware(auth))
|
|
246
|
+
.use('/api/activity/*', requireAuth())
|
|
247
|
+
.use('/api/analytics/overview', authMiddleware(auth))
|
|
248
|
+
.use('/api/analytics/overview', requireAuth())
|
|
249
|
+
.use('/api/analytics/pages', authMiddleware(auth))
|
|
250
|
+
.use('/api/analytics/pages', requireAuth())
|
|
251
|
+
.use('/api/analytics/referrers', authMiddleware(auth))
|
|
252
|
+
.use('/api/analytics/referrers', requireAuth())
|
|
253
|
+
.use('/api/analytics/devices', authMiddleware(auth))
|
|
254
|
+
.use('/api/analytics/devices', requireAuth())
|
|
255
|
+
.use('/api/analytics/campaigns', authMiddleware(auth))
|
|
256
|
+
.use('/api/analytics/campaigns', requireAuth())
|
|
257
|
+
: honoWithActivityRateLimit
|
|
258
|
+
.use('/api/activity', requireAuth())
|
|
259
|
+
.use('/api/activity/*', requireAuth())
|
|
260
|
+
.use('/api/analytics/overview', requireAuth())
|
|
261
|
+
.use('/api/analytics/pages', requireAuth())
|
|
262
|
+
.use('/api/analytics/referrers', requireAuth())
|
|
263
|
+
.use('/api/analytics/devices', requireAuth())
|
|
264
|
+
.use('/api/analytics/campaigns', requireAuth())
|
|
265
|
+
|
|
266
|
+
// Chain table routes (always register, returns empty array if no tables configured)
|
|
267
|
+
// Routes now have access to session via c.var.session
|
|
268
|
+
// Pass app configuration for table metadata lookup (tableId → table name mapping)
|
|
269
|
+
const honoWithTables = chainTableRoutes(honoWithAuth, app)
|
|
270
|
+
|
|
271
|
+
// Chain activity routes (activity log access)
|
|
272
|
+
const honoWithActivity = chainActivityRoutes(honoWithTables)
|
|
273
|
+
|
|
274
|
+
// Chain analytics routes only when analytics is enabled (not undefined, not false)
|
|
275
|
+
// When analytics is not configured, all /api/analytics/* endpoints return 404 (no routes registered)
|
|
276
|
+
const analyticsEnabled = app.analytics !== undefined && app.analytics !== false
|
|
277
|
+
const honoWithAnalytics = analyticsEnabled
|
|
278
|
+
? chainAnalyticsRoutes(
|
|
279
|
+
honoWithActivity,
|
|
280
|
+
app.name,
|
|
281
|
+
typeof app.analytics === 'object' ? app.analytics.retentionDays : undefined,
|
|
282
|
+
typeof app.analytics === 'object' ? app.analytics.excludedPaths : undefined,
|
|
283
|
+
typeof app.analytics === 'object' ? app.analytics.respectDoNotTrack : undefined
|
|
284
|
+
)
|
|
285
|
+
: honoWithActivity
|
|
286
|
+
|
|
287
|
+
// Chain auth routes (role manipulation prevention)
|
|
288
|
+
return chainAuthRoutes(honoWithAnalytics, auth)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Type export for Hono RPC client
|
|
293
|
+
*
|
|
294
|
+
* This type is used by the RPC client to provide full type safety
|
|
295
|
+
* and autocomplete for API calls on the frontend.
|
|
296
|
+
*
|
|
297
|
+
* **Important**: This type must be extracted from the chained result,
|
|
298
|
+
* not from a sub-app mounted with .route()
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* import { hc } from 'hono/client'
|
|
303
|
+
* import type { ApiType } from '@/infrastructure/server/route-setup/api-routes'
|
|
304
|
+
*
|
|
305
|
+
* const client = hc<ApiType>('http://localhost:3000')
|
|
306
|
+
* const res = await client.api.health.$get()
|
|
307
|
+
* const data = await res.json() // Fully typed HealthResponse!
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
export type ApiType = ReturnType<typeof createApiRoutes<Hono>>
|