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,122 @@
|
|
|
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 { filterReadableFields } from './field-read-filter'
|
|
9
|
+
import { transformRecords } from './record-transformer'
|
|
10
|
+
import type { TransformedRecord, RecordFieldValue, FormattedFieldValue } from './record-transformer'
|
|
11
|
+
import type { App } from '@/domain/models/app'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Apply field selection to transform records into flat structure
|
|
15
|
+
* When fields parameter is specified, returns records with only selected fields
|
|
16
|
+
* Maintains Airtable-style structure: { id, fields: { ... }, createdAt, updatedAt }
|
|
17
|
+
*/
|
|
18
|
+
export function applyFieldSelection(
|
|
19
|
+
records: readonly TransformedRecord[],
|
|
20
|
+
fields: string
|
|
21
|
+
): readonly TransformedRecord[] {
|
|
22
|
+
const fieldNames = fields.split(',').map((f) => f.trim())
|
|
23
|
+
|
|
24
|
+
return records.map((record) => {
|
|
25
|
+
// Build fields object with only requested fields
|
|
26
|
+
const selectedFields = fieldNames.reduce<
|
|
27
|
+
Record<string, RecordFieldValue | FormattedFieldValue>
|
|
28
|
+
>((acc, fieldName) => {
|
|
29
|
+
// Skip system fields (id, createdAt, updatedAt) - they're at root level
|
|
30
|
+
if (fieldName === 'id' || fieldName === 'createdAt' || fieldName === 'updatedAt') {
|
|
31
|
+
return acc
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Include user field if it exists
|
|
35
|
+
if (record.fields[fieldName] !== undefined) {
|
|
36
|
+
return { ...acc, [fieldName]: record.fields[fieldName] }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return acc
|
|
40
|
+
}, {})
|
|
41
|
+
|
|
42
|
+
// Return record with Airtable structure, only selected fields
|
|
43
|
+
return {
|
|
44
|
+
id: record.id,
|
|
45
|
+
fields: selectedFields,
|
|
46
|
+
createdAt: record.createdAt,
|
|
47
|
+
updatedAt: record.updatedAt,
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Apply pagination to records and calculate pagination metadata
|
|
54
|
+
*/
|
|
55
|
+
export function applyPagination(
|
|
56
|
+
records: readonly TransformedRecord[],
|
|
57
|
+
totalRecords: number,
|
|
58
|
+
limit?: number,
|
|
59
|
+
offset?: number
|
|
60
|
+
): {
|
|
61
|
+
readonly paginatedRecords: readonly TransformedRecord[]
|
|
62
|
+
readonly pagination: {
|
|
63
|
+
readonly page: number
|
|
64
|
+
readonly limit: number
|
|
65
|
+
readonly offset: number
|
|
66
|
+
readonly total: number
|
|
67
|
+
readonly totalPages: number
|
|
68
|
+
readonly hasNextPage: boolean
|
|
69
|
+
readonly hasPreviousPage: boolean
|
|
70
|
+
}
|
|
71
|
+
} {
|
|
72
|
+
const paginationLimit = limit ?? 10
|
|
73
|
+
const paginationOffset = offset ?? 0
|
|
74
|
+
const paginatedRecords = records.slice(paginationOffset, paginationOffset + paginationLimit)
|
|
75
|
+
|
|
76
|
+
const totalPages = Math.ceil(totalRecords / paginationLimit)
|
|
77
|
+
const currentPage = Math.floor(paginationOffset / paginationLimit) + 1
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
paginatedRecords,
|
|
81
|
+
pagination: {
|
|
82
|
+
page: currentPage,
|
|
83
|
+
limit: paginationLimit,
|
|
84
|
+
offset: paginationOffset,
|
|
85
|
+
total: totalRecords,
|
|
86
|
+
totalPages,
|
|
87
|
+
hasNextPage: paginationOffset + paginationLimit < totalRecords,
|
|
88
|
+
hasPreviousPage: paginationOffset > 0,
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Process and transform records with filtering and field selection
|
|
95
|
+
*/
|
|
96
|
+
export function processRecords(config: {
|
|
97
|
+
readonly records: readonly Record<string, unknown>[]
|
|
98
|
+
readonly app: App
|
|
99
|
+
readonly tableName: string
|
|
100
|
+
readonly userRole: string
|
|
101
|
+
readonly userId: string
|
|
102
|
+
readonly format?: 'display'
|
|
103
|
+
readonly timezone?: string
|
|
104
|
+
readonly fields?: string
|
|
105
|
+
}): readonly TransformedRecord[] {
|
|
106
|
+
const { records, app, tableName, userRole, userId, format, timezone, fields } = config
|
|
107
|
+
|
|
108
|
+
// Apply field-level read permissions filtering
|
|
109
|
+
const filteredRecords = records.map((record) =>
|
|
110
|
+
filterReadableFields({ app, tableName, userRole, userId, record })
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const transformedRecords = transformRecords(filteredRecords, {
|
|
114
|
+
format,
|
|
115
|
+
app,
|
|
116
|
+
tableName,
|
|
117
|
+
timezone,
|
|
118
|
+
}) as TransformedRecord[]
|
|
119
|
+
|
|
120
|
+
// Apply field selection if specified
|
|
121
|
+
return fields ? applyFieldSelection(transformedRecords, fields) : transformedRecords
|
|
122
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
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 { formatFieldForDisplay, type FormatResult } from './display-formatter'
|
|
9
|
+
import type { App } from '@/domain/models/app'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Field value types supported by record transformation
|
|
13
|
+
*/
|
|
14
|
+
export type RecordFieldValue =
|
|
15
|
+
| string
|
|
16
|
+
| number
|
|
17
|
+
| boolean
|
|
18
|
+
| unknown[]
|
|
19
|
+
| Record<string, unknown>
|
|
20
|
+
| null
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Formatted field value with optional display formatting
|
|
24
|
+
*/
|
|
25
|
+
export interface FormattedFieldValue {
|
|
26
|
+
readonly value: RecordFieldValue
|
|
27
|
+
readonly displayValue?: string
|
|
28
|
+
readonly timezone?: string
|
|
29
|
+
readonly displayTimezone?: string
|
|
30
|
+
readonly allowedFileTypes?: readonly string[]
|
|
31
|
+
readonly maxFileSize?: number
|
|
32
|
+
readonly maxFileSizeDisplay?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* User reference object for authorship fields (createdBy, updatedBy, deletedBy)
|
|
37
|
+
*/
|
|
38
|
+
export interface AuthorUserRef {
|
|
39
|
+
readonly id: string
|
|
40
|
+
readonly name?: string
|
|
41
|
+
readonly email?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Transformed record structure for API responses (Airtable-style)
|
|
46
|
+
*
|
|
47
|
+
* System fields (id, createdAt, updatedAt, createdBy, updatedBy) are at root level.
|
|
48
|
+
* User-defined fields are nested under the `fields` property.
|
|
49
|
+
*/
|
|
50
|
+
export interface TransformedRecord {
|
|
51
|
+
readonly id: string | number
|
|
52
|
+
readonly fields: Record<string, RecordFieldValue | FormattedFieldValue>
|
|
53
|
+
readonly createdAt: string
|
|
54
|
+
readonly updatedAt: string
|
|
55
|
+
readonly createdBy?: string
|
|
56
|
+
readonly updatedBy?: string
|
|
57
|
+
readonly deletedBy?: AuthorUserRef
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Convert a value to ISO 8601 datetime string
|
|
62
|
+
*
|
|
63
|
+
* @param value - Value to convert (Date object or string)
|
|
64
|
+
* @returns ISO 8601 datetime string
|
|
65
|
+
*/
|
|
66
|
+
const toISOString = (value: unknown): string => {
|
|
67
|
+
if (value instanceof Date) {
|
|
68
|
+
return value.toISOString()
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === 'string') {
|
|
71
|
+
return value
|
|
72
|
+
}
|
|
73
|
+
return new Date().toISOString()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Numeric field types that should return number values in API responses.
|
|
78
|
+
* PostgreSQL DECIMAL/NUMERIC types are returned as strings by database drivers,
|
|
79
|
+
* so we coerce them to numbers based on the field's schema type.
|
|
80
|
+
*
|
|
81
|
+
* Note: 'decimal' is NOT included here because decimal values should be preserved
|
|
82
|
+
* as strings to maintain precision and formatting (e.g., "50.00" not 50).
|
|
83
|
+
*/
|
|
84
|
+
const NUMERIC_FIELD_TYPES: ReadonlySet<string> = new Set([
|
|
85
|
+
'currency',
|
|
86
|
+
'number',
|
|
87
|
+
'integer',
|
|
88
|
+
'percentage',
|
|
89
|
+
'percent',
|
|
90
|
+
'rating',
|
|
91
|
+
'duration',
|
|
92
|
+
])
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Look up a field's type from the app schema
|
|
96
|
+
*/
|
|
97
|
+
const getFieldType = (
|
|
98
|
+
app: Readonly<App>,
|
|
99
|
+
tableName: string,
|
|
100
|
+
fieldName: string
|
|
101
|
+
): string | undefined => {
|
|
102
|
+
const table = app.tables?.find((t) => t.name === tableName)
|
|
103
|
+
return table?.fields.find((f) => f.name === fieldName)?.type
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Coerce a string value to a number if the field type is numeric.
|
|
108
|
+
* Returns the original value unchanged for non-numeric field types.
|
|
109
|
+
*/
|
|
110
|
+
/* eslint-disable functional/prefer-immutable-types -- RecordFieldValue must be mutable to match FormattedFieldValue interface */
|
|
111
|
+
const coerceNumericField = (
|
|
112
|
+
fieldName: string,
|
|
113
|
+
value: RecordFieldValue,
|
|
114
|
+
app: Readonly<App>,
|
|
115
|
+
tableName: string
|
|
116
|
+
): RecordFieldValue => {
|
|
117
|
+
/* eslint-enable functional/prefer-immutable-types */
|
|
118
|
+
if (typeof value !== 'string') return value
|
|
119
|
+
const fieldType = getFieldType(app, tableName, fieldName)
|
|
120
|
+
if (!fieldType || !NUMERIC_FIELD_TYPES.has(fieldType)) return value
|
|
121
|
+
const num = Number(value)
|
|
122
|
+
return !isNaN(num) && isFinite(num) ? num : value
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Convert string numbers to numeric values (used in display format path)
|
|
127
|
+
*/
|
|
128
|
+
// eslint-disable-next-line functional/prefer-immutable-types -- RecordFieldValue must be mutable to match FormattedFieldValue interface
|
|
129
|
+
const parseNumericString = (value: unknown, processedValue: RecordFieldValue): RecordFieldValue => {
|
|
130
|
+
// Coerce string numbers to numeric values for numeric field types
|
|
131
|
+
if (typeof value === 'string') {
|
|
132
|
+
const num = Number(value)
|
|
133
|
+
return !isNaN(num) && isFinite(num) ? num : processedValue
|
|
134
|
+
}
|
|
135
|
+
return typeof value === 'number' ? value : processedValue
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Build formatted field value with optional metadata
|
|
140
|
+
*/
|
|
141
|
+
/* eslint-disable functional/prefer-immutable-types -- RecordFieldValue must be mutable to match FormattedFieldValue interface */
|
|
142
|
+
function buildFormattedValue(
|
|
143
|
+
fieldValue: RecordFieldValue,
|
|
144
|
+
formatResult: Readonly<FormatResult>
|
|
145
|
+
): FormattedFieldValue {
|
|
146
|
+
/* eslint-enable functional/prefer-immutable-types */
|
|
147
|
+
const base: FormattedFieldValue = {
|
|
148
|
+
value: fieldValue,
|
|
149
|
+
displayValue: formatResult.displayValue,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
...base,
|
|
154
|
+
...(formatResult.timezone ? { timezone: formatResult.timezone } : {}),
|
|
155
|
+
...(formatResult.displayTimezone ? { displayTimezone: formatResult.displayTimezone } : {}),
|
|
156
|
+
...(formatResult.allowedFileTypes ? { allowedFileTypes: formatResult.allowedFileTypes } : {}),
|
|
157
|
+
...(formatResult.maxFileSize !== undefined ? { maxFileSize: formatResult.maxFileSize } : {}),
|
|
158
|
+
...(formatResult.maxFileSizeDisplay
|
|
159
|
+
? { maxFileSizeDisplay: formatResult.maxFileSizeDisplay }
|
|
160
|
+
: {}),
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Process a single field value with optional display formatting
|
|
166
|
+
*/
|
|
167
|
+
const processFieldValue = (
|
|
168
|
+
key: string,
|
|
169
|
+
value: unknown,
|
|
170
|
+
options?: Readonly<{
|
|
171
|
+
readonly format?: 'display'
|
|
172
|
+
readonly app?: App
|
|
173
|
+
readonly tableName?: string
|
|
174
|
+
readonly timezone?: string
|
|
175
|
+
}>
|
|
176
|
+
): Readonly<RecordFieldValue | FormattedFieldValue> => {
|
|
177
|
+
const processedValue = value instanceof Date ? value.toISOString() : (value as RecordFieldValue)
|
|
178
|
+
|
|
179
|
+
// Check if app schema info is available for type-aware processing
|
|
180
|
+
const hasSchemaInfo = options?.app && options?.tableName
|
|
181
|
+
|
|
182
|
+
// Apply display formatting if requested
|
|
183
|
+
if (options?.format !== 'display' || !hasSchemaInfo) {
|
|
184
|
+
// Coerce numeric field types to numbers when schema info is available
|
|
185
|
+
return hasSchemaInfo
|
|
186
|
+
? coerceNumericField(key, processedValue, options.app!, options.tableName!)
|
|
187
|
+
: processedValue
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// For display formatting, pass the original value (may be string or number from database)
|
|
191
|
+
const formatResult = formatFieldForDisplay({
|
|
192
|
+
fieldName: key,
|
|
193
|
+
value,
|
|
194
|
+
app: options.app!,
|
|
195
|
+
tableName: options.tableName!,
|
|
196
|
+
timezoneOverride: options.timezone,
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
if (formatResult === undefined) {
|
|
200
|
+
return processedValue
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// For formatted fields, use the original value (preserve number type)
|
|
204
|
+
const fieldValue = parseNumericString(value, processedValue)
|
|
205
|
+
|
|
206
|
+
return buildFormattedValue(fieldValue, formatResult)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Check if a field is defined in the table schema
|
|
211
|
+
*/
|
|
212
|
+
const isTableField = (
|
|
213
|
+
fieldName: string,
|
|
214
|
+
app: Readonly<App> | undefined,
|
|
215
|
+
tableName: string | undefined
|
|
216
|
+
): boolean => {
|
|
217
|
+
if (!app || !tableName) return false
|
|
218
|
+
const table = app.tables?.find((t) => t.name === tableName)
|
|
219
|
+
return Boolean(table?.fields.some((f) => f.name === fieldName))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Build fields object including created_at/updated_at if they're defined as table fields
|
|
224
|
+
*/
|
|
225
|
+
const buildFieldsObject = (
|
|
226
|
+
userFields: Readonly<Record<string, unknown>>,
|
|
227
|
+
createdAt: unknown,
|
|
228
|
+
updatedAt: unknown,
|
|
229
|
+
options?: {
|
|
230
|
+
readonly app?: App
|
|
231
|
+
readonly tableName?: string
|
|
232
|
+
}
|
|
233
|
+
): Readonly<Record<string, unknown>> => {
|
|
234
|
+
const hasCreatedAtField = isTableField('created_at', options?.app, options?.tableName)
|
|
235
|
+
const hasUpdatedAtField = isTableField('updated_at', options?.app, options?.tableName)
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
...userFields,
|
|
239
|
+
...(hasCreatedAtField && createdAt !== undefined ? { created_at: createdAt } : {}),
|
|
240
|
+
...(hasUpdatedAtField && updatedAt !== undefined ? { updated_at: updatedAt } : {}),
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Transform a raw database record into the API response format (Airtable-style)
|
|
246
|
+
*
|
|
247
|
+
* This utility standardizes record transformation across all table endpoints:
|
|
248
|
+
* - Converts id to string
|
|
249
|
+
* - Nests user-defined fields under `fields` property (Airtable-style)
|
|
250
|
+
* - Keeps system fields (id, createdAt, updatedAt) at root level
|
|
251
|
+
* - Normalizes created_at/updated_at to ISO strings (or current timestamp if missing)
|
|
252
|
+
* - Converts Date objects in field values to ISO 8601 strings for API compliance
|
|
253
|
+
* - Optionally applies display formatting when format=display is requested
|
|
254
|
+
*
|
|
255
|
+
* @param record - Raw database record
|
|
256
|
+
* @param options - Transformation options
|
|
257
|
+
* @returns Transformed record for API response
|
|
258
|
+
*/
|
|
259
|
+
export const transformRecord = (
|
|
260
|
+
record: Readonly<Record<string, unknown>>,
|
|
261
|
+
options?: {
|
|
262
|
+
readonly format?: 'display'
|
|
263
|
+
readonly app?: App
|
|
264
|
+
readonly tableName?: string
|
|
265
|
+
readonly timezone?: string
|
|
266
|
+
}
|
|
267
|
+
): TransformedRecord => {
|
|
268
|
+
// Extract system fields including authorship metadata
|
|
269
|
+
const {
|
|
270
|
+
id,
|
|
271
|
+
created_at: createdAt,
|
|
272
|
+
updated_at: updatedAt,
|
|
273
|
+
created_by: createdBy,
|
|
274
|
+
updated_by: updatedBy,
|
|
275
|
+
deleted_by: deletedBy,
|
|
276
|
+
...userFields
|
|
277
|
+
} = record
|
|
278
|
+
|
|
279
|
+
// Build user fields, potentially including created_at/updated_at if they're table fields
|
|
280
|
+
const fieldsToTransform = buildFieldsObject(userFields, createdAt, updatedAt, options)
|
|
281
|
+
|
|
282
|
+
// Convert Date objects to ISO strings in user fields and optionally format for display
|
|
283
|
+
const transformedFields = Object.entries(fieldsToTransform).reduce<
|
|
284
|
+
Record<string, RecordFieldValue | FormattedFieldValue>
|
|
285
|
+
>(
|
|
286
|
+
(acc, [key, value]) => ({
|
|
287
|
+
...acc,
|
|
288
|
+
[key]: processFieldValue(key, value, options) as RecordFieldValue | FormattedFieldValue,
|
|
289
|
+
}),
|
|
290
|
+
{}
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
id: String(id),
|
|
295
|
+
fields: transformedFields,
|
|
296
|
+
createdAt: createdAt ? toISOString(createdAt) : new Date().toISOString(),
|
|
297
|
+
updatedAt: updatedAt ? toISOString(updatedAt) : new Date().toISOString(),
|
|
298
|
+
...(createdBy ? { createdBy: String(createdBy) } : {}),
|
|
299
|
+
...(updatedBy ? { updatedBy: String(updatedBy) } : {}),
|
|
300
|
+
...(deletedBy ? { deletedBy: { id: String(deletedBy) } } : {}),
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Transform multiple database records into API response format
|
|
306
|
+
*
|
|
307
|
+
* @param records - Array of raw database records
|
|
308
|
+
* @param options - Transformation options
|
|
309
|
+
* @returns Array of transformed records (mutable for API response compatibility)
|
|
310
|
+
*/
|
|
311
|
+
export const transformRecords = (
|
|
312
|
+
records: readonly Record<string, unknown>[],
|
|
313
|
+
options?: {
|
|
314
|
+
readonly format?: 'display'
|
|
315
|
+
readonly app?: App
|
|
316
|
+
readonly tableName?: string
|
|
317
|
+
readonly timezone?: string
|
|
318
|
+
}
|
|
319
|
+
): readonly TransformedRecord[] => records.map((record) => transformRecord(record, options))
|