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,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Languages } from '@/domain/models/app/languages'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Normalize language code to match translation keys
|
|
12
|
+
*
|
|
13
|
+
* Tries exact match first, then falls back to base language code (e.g., 'fr-FR' → 'fr')
|
|
14
|
+
*
|
|
15
|
+
* @param lang - Language code (e.g., 'fr-FR', 'en-US', 'fr')
|
|
16
|
+
* @param translations - Available translations object
|
|
17
|
+
* @returns Matching translation key or original language code
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* normalizeLanguageCode('fr-FR', { fr: {...}, en: {...} }) // 'fr'
|
|
22
|
+
* normalizeLanguageCode('fr', { fr: {...}, en: {...} }) // 'fr'
|
|
23
|
+
* normalizeLanguageCode('en-US', { 'en-US': {...} }) // 'en-US'
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function normalizeLanguageCode(
|
|
27
|
+
lang: string,
|
|
28
|
+
translations: Record<string, Record<string, string>>
|
|
29
|
+
): string {
|
|
30
|
+
// Try exact match first
|
|
31
|
+
if (translations[lang]) {
|
|
32
|
+
return lang
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Try base language code (e.g., 'fr-FR' → 'fr')
|
|
36
|
+
const baseLang = lang.split('-')[0]
|
|
37
|
+
if (baseLang && translations[baseLang]) {
|
|
38
|
+
return baseLang
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// No match found - return original
|
|
42
|
+
return lang
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve translation key with fallback support
|
|
47
|
+
*
|
|
48
|
+
* Implements the $t:key pattern for centralized translations.
|
|
49
|
+
* When a translation is missing in the current language, falls back to the fallback language.
|
|
50
|
+
*
|
|
51
|
+
* @param key - Translation key (e.g., 'welcome', 'common.save')
|
|
52
|
+
* @param currentLang - Current language code (e.g., 'fr-FR')
|
|
53
|
+
* @param languages - Languages configuration from app schema
|
|
54
|
+
* @returns Translated string or key if not found
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const text = resolveTranslation('welcome', 'fr-FR', languages)
|
|
59
|
+
* // Returns: 'Bienvenue' if exists in fr-FR
|
|
60
|
+
* // Returns: 'Welcome' if missing in fr-FR but exists in fallback en-US
|
|
61
|
+
* // Returns: 'welcome' if not found in any language
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export function resolveTranslation(
|
|
65
|
+
key: string,
|
|
66
|
+
currentLang: string,
|
|
67
|
+
languages?: Languages
|
|
68
|
+
): string {
|
|
69
|
+
// No translations configured - return key as-is
|
|
70
|
+
if (!languages?.translations) {
|
|
71
|
+
return key
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { translations, fallback } = languages
|
|
75
|
+
|
|
76
|
+
// Normalize language code to match translation keys (e.g., 'fr-FR' → 'fr')
|
|
77
|
+
const normalizedLang = normalizeLanguageCode(currentLang, translations)
|
|
78
|
+
|
|
79
|
+
// Try current language first
|
|
80
|
+
const currentTranslations = translations[normalizedLang]
|
|
81
|
+
if (currentTranslations?.[key]) {
|
|
82
|
+
return currentTranslations[key]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Try fallback language (defaults to default language)
|
|
86
|
+
const fallbackLang = fallback || languages.default
|
|
87
|
+
if (fallbackLang !== normalizedLang) {
|
|
88
|
+
const normalizedFallback = normalizeLanguageCode(fallbackLang, translations)
|
|
89
|
+
const fallbackTranslations = translations[normalizedFallback]
|
|
90
|
+
if (fallbackTranslations?.[key]) {
|
|
91
|
+
return fallbackTranslations[key]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Translation not found - return key
|
|
96
|
+
return key
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Resolve $t:key pattern in a string
|
|
101
|
+
*
|
|
102
|
+
* Processes strings containing $t:key syntax and replaces them with translations.
|
|
103
|
+
* Supports fallback when translation is missing.
|
|
104
|
+
*
|
|
105
|
+
* @param text - String that may contain $t:key patterns
|
|
106
|
+
* @param currentLang - Current language code
|
|
107
|
+
* @param languages - Languages configuration from app schema
|
|
108
|
+
* @returns String with resolved translations
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* resolveTranslationPattern('$t:welcome', 'fr-FR', languages) // 'Bienvenue'
|
|
113
|
+
* resolveTranslationPattern('$t:goodbye', 'fr-FR', languages) // 'Goodbye' (fallback)
|
|
114
|
+
* resolveTranslationPattern('Hello world', 'fr-FR', languages) // 'Hello world' (no pattern)
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export function resolveTranslationPattern(
|
|
118
|
+
text: string,
|
|
119
|
+
currentLang: string,
|
|
120
|
+
languages?: Languages
|
|
121
|
+
): string {
|
|
122
|
+
// Check if text starts with $t: pattern
|
|
123
|
+
if (text.startsWith('$t:')) {
|
|
124
|
+
const key = text.slice(3) // Remove '$t:' prefix
|
|
125
|
+
return resolveTranslation(key, currentLang, languages)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// No pattern found - return text as-is
|
|
129
|
+
return text
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Collect all available translations for a key across all languages
|
|
134
|
+
*
|
|
135
|
+
* Used for pre-resolving translations on the server side, allowing client-side
|
|
136
|
+
* code to simply lookup translations without re-implementing fallback logic.
|
|
137
|
+
*
|
|
138
|
+
* @param key - Translation key (e.g., 'welcome', 'common.save')
|
|
139
|
+
* @param languages - Languages configuration from app schema
|
|
140
|
+
* @returns Object mapping language codes to translated strings, or undefined if no translations
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* collectTranslationsForKey('welcome', languages)
|
|
145
|
+
* // Returns: { 'en-US': 'Welcome', 'fr-FR': 'Bienvenue', 'es-ES': 'Bienvenido' }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function collectTranslationsForKey(
|
|
149
|
+
key: string,
|
|
150
|
+
languages?: Languages
|
|
151
|
+
): Record<string, string> | undefined {
|
|
152
|
+
if (!languages?.translations) {
|
|
153
|
+
return undefined
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Collect translation for this key from all available languages (functional approach)
|
|
157
|
+
const result = Object.entries(languages.translations).reduce(
|
|
158
|
+
(acc, [lang, translations]) => {
|
|
159
|
+
const translationDict = translations as Record<string, string>
|
|
160
|
+
if (translationDict[key]) {
|
|
161
|
+
return { ...acc, [lang]: translationDict[key] }
|
|
162
|
+
}
|
|
163
|
+
return acc
|
|
164
|
+
},
|
|
165
|
+
{} as Record<string, string>
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
// Return undefined if no translations found (key doesn't exist in any language)
|
|
169
|
+
return Object.keys(result).length > 0 ? result : undefined
|
|
170
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sovrium - A Bun web framework with React SSR and Tailwind CSS
|
|
10
|
+
*
|
|
11
|
+
* This is the main entry point for Sovrium applications. It provides a simple
|
|
12
|
+
* Promise-based API for starting a web server with automatic:
|
|
13
|
+
* - React 19 server-side rendering
|
|
14
|
+
* - Tailwind CSS compilation (no build step)
|
|
15
|
+
* - Type-safe configuration validation
|
|
16
|
+
* - Graceful shutdown handling
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { Console, Effect, Schema } from 'effect'
|
|
20
|
+
import { generateStatic as generateStaticUseCase } from '@/application/use-cases/server/generate-static'
|
|
21
|
+
import { startServer } from '@/application/use-cases/server/start-server'
|
|
22
|
+
import { AppSchema } from '@/domain/models/app'
|
|
23
|
+
import { createAppLayer } from '@/infrastructure/layers/app-layer'
|
|
24
|
+
import { withGracefulShutdown } from '@/infrastructure/server/lifecycle'
|
|
25
|
+
import type { ServerInstance } from '@/application/models/server'
|
|
26
|
+
import type {
|
|
27
|
+
GenerateStaticOptions,
|
|
28
|
+
GenerateStaticResult,
|
|
29
|
+
} from '@/application/use-cases/server/generate-static'
|
|
30
|
+
import type { StartOptions } from '@/application/use-cases/server/start-server'
|
|
31
|
+
import type { App, AppEncoded } from '@/domain/models/app'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Simple server interface with Promise-based methods
|
|
35
|
+
*/
|
|
36
|
+
export interface SimpleServer {
|
|
37
|
+
/**
|
|
38
|
+
* Server URL (e.g., "http://localhost:3000")
|
|
39
|
+
*/
|
|
40
|
+
readonly url: string
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Stop the server gracefully
|
|
44
|
+
* @returns Promise that resolves when server is stopped
|
|
45
|
+
*/
|
|
46
|
+
stop: () => Promise<void>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Convert Effect-based ServerInstance to simple Promise-based interface
|
|
51
|
+
*/
|
|
52
|
+
const toSimpleServer = (server: Readonly<ServerInstance>): SimpleServer => ({
|
|
53
|
+
url: server.url,
|
|
54
|
+
stop: () => Effect.runPromise(server.stop),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Start an Sovrium server with automatic logging and graceful shutdown
|
|
59
|
+
*
|
|
60
|
+
* This is the main entry point for Sovrium applications. It:
|
|
61
|
+
* 1. Validates the app configuration using Effect Schema
|
|
62
|
+
* 2. Compiles Tailwind CSS dynamically using PostCSS
|
|
63
|
+
* 3. Creates a Hono web server with React SSR
|
|
64
|
+
* 4. Serves the homepage at "/" and compiled CSS at "/assets/output.css"
|
|
65
|
+
* 5. Sets up graceful shutdown handlers (SIGINT, SIGTERM)
|
|
66
|
+
* 6. Returns a simple server interface with url and stop method
|
|
67
|
+
*
|
|
68
|
+
* @param app - Application configuration with name and description
|
|
69
|
+
* @param options - Optional server configuration (port, hostname)
|
|
70
|
+
* @returns Promise that resolves to a simple server interface
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* Basic usage:
|
|
74
|
+
* ```typescript
|
|
75
|
+
* import { start } from 'sovrium'
|
|
76
|
+
*
|
|
77
|
+
* const myApp = {
|
|
78
|
+
* name: 'My App',
|
|
79
|
+
* description: 'A simple Bun application'
|
|
80
|
+
* }
|
|
81
|
+
*
|
|
82
|
+
* // Start with default port (3000) and hostname ('localhost')
|
|
83
|
+
* const server = await start(myApp)
|
|
84
|
+
* console.log(`Server running at ${server.url}`)
|
|
85
|
+
* // Server stays alive until Ctrl+C
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* With custom configuration:
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const server = await start(myApp, {
|
|
92
|
+
* port: 8080,
|
|
93
|
+
* hostname: '0.0.0.0'
|
|
94
|
+
* })
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* With error handling:
|
|
99
|
+
* ```typescript
|
|
100
|
+
* start(myApp).catch((error) => {
|
|
101
|
+
* console.error('Failed to start server:', error)
|
|
102
|
+
* process.exit(1)
|
|
103
|
+
* })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export const start = async (app: AppEncoded, options: StartOptions = {}): Promise<SimpleServer> => {
|
|
107
|
+
// Parse app configuration once to extract auth config
|
|
108
|
+
const validatedApp: App = Schema.decodeUnknownSync(AppSchema)(app)
|
|
109
|
+
|
|
110
|
+
const program = Effect.gen(function* () {
|
|
111
|
+
yield* Console.log('Starting Sovrium server...')
|
|
112
|
+
|
|
113
|
+
// Start the server (dependencies injected via AppLayer with auth config)
|
|
114
|
+
const server = yield* startServer(app, options)
|
|
115
|
+
|
|
116
|
+
// Setup graceful shutdown in background (forked so it doesn't block)
|
|
117
|
+
yield* Effect.fork(withGracefulShutdown(server))
|
|
118
|
+
|
|
119
|
+
// Return the server instance immediately (don't wait for shutdown)
|
|
120
|
+
return server
|
|
121
|
+
}).pipe(
|
|
122
|
+
// Provide dependencies (ServerFactory + PageRenderer + Auth with app-specific config)
|
|
123
|
+
Effect.provide(createAppLayer(validatedApp.auth))
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
// Run the Effect program and convert to simple server interface
|
|
127
|
+
const server = await Effect.runPromise(program)
|
|
128
|
+
return toSimpleServer(server)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Build static site files from a Sovrium application
|
|
133
|
+
*
|
|
134
|
+
* This function generates static HTML files and supporting assets that can be
|
|
135
|
+
* deployed to any static hosting provider (GitHub Pages, Netlify, Vercel, etc.).
|
|
136
|
+
*
|
|
137
|
+
* @param app - Application configuration with pages, theme, etc.
|
|
138
|
+
* @param options - Optional static generation configuration
|
|
139
|
+
* @returns Promise that resolves to generation result with output directory and file list
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* Basic usage:
|
|
143
|
+
* ```typescript
|
|
144
|
+
* import { build } from 'sovrium'
|
|
145
|
+
*
|
|
146
|
+
* const myApp = {
|
|
147
|
+
* name: 'My App',
|
|
148
|
+
* pages: [
|
|
149
|
+
* {
|
|
150
|
+
* name: 'home',
|
|
151
|
+
* path: '/',
|
|
152
|
+
* meta: { title: 'Home' },
|
|
153
|
+
* sections: []
|
|
154
|
+
* }
|
|
155
|
+
* ]
|
|
156
|
+
* }
|
|
157
|
+
*
|
|
158
|
+
* const result = await build(myApp)
|
|
159
|
+
* console.log(`Generated ${result.files.length} files to ${result.outputDir}`)
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* With options:
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const result = await build(myApp, {
|
|
166
|
+
* outputDir: './dist',
|
|
167
|
+
* baseUrl: 'https://example.com',
|
|
168
|
+
* generateSitemap: true,
|
|
169
|
+
* generateRobotsTxt: true,
|
|
170
|
+
* deployment: 'github-pages'
|
|
171
|
+
* })
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export const build = async (
|
|
175
|
+
app: AppEncoded,
|
|
176
|
+
options: GenerateStaticOptions = {}
|
|
177
|
+
): Promise<GenerateStaticResult> => {
|
|
178
|
+
// Parse app configuration once to extract auth config
|
|
179
|
+
const validatedApp: App = Schema.decodeUnknownSync(AppSchema)(app)
|
|
180
|
+
|
|
181
|
+
const program = Effect.gen(function* () {
|
|
182
|
+
yield* Console.log('Generating static site...')
|
|
183
|
+
|
|
184
|
+
// Generate static site (dependencies injected via AppLayer)
|
|
185
|
+
const result = yield* generateStaticUseCase(app, options)
|
|
186
|
+
|
|
187
|
+
yield* Console.log(`✅ Static site generated to ${result.outputDir}`)
|
|
188
|
+
yield* Console.log(` Generated ${result.files.length} files`)
|
|
189
|
+
|
|
190
|
+
return result
|
|
191
|
+
}).pipe(
|
|
192
|
+
// Provide dependencies (ServerFactory + PageRenderer + Auth with app-specific config)
|
|
193
|
+
Effect.provide(createAppLayer(validatedApp.auth))
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// Run the Effect program and return the result
|
|
197
|
+
return await Effect.runPromise(program)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Re-export types for convenience
|
|
202
|
+
*/
|
|
203
|
+
export type { StartOptions, GenerateStaticOptions, GenerateStaticResult }
|
|
204
|
+
export type { App, AppEncoded } from '@/domain/models/app'
|
|
205
|
+
export { AppSchema } from '@/domain/models/app'
|
|
206
|
+
export type { Page, PageEncoded } from '@/domain/models/app/pages'
|
|
207
|
+
export { PageSchema } from '@/domain/models/app/pages'
|
|
208
|
+
export type { ComponentTemplate } from '@/domain/models/app/component/component'
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 ESSENTIAL SERVICES
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Business Source License 1.1
|
|
5
|
+
* found in the LICENSE.md file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Minimal first-party analytics tracking script (~1KB minified)
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Sends page path, title, referrer, screen size via navigator.sendBeacon
|
|
13
|
+
* - Extracts UTM params from URL on load
|
|
14
|
+
* - Listens for history.pushState / popstate for SPA navigation
|
|
15
|
+
* - Respects navigator.doNotTrack if configured
|
|
16
|
+
* - No cookies, no external dependencies
|
|
17
|
+
*
|
|
18
|
+
* Template variables replaced at serve time:
|
|
19
|
+
* - __ENDPOINT__ — collection API URL (e.g., /api/analytics/collect)
|
|
20
|
+
* - __APP_NAME__ — application name for multi-tenant support
|
|
21
|
+
* - __RESPECT_DNT__ — whether to respect Do Not Track header ("true" or "false")
|
|
22
|
+
*/
|
|
23
|
+
export function generateTrackingScript(
|
|
24
|
+
endpoint: string,
|
|
25
|
+
appName: string,
|
|
26
|
+
respectDoNotTrack: boolean
|
|
27
|
+
): string {
|
|
28
|
+
return `(function(){
|
|
29
|
+
"use strict";
|
|
30
|
+
var E="${endpoint}",A="${appName}",D=${respectDoNotTrack ? 'true' : 'false'};
|
|
31
|
+
if(D&&navigator.doNotTrack==="1")return;
|
|
32
|
+
var u=function(){
|
|
33
|
+
try{var s=new URLSearchParams(location.search);
|
|
34
|
+
var d={p:location.pathname,t:document.title,r:document.referrer||void 0,
|
|
35
|
+
sw:screen.width,sh:screen.height,
|
|
36
|
+
us:s.get("utm_source")||void 0,um:s.get("utm_medium")||void 0,
|
|
37
|
+
uc:s.get("utm_campaign")||void 0,ux:s.get("utm_content")||void 0,
|
|
38
|
+
ut:s.get("utm_term")||void 0};
|
|
39
|
+
var b=JSON.stringify(d);
|
|
40
|
+
if(navigator.sendBeacon){navigator.sendBeacon(E,new Blob([b],{type:"application/json"}))}
|
|
41
|
+
else{var x=new XMLHttpRequest();x.open("POST",E,true);x.setRequestHeader("Content-Type","application/json");x.send(b)}
|
|
42
|
+
}catch(e){}};
|
|
43
|
+
u();
|
|
44
|
+
var op=history.pushState;
|
|
45
|
+
history.pushState=function(){op.apply(this,arguments);u()};
|
|
46
|
+
window.addEventListener("popstate",u);
|
|
47
|
+
})();`
|
|
48
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
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 { betterAuth } from 'better-auth'
|
|
9
|
+
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
10
|
+
import { createAuthMiddleware, APIError } from 'better-auth/api'
|
|
11
|
+
import { openAPI } from 'better-auth/plugins'
|
|
12
|
+
import { getStrategy, hasStrategy } from '@/domain/models/app/auth'
|
|
13
|
+
import { db } from '@/infrastructure/database'
|
|
14
|
+
import { createEmailHandlers } from './email-handlers'
|
|
15
|
+
import { buildAdminPlugin } from './plugins/admin'
|
|
16
|
+
import { buildMagicLinkPlugin } from './plugins/magic-link'
|
|
17
|
+
import { buildTwoFactorPlugin } from './plugins/two-factor'
|
|
18
|
+
import { users, sessions, accounts, verifications, twoFactors } from './schema'
|
|
19
|
+
import type { Auth } from '@/domain/models/app/auth'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Build socialProviders configuration from auth config
|
|
23
|
+
*
|
|
24
|
+
* Maps enabled OAuth providers to Better Auth socialProviders configuration.
|
|
25
|
+
* Credentials are loaded from environment variables using the pattern:
|
|
26
|
+
* - {PROVIDER}_CLIENT_ID (e.g., GOOGLE_CLIENT_ID)
|
|
27
|
+
* - {PROVIDER}_CLIENT_SECRET (e.g., GOOGLE_CLIENT_SECRET)
|
|
28
|
+
*/
|
|
29
|
+
export const buildSocialProviders = (authConfig?: Auth) => {
|
|
30
|
+
const oauthStrategy = getStrategy(authConfig, 'oauth')
|
|
31
|
+
if (!oauthStrategy?.providers) return {}
|
|
32
|
+
|
|
33
|
+
return oauthStrategy.providers.reduce(
|
|
34
|
+
(providers, provider) => {
|
|
35
|
+
const envVarPrefix = provider.toUpperCase()
|
|
36
|
+
return {
|
|
37
|
+
...providers,
|
|
38
|
+
[provider]: {
|
|
39
|
+
clientId: process.env[`${envVarPrefix}_CLIENT_ID`] || '',
|
|
40
|
+
clientSecret: process.env[`${envVarPrefix}_CLIENT_SECRET`] || '',
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{} as Record<string, { clientId: string; clientSecret: string }>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Schema mapping for Better Auth's drizzle adapter
|
|
50
|
+
*
|
|
51
|
+
* IMPORTANT: The keys MUST be Better Auth's internal model names (user, account, session, etc.)
|
|
52
|
+
* NOT the custom table names. The actual database table name is determined by the Drizzle
|
|
53
|
+
* table definition (e.g., pgTable('_sovrium_auth_users', ...)).
|
|
54
|
+
*
|
|
55
|
+
* This is a critical fix for GitHub issue #5879 - using table names as keys causes
|
|
56
|
+
* the adapter to return wrong records, breaking account linking.
|
|
57
|
+
*
|
|
58
|
+
* See: https://github.com/better-auth/better-auth/issues/5879
|
|
59
|
+
*/
|
|
60
|
+
const drizzleSchema = {
|
|
61
|
+
user: users,
|
|
62
|
+
session: sessions,
|
|
63
|
+
account: accounts,
|
|
64
|
+
verification: verifications,
|
|
65
|
+
twoFactor: twoFactors,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build Better Auth plugins array with custom table names
|
|
70
|
+
*
|
|
71
|
+
* Conditionally includes plugins when enabled in auth configuration.
|
|
72
|
+
* If a plugin is not enabled, its endpoints will not be available (404).
|
|
73
|
+
*/
|
|
74
|
+
export const buildAuthPlugins = (
|
|
75
|
+
handlers: Readonly<ReturnType<typeof createEmailHandlers>>,
|
|
76
|
+
authConfig?: Auth
|
|
77
|
+
) => [
|
|
78
|
+
openAPI({ disableDefaultReference: true }),
|
|
79
|
+
...buildAdminPlugin(authConfig),
|
|
80
|
+
...buildTwoFactorPlugin(authConfig),
|
|
81
|
+
...buildMagicLinkPlugin(handlers.magicLink, authConfig),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build rate limiting configuration for Better Auth
|
|
86
|
+
*
|
|
87
|
+
* NOTE: Better Auth's native rate limiting has known issues with customRules not working reliably
|
|
88
|
+
* (see GitHub issues #392, #1891, #2153). As a workaround, Sovrium uses custom Hono middleware
|
|
89
|
+
* in auth-routes.ts to implement endpoint-specific rate limiting for sign-in, sign-up, and
|
|
90
|
+
* password-reset endpoints.
|
|
91
|
+
*
|
|
92
|
+
* This configuration keeps Better Auth's rate limiting disabled to avoid conflicts with the
|
|
93
|
+
* custom middleware implementation.
|
|
94
|
+
*/
|
|
95
|
+
export function buildRateLimitConfig() {
|
|
96
|
+
return {
|
|
97
|
+
enabled: false, // Disabled in favor of custom Hono middleware
|
|
98
|
+
window: 60,
|
|
99
|
+
max: 100,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Build email and password configuration from auth config
|
|
105
|
+
*/
|
|
106
|
+
export function buildEmailAndPasswordConfig(
|
|
107
|
+
authConfig: Auth | undefined,
|
|
108
|
+
handlers: Readonly<ReturnType<typeof createEmailHandlers>>
|
|
109
|
+
) {
|
|
110
|
+
const strategy = getStrategy(authConfig, 'emailAndPassword')
|
|
111
|
+
const requireEmailVerification = strategy?.requireEmailVerification ?? false
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
enabled: hasStrategy(authConfig, 'emailAndPassword'),
|
|
115
|
+
requireEmailVerification,
|
|
116
|
+
sendResetPassword: handlers.passwordReset,
|
|
117
|
+
minPasswordLength: strategy?.minPasswordLength ?? 8,
|
|
118
|
+
maxPasswordLength: strategy?.maxPasswordLength ?? 128,
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type AuthMiddlewareCtx = Parameters<typeof createAuthMiddleware>[0] extends (
|
|
123
|
+
ctx: infer C
|
|
124
|
+
) => unknown
|
|
125
|
+
? C
|
|
126
|
+
: never
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Validate admin create-user password length (Better Auth Issue #4651 workaround).
|
|
130
|
+
* The admin plugin doesn't respect emailAndPassword validation settings.
|
|
131
|
+
*/
|
|
132
|
+
// eslint-disable-next-line functional/prefer-immutable-types
|
|
133
|
+
async function validateAdminCreateUserPassword(ctx: AuthMiddlewareCtx) {
|
|
134
|
+
const body = ctx.body as { password?: string }
|
|
135
|
+
if (!body?.password) return
|
|
136
|
+
const minLength = 8
|
|
137
|
+
const maxLength = 128
|
|
138
|
+
if (body.password.length < minLength) {
|
|
139
|
+
// eslint-disable-next-line functional/no-throw-statements
|
|
140
|
+
throw new APIError('BAD_REQUEST', {
|
|
141
|
+
message: `Password must be at least ${minLength} characters`,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
if (body.password.length > maxLength) {
|
|
145
|
+
// eslint-disable-next-line functional/no-throw-statements
|
|
146
|
+
throw new APIError('BAD_REQUEST', {
|
|
147
|
+
message: `Password must not exceed ${maxLength} characters`,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Build auth hooks with request validation middleware
|
|
154
|
+
*
|
|
155
|
+
* Validates password length for admin createUser endpoint (Better Auth Issue #4651 workaround).
|
|
156
|
+
* The admin plugin doesn't respect emailAndPassword validation settings.
|
|
157
|
+
*
|
|
158
|
+
* Note: The /change-email endpoint uses Better Auth 1.5's native email enumeration protection,
|
|
159
|
+
* which always returns 200 OK regardless of whether the target email exists.
|
|
160
|
+
*/
|
|
161
|
+
export function buildAuthHooks() {
|
|
162
|
+
return {
|
|
163
|
+
before: createAuthMiddleware(async (ctx) => {
|
|
164
|
+
if (ctx.path === '/admin/create-user') {
|
|
165
|
+
// eslint-disable-next-line functional/no-expression-statements
|
|
166
|
+
await validateAdminCreateUserPassword(ctx)
|
|
167
|
+
}
|
|
168
|
+
}),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Create Better Auth instance with dynamic configuration
|
|
173
|
+
*/
|
|
174
|
+
export function createAuthInstance(authConfig?: Auth) {
|
|
175
|
+
const handlers = createEmailHandlers(authConfig)
|
|
176
|
+
const emailAndPasswordConfig = buildEmailAndPasswordConfig(authConfig, handlers)
|
|
177
|
+
const { requireEmailVerification } = emailAndPasswordConfig
|
|
178
|
+
|
|
179
|
+
return betterAuth({
|
|
180
|
+
secret: process.env.AUTH_SECRET,
|
|
181
|
+
baseURL: process.env.BASE_URL || `http://localhost:${process.env.PORT || 3000}`,
|
|
182
|
+
database: drizzleAdapter(db, {
|
|
183
|
+
provider: 'pg',
|
|
184
|
+
usePlural: false,
|
|
185
|
+
schema: drizzleSchema,
|
|
186
|
+
}),
|
|
187
|
+
// NOTE: modelName options removed - drizzleSchema uses standard model names
|
|
188
|
+
// and Drizzle pgTable() definitions specify actual database table names
|
|
189
|
+
trustedOrigins: ['*'],
|
|
190
|
+
advanced: {
|
|
191
|
+
useSecureCookies: process.env.NODE_ENV === 'production',
|
|
192
|
+
disableCSRFCheck: process.env.NODE_ENV !== 'production',
|
|
193
|
+
},
|
|
194
|
+
emailAndPassword: emailAndPasswordConfig,
|
|
195
|
+
emailVerification: {
|
|
196
|
+
sendOnSignUp: requireEmailVerification,
|
|
197
|
+
autoSignInAfterVerification: true,
|
|
198
|
+
sendVerificationEmail: handlers.verification,
|
|
199
|
+
},
|
|
200
|
+
user: {
|
|
201
|
+
changeEmail: { enabled: true, sendChangeEmailVerification: handlers.verification },
|
|
202
|
+
},
|
|
203
|
+
socialProviders: buildSocialProviders(authConfig),
|
|
204
|
+
plugins: buildAuthPlugins(handlers, authConfig),
|
|
205
|
+
rateLimit: buildRateLimitConfig(),
|
|
206
|
+
hooks: buildAuthHooks(),
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Default Better Auth instance for OpenAPI schema generation
|
|
212
|
+
* Uses default configuration (requireEmailVerification: false)
|
|
213
|
+
*
|
|
214
|
+
* For app-specific configuration, use createAuthLayer(authConfig) instead.
|
|
215
|
+
*/
|
|
216
|
+
export const auth = createAuthInstance()
|