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,166 @@
|
|
|
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 { Schema } from 'effect'
|
|
9
|
+
import { HttpUrlSchema } from '../common/url'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Open Graph content type
|
|
13
|
+
*
|
|
14
|
+
* 6 standard Open Graph types for different content:
|
|
15
|
+
* - website: General websites, landing pages (most common, default)
|
|
16
|
+
* - article: Blog posts, news articles (adds publish date, author metadata)
|
|
17
|
+
* - book: Book pages, publications
|
|
18
|
+
* - profile: Personal or company profiles
|
|
19
|
+
* - video: Video content pages (enables video embeds in social feeds)
|
|
20
|
+
* - music: Music content, albums (enables audio players)
|
|
21
|
+
*/
|
|
22
|
+
export const OpenGraphTypeSchema = Schema.Literal(
|
|
23
|
+
'website',
|
|
24
|
+
'article',
|
|
25
|
+
'book',
|
|
26
|
+
'profile',
|
|
27
|
+
'video',
|
|
28
|
+
'music'
|
|
29
|
+
).annotations({
|
|
30
|
+
description: 'Open Graph object type',
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Open Graph locale format
|
|
35
|
+
*
|
|
36
|
+
* Language and territory format: [language]_[TERRITORY]
|
|
37
|
+
* - Pattern: ^[a-z]{2}_[A-Z]{2}$ (2 lowercase + underscore + 2 uppercase)
|
|
38
|
+
* - Examples: en_US (English, United States), fr_FR (French, France), es_ES (Spanish, Spain)
|
|
39
|
+
* - Helps platforms show content to the right audience based on language/region
|
|
40
|
+
*/
|
|
41
|
+
export const OpenGraphLocaleSchema = Schema.String.pipe(
|
|
42
|
+
Schema.pattern(/^[a-z]{2}_[A-Z]{2}$/, {
|
|
43
|
+
message: () =>
|
|
44
|
+
'Locale must be in format language_TERRITORY (e.g., en_US, fr_FR, es_ES, de_DE, ja_JP)',
|
|
45
|
+
})
|
|
46
|
+
).annotations({
|
|
47
|
+
description: 'Locale in format language_TERRITORY',
|
|
48
|
+
examples: ['en_US', 'fr_FR', 'es_ES'],
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Open Graph determiner
|
|
53
|
+
*
|
|
54
|
+
* Grammatical article that appears before the title in share messages.
|
|
55
|
+
* Used in: "John shared [determiner] [title]"
|
|
56
|
+
*
|
|
57
|
+
* 5 options:
|
|
58
|
+
* - 'a': "Share a Website Builder"
|
|
59
|
+
* - 'an': "Share an Amazing Product"
|
|
60
|
+
* - 'the': "Share the Ultimate Guide to SEO"
|
|
61
|
+
* - 'auto': Platform decides based on title (no article)
|
|
62
|
+
* - '': Empty string (no article)
|
|
63
|
+
*
|
|
64
|
+
* Improves grammar in social sharing messages for better user experience.
|
|
65
|
+
*/
|
|
66
|
+
export const OpenGraphDeterminerSchema = Schema.Literal('a', 'an', 'the', 'auto', '').annotations({
|
|
67
|
+
description: 'Word that appears before the title',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Open Graph protocol metadata for rich social media sharing
|
|
72
|
+
*
|
|
73
|
+
* Defines how pages appear when shared on Facebook, LinkedIn, and other platforms
|
|
74
|
+
* supporting the Open Graph protocol. Creates rich preview cards with images, titles,
|
|
75
|
+
* and descriptions to dramatically increase engagement and click-through rates.
|
|
76
|
+
*
|
|
77
|
+
* Required properties:
|
|
78
|
+
* - title: Page title for social sharing (max 90 chars, shorter than page <title>)
|
|
79
|
+
* - description: Page description (max 200 chars, concise value proposition)
|
|
80
|
+
* - type: Content type (website, article, book, profile, video, music)
|
|
81
|
+
* - url: Canonical URL for this page (absolute URL)
|
|
82
|
+
*
|
|
83
|
+
* Optional properties:
|
|
84
|
+
* - image: Social sharing image URL (recommended: 1200x630px, 1.91:1 aspect ratio)
|
|
85
|
+
* - imageAlt: Alternative text for the image (accessibility, screen readers)
|
|
86
|
+
* - siteName: Overall website/brand name (different from page title)
|
|
87
|
+
* - locale: Content language/territory (en_US, fr_FR, etc.)
|
|
88
|
+
* - determiner: Grammatical article before title (a, an, the, auto, "")
|
|
89
|
+
* - video: Video URL for video content (enables video embeds in feeds)
|
|
90
|
+
* - audio: Audio URL for audio content (enables audio players)
|
|
91
|
+
*
|
|
92
|
+
* Impact:
|
|
93
|
+
* - Rich cards get 2-3x more clicks than plain links
|
|
94
|
+
* - Image is most important element (grabs attention)
|
|
95
|
+
* - Without OG tags: generic unfurl with no image (low engagement)
|
|
96
|
+
* - Complete OG tags: professional social presence
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const openGraph = {
|
|
101
|
+
* title: 'Transform Your Business with AI-Powered Analytics',
|
|
102
|
+
* description: 'Get real-time insights, automated reporting, and predictive analytics. Start free trial.',
|
|
103
|
+
* type: 'website',
|
|
104
|
+
* url: 'https://example.com/product',
|
|
105
|
+
* image: 'https://example.com/og-image-1200x630.jpg',
|
|
106
|
+
* imageAlt: 'Dashboard screenshot showing analytics graphs',
|
|
107
|
+
* siteName: 'Acme Analytics',
|
|
108
|
+
* locale: 'en_US'
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @see specs/app/pages/meta/social/open-graph.schema.json
|
|
113
|
+
*/
|
|
114
|
+
export const OpenGraphSchema = Schema.Struct({
|
|
115
|
+
title: Schema.optional(
|
|
116
|
+
Schema.String.pipe(Schema.maxLength(90)).annotations({
|
|
117
|
+
description: 'Open Graph title (may differ from page title)',
|
|
118
|
+
})
|
|
119
|
+
),
|
|
120
|
+
description: Schema.optional(
|
|
121
|
+
Schema.String.pipe(Schema.maxLength(200)).annotations({
|
|
122
|
+
description: 'Open Graph description',
|
|
123
|
+
})
|
|
124
|
+
),
|
|
125
|
+
type: Schema.optional(OpenGraphTypeSchema),
|
|
126
|
+
url: Schema.optional(
|
|
127
|
+
HttpUrlSchema.annotations({
|
|
128
|
+
description: 'Canonical URL for this page',
|
|
129
|
+
})
|
|
130
|
+
),
|
|
131
|
+
image: Schema.optional(
|
|
132
|
+
HttpUrlSchema.annotations({
|
|
133
|
+
description: 'Image URL for social sharing (recommended: 1200x630px)',
|
|
134
|
+
})
|
|
135
|
+
),
|
|
136
|
+
imageAlt: Schema.optional(
|
|
137
|
+
Schema.String.annotations({
|
|
138
|
+
description: 'Alternative text for the Open Graph image',
|
|
139
|
+
})
|
|
140
|
+
),
|
|
141
|
+
siteName: Schema.optional(
|
|
142
|
+
Schema.String.annotations({
|
|
143
|
+
description: 'Name of the overall website',
|
|
144
|
+
})
|
|
145
|
+
),
|
|
146
|
+
locale: Schema.optional(OpenGraphLocaleSchema),
|
|
147
|
+
determiner: Schema.optional(OpenGraphDeterminerSchema),
|
|
148
|
+
video: Schema.optional(
|
|
149
|
+
HttpUrlSchema.annotations({
|
|
150
|
+
description: 'Video URL if sharing video content',
|
|
151
|
+
})
|
|
152
|
+
),
|
|
153
|
+
audio: Schema.optional(
|
|
154
|
+
HttpUrlSchema.annotations({
|
|
155
|
+
description: 'Audio URL if sharing audio content',
|
|
156
|
+
})
|
|
157
|
+
),
|
|
158
|
+
}).annotations({
|
|
159
|
+
title: 'Open Graph Metadata',
|
|
160
|
+
description: 'Open Graph protocol metadata for rich social media sharing',
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
export type OpenGraphType = Schema.Schema.Type<typeof OpenGraphTypeSchema>
|
|
164
|
+
export type OpenGraphLocale = Schema.Schema.Type<typeof OpenGraphLocaleSchema>
|
|
165
|
+
export type OpenGraphDeterminer = Schema.Schema.Type<typeof OpenGraphDeterminerSchema>
|
|
166
|
+
export type OpenGraph = Schema.Schema.Type<typeof OpenGraphSchema>
|
|
@@ -0,0 +1,190 @@
|
|
|
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 { Schema } from 'effect'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resource type hint for preloading
|
|
12
|
+
*
|
|
13
|
+
* 8 standard resource types for <link rel="preload" as="...">:
|
|
14
|
+
* - style: CSS stylesheets (critical CSS for above-the-fold content)
|
|
15
|
+
* - script: JavaScript files (critical scripts needed for initial render)
|
|
16
|
+
* - font: Web fonts (WOFF2, WOFF, TTF) - requires crossorigin attribute
|
|
17
|
+
* - image: Images (hero images, above-the-fold images)
|
|
18
|
+
* - video: Video files
|
|
19
|
+
* - audio: Audio files
|
|
20
|
+
* - document: HTML documents (iframes, embeds)
|
|
21
|
+
* - fetch: API data (XHR, Fetch API responses) - prefetch critical API data
|
|
22
|
+
*/
|
|
23
|
+
export const PreloadResourceTypeSchema = Schema.Literal(
|
|
24
|
+
'style',
|
|
25
|
+
'script',
|
|
26
|
+
'font',
|
|
27
|
+
'image',
|
|
28
|
+
'video',
|
|
29
|
+
'audio',
|
|
30
|
+
'document',
|
|
31
|
+
'fetch'
|
|
32
|
+
).annotations({
|
|
33
|
+
description: 'Resource type hint',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* CORS setting for preloaded resources
|
|
38
|
+
*
|
|
39
|
+
* 3 options:
|
|
40
|
+
* - true: Anonymous CORS (no credentials) - most common for fonts
|
|
41
|
+
* - false: No CORS (same-origin)
|
|
42
|
+
* - 'anonymous': Explicit anonymous CORS (same as true)
|
|
43
|
+
* - 'use-credentials': CORS with credentials (cookies, auth)
|
|
44
|
+
*
|
|
45
|
+
* Important for fonts:
|
|
46
|
+
* - Web fonts MUST have crossorigin attribute (even from same origin)
|
|
47
|
+
* - Without crossorigin: font downloads twice (preload + actual request)
|
|
48
|
+
* - With crossorigin: font downloads once (preload is reused)
|
|
49
|
+
*/
|
|
50
|
+
export const PreloadCrossOriginSchema = Schema.Union(
|
|
51
|
+
Schema.Boolean,
|
|
52
|
+
Schema.Literal('anonymous', 'use-credentials')
|
|
53
|
+
).annotations({
|
|
54
|
+
description: 'CORS setting for the resource',
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Preload resource configuration
|
|
59
|
+
*
|
|
60
|
+
* Defines a single resource to preload early in page load for performance optimization.
|
|
61
|
+
*
|
|
62
|
+
* Required properties:
|
|
63
|
+
* - href: Resource URL to preload (absolute or relative path)
|
|
64
|
+
* - as: Resource type hint (style, script, font, image, video, audio, document, fetch)
|
|
65
|
+
*
|
|
66
|
+
* Optional properties:
|
|
67
|
+
* - type: MIME type (font/woff2, image/webp, text/css, etc.) - helps browser prioritize
|
|
68
|
+
* - crossorigin: CORS setting (true/false/'anonymous'/'use-credentials') - required for fonts
|
|
69
|
+
* - media: Media query for conditional loading (e.g., "(min-width: 768px)")
|
|
70
|
+
*
|
|
71
|
+
* Common preload patterns:
|
|
72
|
+
* 1. **Critical CSS**: Preload main stylesheet for faster first paint
|
|
73
|
+
* ```typescript
|
|
74
|
+
* { href: './output.css', as: 'style' }
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* 2. **Web fonts**: Preload fonts used above-the-fold (crossorigin required!)
|
|
78
|
+
* ```typescript
|
|
79
|
+
* { href: './fonts/MyFont.woff2', as: 'font', type: 'font/woff2', crossorigin: true }
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* 3. **Hero images**: Preload above-the-fold images for faster LCP
|
|
83
|
+
* ```typescript
|
|
84
|
+
* { href: './hero.jpg', as: 'image', type: 'image/jpeg' }
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* 4. **Critical API data**: Prefetch data needed for initial render
|
|
88
|
+
* ```typescript
|
|
89
|
+
* { href: '/api/posts', as: 'fetch', crossorigin: 'use-credentials' }
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* 5. **Responsive images**: Preload images conditionally based on screen size
|
|
93
|
+
* ```typescript
|
|
94
|
+
* { href: './hero-mobile.jpg', as: 'image', media: '(max-width: 767px)' }
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* Performance impact:
|
|
98
|
+
* - Preload critical resources before parser discovers them
|
|
99
|
+
* - Reduces time to First Contentful Paint (FCP) by 200-500ms
|
|
100
|
+
* - Reduces Largest Contentful Paint (LCP) by 300-800ms (hero images, fonts)
|
|
101
|
+
* - Improves Core Web Vitals (FCP, LCP, CLS)
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const preloadItem = {
|
|
106
|
+
* href: './fonts/Inter.woff2',
|
|
107
|
+
* as: 'font',
|
|
108
|
+
* type: 'font/woff2',
|
|
109
|
+
* crossorigin: true
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @see specs/app/pages/meta/performance/preload.schema.json
|
|
114
|
+
*/
|
|
115
|
+
export const PreloadItemSchema = Schema.Struct({
|
|
116
|
+
href: Schema.String.annotations({
|
|
117
|
+
description: 'Resource URL to preload',
|
|
118
|
+
}),
|
|
119
|
+
as: PreloadResourceTypeSchema,
|
|
120
|
+
type: Schema.optional(
|
|
121
|
+
Schema.String.annotations({
|
|
122
|
+
description: 'MIME type for the resource',
|
|
123
|
+
})
|
|
124
|
+
),
|
|
125
|
+
crossorigin: Schema.optional(PreloadCrossOriginSchema),
|
|
126
|
+
media: Schema.optional(
|
|
127
|
+
Schema.String.annotations({
|
|
128
|
+
description: 'Media query for conditional loading',
|
|
129
|
+
})
|
|
130
|
+
),
|
|
131
|
+
}).annotations({
|
|
132
|
+
description: 'Preload resource',
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Resource preloading for performance optimization
|
|
137
|
+
*
|
|
138
|
+
* Array of critical resources to preload early in page load.
|
|
139
|
+
* Improves First Contentful Paint (FCP) and Largest Contentful Paint (LCP)
|
|
140
|
+
* by fetching resources before the browser parser discovers them.
|
|
141
|
+
*
|
|
142
|
+
* How preload works:
|
|
143
|
+
* 1. Browser receives <link rel="preload" ...> in <head>
|
|
144
|
+
* 2. Browser downloads resource immediately (high priority)
|
|
145
|
+
* 3. Resource is cached in browser
|
|
146
|
+
* 4. When parser discovers resource later, it's already downloaded (instant load)
|
|
147
|
+
*
|
|
148
|
+
* What to preload:
|
|
149
|
+
* - **Critical CSS**: Main stylesheet for above-the-fold content
|
|
150
|
+
* - **Web fonts**: Fonts used above-the-fold (prevent FOIT/FOUT)
|
|
151
|
+
* - **Hero images**: Largest Contentful Paint (LCP) images
|
|
152
|
+
* - **Critical scripts**: JavaScript needed for initial render
|
|
153
|
+
* - **API data**: Critical data needed for first render
|
|
154
|
+
*
|
|
155
|
+
* What NOT to preload:
|
|
156
|
+
* - Resources below the fold (defer or lazy load instead)
|
|
157
|
+
* - Non-critical resources (wasted bandwidth, slows critical resources)
|
|
158
|
+
* - Too many resources (limit to 3-5 items, prioritize most critical)
|
|
159
|
+
*
|
|
160
|
+
* Performance metrics improved:
|
|
161
|
+
* - First Contentful Paint (FCP): 200-500ms faster
|
|
162
|
+
* - Largest Contentful Paint (LCP): 300-800ms faster
|
|
163
|
+
* - Cumulative Layout Shift (CLS): Reduced by preventing font swaps
|
|
164
|
+
* - Time to Interactive (TTI): Faster by preloading critical scripts
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const preload = [
|
|
169
|
+
* // Critical CSS
|
|
170
|
+
* { href: './output.css', as: 'style' },
|
|
171
|
+
* // Web font (crossorigin required!)
|
|
172
|
+
* { href: './fonts/Inter-Bold.woff2', as: 'font', type: 'font/woff2', crossorigin: true },
|
|
173
|
+
* // Hero image (LCP)
|
|
174
|
+
* { href: './hero.jpg', as: 'image', type: 'image/jpeg' },
|
|
175
|
+
* // Critical API data
|
|
176
|
+
* { href: '/api/posts', as: 'fetch', crossorigin: true }
|
|
177
|
+
* ]
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @see specs/app/pages/meta/performance/preload.schema.json
|
|
181
|
+
*/
|
|
182
|
+
export const PreloadSchema = Schema.Array(PreloadItemSchema).annotations({
|
|
183
|
+
title: 'Resource Preloading',
|
|
184
|
+
description: 'Preload critical resources for performance optimization',
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
export type PreloadResourceType = Schema.Schema.Type<typeof PreloadResourceTypeSchema>
|
|
188
|
+
export type PreloadCrossOrigin = Schema.Schema.Type<typeof PreloadCrossOriginSchema>
|
|
189
|
+
export type PreloadItem = Schema.Schema.Type<typeof PreloadItemSchema>
|
|
190
|
+
export type Preload = Schema.Schema.Type<typeof PreloadSchema>
|
|
@@ -0,0 +1,211 @@
|
|
|
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 { Schema } from 'effect'
|
|
9
|
+
import { SchemaOrgContext, schemaType } from './common-fields'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Article type
|
|
13
|
+
*
|
|
14
|
+
* 3 article types for different content:
|
|
15
|
+
* - Article: General articles (default, most common)
|
|
16
|
+
* - NewsArticle: News articles (journalistic content, breaking news)
|
|
17
|
+
* - BlogPosting: Blog posts (personal/company blogs, opinion pieces)
|
|
18
|
+
*/
|
|
19
|
+
export const ArticleTypeSchema = Schema.Literal(
|
|
20
|
+
'Article',
|
|
21
|
+
'NewsArticle',
|
|
22
|
+
'BlogPosting'
|
|
23
|
+
).annotations({
|
|
24
|
+
description: 'Article type',
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Article author
|
|
29
|
+
*
|
|
30
|
+
* Author can be either a simple string name or a structured Person/Organization object.
|
|
31
|
+
* - String: Simple author name (e.g., "John Doe")
|
|
32
|
+
* - Object: Structured author with @type (Person/Organization), name, and optional URL
|
|
33
|
+
*/
|
|
34
|
+
export const ArticleAuthorSchema = Schema.Union(
|
|
35
|
+
Schema.String,
|
|
36
|
+
Schema.Struct({
|
|
37
|
+
'@type': Schema.Literal('Person', 'Organization').annotations({
|
|
38
|
+
description: 'Author type',
|
|
39
|
+
}),
|
|
40
|
+
name: Schema.optional(
|
|
41
|
+
Schema.String.annotations({
|
|
42
|
+
description: 'Author name',
|
|
43
|
+
})
|
|
44
|
+
),
|
|
45
|
+
url: Schema.optional(
|
|
46
|
+
Schema.String.annotations({
|
|
47
|
+
description: 'Author profile URL',
|
|
48
|
+
format: 'uri',
|
|
49
|
+
})
|
|
50
|
+
),
|
|
51
|
+
})
|
|
52
|
+
).annotations({
|
|
53
|
+
description: 'Article author',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Publisher logo
|
|
58
|
+
*
|
|
59
|
+
* ImageObject with @type and url for publisher logo.
|
|
60
|
+
* Required for Article structured data to be eligible for rich results.
|
|
61
|
+
*/
|
|
62
|
+
export const PublisherLogoSchema = Schema.Struct({
|
|
63
|
+
'@type': schemaType('ImageObject'),
|
|
64
|
+
url: Schema.optional(
|
|
65
|
+
Schema.String.annotations({
|
|
66
|
+
description: 'Logo URL',
|
|
67
|
+
format: 'uri',
|
|
68
|
+
})
|
|
69
|
+
),
|
|
70
|
+
}).annotations({
|
|
71
|
+
description: 'Publisher logo',
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Article publisher
|
|
76
|
+
*
|
|
77
|
+
* Organization object representing the content publisher.
|
|
78
|
+
* - @type: "Organization" (required)
|
|
79
|
+
* - name: Publisher name (e.g., "Acme Blog", "TechCrunch")
|
|
80
|
+
* - logo: ImageObject with publisher logo URL
|
|
81
|
+
*/
|
|
82
|
+
export const ArticlePublisherSchema = Schema.Struct({
|
|
83
|
+
'@type': schemaType('Organization'),
|
|
84
|
+
name: Schema.optional(
|
|
85
|
+
Schema.String.annotations({
|
|
86
|
+
description: 'Publisher name',
|
|
87
|
+
})
|
|
88
|
+
),
|
|
89
|
+
logo: Schema.optional(PublisherLogoSchema),
|
|
90
|
+
}).annotations({
|
|
91
|
+
description: 'Article publisher',
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Schema.org Article structured data
|
|
96
|
+
*
|
|
97
|
+
* Represents articles, news articles, and blog posts for rich results in Google Search.
|
|
98
|
+
* Enables article cards with images, publication dates, and author attribution.
|
|
99
|
+
*
|
|
100
|
+
* Required properties:
|
|
101
|
+
* - @context: "https://schema.org" (Schema.org vocabulary)
|
|
102
|
+
* - @type: Article type (Article, NewsArticle, BlogPosting)
|
|
103
|
+
* - headline: Article title (shown in search results)
|
|
104
|
+
*
|
|
105
|
+
* Optional properties:
|
|
106
|
+
* - description: Article summary/excerpt
|
|
107
|
+
* - image: Article image URL (string) or array of image URLs (for carousel)
|
|
108
|
+
* - author: Author name (string) or structured Person/Organization object
|
|
109
|
+
* - datePublished: Publication date (ISO 8601 format)
|
|
110
|
+
* - dateModified: Last modification date (ISO 8601 format)
|
|
111
|
+
* - publisher: Publishing organization (Organization object with name and logo)
|
|
112
|
+
* - mainEntityOfPage: Canonical URL for the article
|
|
113
|
+
*
|
|
114
|
+
* Article types:
|
|
115
|
+
* - **Article**: General articles, how-to guides, tutorials
|
|
116
|
+
* - **NewsArticle**: Breaking news, journalism (adds publish date prominence)
|
|
117
|
+
* - **BlogPosting**: Personal/company blog posts, opinion pieces
|
|
118
|
+
*
|
|
119
|
+
* SEO impact:
|
|
120
|
+
* - **Rich results**: Article cards with image, headline, date, author in search
|
|
121
|
+
* - **Google News**: NewsArticle eligible for Google News (with additional requirements)
|
|
122
|
+
* - **Author attribution**: Links content to authors (E-E-A-T signals)
|
|
123
|
+
* - **Publisher branding**: Publisher logo and name shown in results
|
|
124
|
+
* - **Freshness signals**: datePublished and dateModified help ranking for time-sensitive queries
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const article = {
|
|
129
|
+
* "@context": "https://schema.org",
|
|
130
|
+
* "@type": "BlogPosting",
|
|
131
|
+
* headline: "10 Ways to Boost Productivity",
|
|
132
|
+
* description: "Proven strategies to improve your daily productivity",
|
|
133
|
+
* image: "https://example.com/article-image.jpg",
|
|
134
|
+
* author: {
|
|
135
|
+
* "@type": "Person",
|
|
136
|
+
* name: "John Doe",
|
|
137
|
+
* url: "https://example.com/author/johndoe"
|
|
138
|
+
* },
|
|
139
|
+
* datePublished: "2025-01-15T10:00:00Z",
|
|
140
|
+
* dateModified: "2025-01-20T14:30:00Z",
|
|
141
|
+
* publisher: {
|
|
142
|
+
* "@type": "Organization",
|
|
143
|
+
* name: "Acme Blog",
|
|
144
|
+
* logo: {
|
|
145
|
+
* "@type": "ImageObject",
|
|
146
|
+
* url: "https://example.com/logo.png"
|
|
147
|
+
* }
|
|
148
|
+
* },
|
|
149
|
+
* mainEntityOfPage: "https://example.com/blog/productivity-tips"
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @see specs/app/pages/meta/structured-data/article.schema.json
|
|
154
|
+
*/
|
|
155
|
+
export const ArticleSchema = Schema.Struct({
|
|
156
|
+
'@context': SchemaOrgContext,
|
|
157
|
+
'@type': ArticleTypeSchema,
|
|
158
|
+
headline: Schema.String.annotations({
|
|
159
|
+
description: 'Article title',
|
|
160
|
+
}),
|
|
161
|
+
description: Schema.optional(
|
|
162
|
+
Schema.String.annotations({
|
|
163
|
+
description: 'Article summary',
|
|
164
|
+
})
|
|
165
|
+
),
|
|
166
|
+
image: Schema.optional(
|
|
167
|
+
Schema.Union(
|
|
168
|
+
Schema.String.annotations({
|
|
169
|
+
description: 'Article image URL',
|
|
170
|
+
format: 'uri',
|
|
171
|
+
}),
|
|
172
|
+
Schema.Array(
|
|
173
|
+
Schema.String.annotations({
|
|
174
|
+
description: 'Article image URL',
|
|
175
|
+
format: 'uri',
|
|
176
|
+
})
|
|
177
|
+
)
|
|
178
|
+
).annotations({
|
|
179
|
+
description: 'Article image(s)',
|
|
180
|
+
})
|
|
181
|
+
),
|
|
182
|
+
author: Schema.optional(ArticleAuthorSchema),
|
|
183
|
+
datePublished: Schema.optional(
|
|
184
|
+
Schema.String.annotations({
|
|
185
|
+
description: 'Publication date',
|
|
186
|
+
format: 'date-time',
|
|
187
|
+
})
|
|
188
|
+
),
|
|
189
|
+
dateModified: Schema.optional(
|
|
190
|
+
Schema.String.annotations({
|
|
191
|
+
description: 'Last modification date',
|
|
192
|
+
format: 'date-time',
|
|
193
|
+
})
|
|
194
|
+
),
|
|
195
|
+
publisher: Schema.optional(ArticlePublisherSchema),
|
|
196
|
+
mainEntityOfPage: Schema.optional(
|
|
197
|
+
Schema.String.annotations({
|
|
198
|
+
description: "Article's canonical URL",
|
|
199
|
+
format: 'uri',
|
|
200
|
+
})
|
|
201
|
+
),
|
|
202
|
+
}).annotations({
|
|
203
|
+
title: 'Article Schema',
|
|
204
|
+
description: 'Schema.org Article structured data',
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
export type ArticleType = Schema.Schema.Type<typeof ArticleTypeSchema>
|
|
208
|
+
export type ArticleAuthor = Schema.Schema.Type<typeof ArticleAuthorSchema>
|
|
209
|
+
export type PublisherLogo = Schema.Schema.Type<typeof PublisherLogoSchema>
|
|
210
|
+
export type ArticlePublisher = Schema.Schema.Type<typeof ArticlePublisherSchema>
|
|
211
|
+
export type Article = Schema.Schema.Type<typeof ArticleSchema>
|
|
@@ -0,0 +1,115 @@
|
|
|
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 { Schema } from 'effect'
|
|
9
|
+
import { SchemaOrgContext, schemaType, positiveInt } from './common-fields'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Breadcrumb list item
|
|
13
|
+
*
|
|
14
|
+
* Represents a single breadcrumb in the navigation trail.
|
|
15
|
+
*
|
|
16
|
+
* Required properties:
|
|
17
|
+
* - @type: "ListItem" (Schema.org type identifier)
|
|
18
|
+
* - position: Item position in breadcrumb trail (starts at 1)
|
|
19
|
+
* - name: Human-readable breadcrumb label (e.g., "Home", "Products", "Widget")
|
|
20
|
+
*
|
|
21
|
+
* Optional properties:
|
|
22
|
+
* - item: URL to the breadcrumb page (clickable link)
|
|
23
|
+
*/
|
|
24
|
+
export const BreadcrumbListItemSchema = Schema.Struct({
|
|
25
|
+
'@type': schemaType('ListItem'),
|
|
26
|
+
position: positiveInt('Item position in breadcrumb trail'),
|
|
27
|
+
name: Schema.String.annotations({
|
|
28
|
+
description: 'Breadcrumb label',
|
|
29
|
+
}),
|
|
30
|
+
item: Schema.optional(
|
|
31
|
+
Schema.String.annotations({
|
|
32
|
+
description: 'URL to the breadcrumb page',
|
|
33
|
+
format: 'uri',
|
|
34
|
+
})
|
|
35
|
+
),
|
|
36
|
+
}).annotations({
|
|
37
|
+
description: 'Breadcrumb list item',
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Schema.org BreadcrumbList structured data
|
|
42
|
+
*
|
|
43
|
+
* Represents the navigation path (breadcrumb trail) showing the page's position
|
|
44
|
+
* in the site hierarchy. Displayed in Google search results as a breadcrumb trail
|
|
45
|
+
* instead of the full URL, improving click-through rates.
|
|
46
|
+
*
|
|
47
|
+
* Required properties:
|
|
48
|
+
* - @context: "https://schema.org" (Schema.org vocabulary)
|
|
49
|
+
* - @type: "BreadcrumbList" (Schema.org type identifier)
|
|
50
|
+
* - itemListElement: Array of breadcrumb items (ListItem objects)
|
|
51
|
+
*
|
|
52
|
+
* Breadcrumb structure:
|
|
53
|
+
* - Each item has @type "ListItem", position (integer starting at 1), name, and optional item URL
|
|
54
|
+
* - Position determines order: 1 = Home, 2 = Category, 3 = Subcategory, etc.
|
|
55
|
+
* - Name is the human-readable label shown in breadcrumb trail
|
|
56
|
+
* - Item URL is optional but recommended for clickable breadcrumbs
|
|
57
|
+
*
|
|
58
|
+
* Common patterns:
|
|
59
|
+
* - **Home > Category > Page**: 3-level hierarchy for content sites
|
|
60
|
+
* - **Home > Products > Category > Product**: 4-level for e-commerce
|
|
61
|
+
* - **Home > Docs > Section > Article**: 4-level for documentation
|
|
62
|
+
*
|
|
63
|
+
* SEO impact:
|
|
64
|
+
* - **Rich results**: Breadcrumb trail replaces URL in Google search results
|
|
65
|
+
* - **Site structure**: Helps search engines understand site architecture
|
|
66
|
+
* - **Navigation UX**: Users see page context in search results (higher CTR)
|
|
67
|
+
* - **Mobile optimization**: Breadcrumbs save space vs full URL on mobile
|
|
68
|
+
*
|
|
69
|
+
* Google display example:
|
|
70
|
+
* - Without breadcrumbs: "https://example.com/products/electronics/laptop"
|
|
71
|
+
* - With breadcrumbs: "Home › Products › Electronics › Laptop"
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const breadcrumb = {
|
|
76
|
+
* "@context": "https://schema.org",
|
|
77
|
+
* "@type": "BreadcrumbList",
|
|
78
|
+
* itemListElement: [
|
|
79
|
+
* {
|
|
80
|
+
* "@type": "ListItem",
|
|
81
|
+
* position: 1,
|
|
82
|
+
* name: "Home",
|
|
83
|
+
* item: "https://example.com"
|
|
84
|
+
* },
|
|
85
|
+
* {
|
|
86
|
+
* "@type": "ListItem",
|
|
87
|
+
* position: 2,
|
|
88
|
+
* name: "Products",
|
|
89
|
+
* item: "https://example.com/products"
|
|
90
|
+
* },
|
|
91
|
+
* {
|
|
92
|
+
* "@type": "ListItem",
|
|
93
|
+
* position: 3,
|
|
94
|
+
* name: "Widget",
|
|
95
|
+
* item: "https://example.com/products/widget"
|
|
96
|
+
* }
|
|
97
|
+
* ]
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @see specs/app/pages/meta/structured-data/breadcrumb.schema.json
|
|
102
|
+
*/
|
|
103
|
+
export const BreadcrumbSchema = Schema.Struct({
|
|
104
|
+
'@context': SchemaOrgContext,
|
|
105
|
+
'@type': schemaType('BreadcrumbList'),
|
|
106
|
+
itemListElement: Schema.Array(BreadcrumbListItemSchema).annotations({
|
|
107
|
+
description: 'Array of breadcrumb items',
|
|
108
|
+
}),
|
|
109
|
+
}).annotations({
|
|
110
|
+
title: 'Breadcrumb Schema',
|
|
111
|
+
description: 'Schema.org BreadcrumbList structured data',
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
export type BreadcrumbListItem = Schema.Schema.Type<typeof BreadcrumbListItemSchema>
|
|
115
|
+
export type Breadcrumb = Schema.Schema.Type<typeof BreadcrumbSchema>
|