@htmless/core 0.1.0
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/dist/ai/content-operations.d.ts +26 -0
- package/dist/ai/content-operations.d.ts.map +1 -0
- package/dist/ai/content-operations.js +75 -0
- package/dist/ai/content-operations.js.map +1 -0
- package/dist/ai/image-analyzer.d.ts +18 -0
- package/dist/ai/image-analyzer.d.ts.map +1 -0
- package/dist/ai/image-analyzer.js +457 -0
- package/dist/ai/image-analyzer.js.map +1 -0
- package/dist/ai/json-to-schema.d.ts +6 -0
- package/dist/ai/json-to-schema.d.ts.map +1 -0
- package/dist/ai/json-to-schema.js +155 -0
- package/dist/ai/json-to-schema.js.map +1 -0
- package/dist/ai/schema-generator.d.ts +34 -0
- package/dist/ai/schema-generator.d.ts.map +1 -0
- package/dist/ai/schema-generator.js +307 -0
- package/dist/ai/schema-generator.js.map +1 -0
- package/dist/api/cda/assets.d.ts +4 -0
- package/dist/api/cda/assets.d.ts.map +1 -0
- package/dist/api/cda/assets.js +82 -0
- package/dist/api/cda/assets.js.map +1 -0
- package/dist/api/cda/blocks.d.ts +4 -0
- package/dist/api/cda/blocks.d.ts.map +1 -0
- package/dist/api/cda/blocks.js +92 -0
- package/dist/api/cda/blocks.js.map +1 -0
- package/dist/api/cda/content.d.ts +4 -0
- package/dist/api/cda/content.d.ts.map +1 -0
- package/dist/api/cda/content.js +192 -0
- package/dist/api/cda/content.js.map +1 -0
- package/dist/api/cda/index.d.ts +4 -0
- package/dist/api/cda/index.d.ts.map +1 -0
- package/dist/api/cda/index.js +21 -0
- package/dist/api/cda/index.js.map +1 -0
- package/dist/api/cda/media.d.ts +4 -0
- package/dist/api/cda/media.d.ts.map +1 -0
- package/dist/api/cda/media.js +114 -0
- package/dist/api/cda/media.js.map +1 -0
- package/dist/api/cda/redirects.d.ts +4 -0
- package/dist/api/cda/redirects.d.ts.map +1 -0
- package/dist/api/cda/redirects.js +69 -0
- package/dist/api/cda/redirects.js.map +1 -0
- package/dist/api/cda/schemas.d.ts +4 -0
- package/dist/api/cda/schemas.d.ts.map +1 -0
- package/dist/api/cda/schemas.js +113 -0
- package/dist/api/cda/schemas.js.map +1 -0
- package/dist/api/cda/taxonomies.d.ts +4 -0
- package/dist/api/cda/taxonomies.d.ts.map +1 -0
- package/dist/api/cda/taxonomies.js +79 -0
- package/dist/api/cda/taxonomies.js.map +1 -0
- package/dist/api/cma/ai.d.ts +4 -0
- package/dist/api/cma/ai.d.ts.map +1 -0
- package/dist/api/cma/ai.js +458 -0
- package/dist/api/cma/ai.js.map +1 -0
- package/dist/api/cma/assets.d.ts +4 -0
- package/dist/api/cma/assets.d.ts.map +1 -0
- package/dist/api/cma/assets.js +166 -0
- package/dist/api/cma/assets.js.map +1 -0
- package/dist/api/cma/audit.d.ts +4 -0
- package/dist/api/cma/audit.d.ts.map +1 -0
- package/dist/api/cma/audit.js +74 -0
- package/dist/api/cma/audit.js.map +1 -0
- package/dist/api/cma/auth.d.ts +4 -0
- package/dist/api/cma/auth.d.ts.map +1 -0
- package/dist/api/cma/auth.js +123 -0
- package/dist/api/cma/auth.js.map +1 -0
- package/dist/api/cma/blocks.d.ts +4 -0
- package/dist/api/cma/blocks.d.ts.map +1 -0
- package/dist/api/cma/blocks.js +249 -0
- package/dist/api/cma/blocks.js.map +1 -0
- package/dist/api/cma/bulk.d.ts +4 -0
- package/dist/api/cma/bulk.d.ts.map +1 -0
- package/dist/api/cma/bulk.js +258 -0
- package/dist/api/cma/bulk.js.map +1 -0
- package/dist/api/cma/cache.d.ts +4 -0
- package/dist/api/cma/cache.d.ts.map +1 -0
- package/dist/api/cma/cache.js +99 -0
- package/dist/api/cma/cache.js.map +1 -0
- package/dist/api/cma/codegen.d.ts +4 -0
- package/dist/api/cma/codegen.d.ts.map +1 -0
- package/dist/api/cma/codegen.js +22 -0
- package/dist/api/cma/codegen.js.map +1 -0
- package/dist/api/cma/comments.d.ts +4 -0
- package/dist/api/cma/comments.d.ts.map +1 -0
- package/dist/api/cma/comments.js +164 -0
- package/dist/api/cma/comments.js.map +1 -0
- package/dist/api/cma/diff.d.ts +4 -0
- package/dist/api/cma/diff.d.ts.map +1 -0
- package/dist/api/cma/diff.js +88 -0
- package/dist/api/cma/diff.js.map +1 -0
- package/dist/api/cma/entries.d.ts +4 -0
- package/dist/api/cma/entries.d.ts.map +1 -0
- package/dist/api/cma/entries.js +736 -0
- package/dist/api/cma/entries.js.map +1 -0
- package/dist/api/cma/environments.d.ts +4 -0
- package/dist/api/cma/environments.d.ts.map +1 -0
- package/dist/api/cma/environments.js +160 -0
- package/dist/api/cma/environments.js.map +1 -0
- package/dist/api/cma/extensions.d.ts +4 -0
- package/dist/api/cma/extensions.d.ts.map +1 -0
- package/dist/api/cma/extensions.js +82 -0
- package/dist/api/cma/extensions.js.map +1 -0
- package/dist/api/cma/importexport.d.ts +4 -0
- package/dist/api/cma/importexport.d.ts.map +1 -0
- package/dist/api/cma/importexport.js +496 -0
- package/dist/api/cma/importexport.js.map +1 -0
- package/dist/api/cma/index.d.ts +4 -0
- package/dist/api/cma/index.d.ts.map +1 -0
- package/dist/api/cma/index.js +69 -0
- package/dist/api/cma/index.js.map +1 -0
- package/dist/api/cma/live.d.ts +4 -0
- package/dist/api/cma/live.d.ts.map +1 -0
- package/dist/api/cma/live.js +64 -0
- package/dist/api/cma/live.js.map +1 -0
- package/dist/api/cma/locales.d.ts +4 -0
- package/dist/api/cma/locales.d.ts.map +1 -0
- package/dist/api/cma/locales.js +117 -0
- package/dist/api/cma/locales.js.map +1 -0
- package/dist/api/cma/marketplace.d.ts +4 -0
- package/dist/api/cma/marketplace.d.ts.map +1 -0
- package/dist/api/cma/marketplace.js +550 -0
- package/dist/api/cma/marketplace.js.map +1 -0
- package/dist/api/cma/redirects.d.ts +4 -0
- package/dist/api/cma/redirects.d.ts.map +1 -0
- package/dist/api/cma/redirects.js +120 -0
- package/dist/api/cma/redirects.js.map +1 -0
- package/dist/api/cma/relationships.d.ts +4 -0
- package/dist/api/cma/relationships.d.ts.map +1 -0
- package/dist/api/cma/relationships.js +47 -0
- package/dist/api/cma/relationships.js.map +1 -0
- package/dist/api/cma/schemas.d.ts +4 -0
- package/dist/api/cma/schemas.d.ts.map +1 -0
- package/dist/api/cma/schemas.js +248 -0
- package/dist/api/cma/schemas.js.map +1 -0
- package/dist/api/cma/search.d.ts +4 -0
- package/dist/api/cma/search.d.ts.map +1 -0
- package/dist/api/cma/search.js +149 -0
- package/dist/api/cma/search.js.map +1 -0
- package/dist/api/cma/spaces.d.ts +4 -0
- package/dist/api/cma/spaces.d.ts.map +1 -0
- package/dist/api/cma/spaces.js +119 -0
- package/dist/api/cma/spaces.js.map +1 -0
- package/dist/api/cma/taxonomies.d.ts +4 -0
- package/dist/api/cma/taxonomies.d.ts.map +1 -0
- package/dist/api/cma/taxonomies.js +296 -0
- package/dist/api/cma/taxonomies.js.map +1 -0
- package/dist/api/cma/templates.d.ts +13 -0
- package/dist/api/cma/templates.d.ts.map +1 -0
- package/dist/api/cma/templates.js +312 -0
- package/dist/api/cma/templates.js.map +1 -0
- package/dist/api/cma/uploads.d.ts +4 -0
- package/dist/api/cma/uploads.d.ts.map +1 -0
- package/dist/api/cma/uploads.js +148 -0
- package/dist/api/cma/uploads.js.map +1 -0
- package/dist/api/cma/webhooks.d.ts +4 -0
- package/dist/api/cma/webhooks.d.ts.map +1 -0
- package/dist/api/cma/webhooks.js +175 -0
- package/dist/api/cma/webhooks.js.map +1 -0
- package/dist/api/cma/white-label.d.ts +4 -0
- package/dist/api/cma/white-label.d.ts.map +1 -0
- package/dist/api/cma/white-label.js +47 -0
- package/dist/api/cma/white-label.js.map +1 -0
- package/dist/api/graphql/index.d.ts +4 -0
- package/dist/api/graphql/index.d.ts.map +1 -0
- package/dist/api/graphql/index.js +57 -0
- package/dist/api/graphql/index.js.map +1 -0
- package/dist/api/graphql/introspection.d.ts +31 -0
- package/dist/api/graphql/introspection.d.ts.map +1 -0
- package/dist/api/graphql/introspection.js +90 -0
- package/dist/api/graphql/introspection.js.map +1 -0
- package/dist/api/graphql/parser.d.ts +14 -0
- package/dist/api/graphql/parser.d.ts.map +1 -0
- package/dist/api/graphql/parser.js +140 -0
- package/dist/api/graphql/parser.js.map +1 -0
- package/dist/api/graphql/resolver.d.ts +3 -0
- package/dist/api/graphql/resolver.d.ts.map +1 -0
- package/dist/api/graphql/resolver.js +138 -0
- package/dist/api/graphql/resolver.js.map +1 -0
- package/dist/api/preview/content.d.ts +4 -0
- package/dist/api/preview/content.d.ts.map +1 -0
- package/dist/api/preview/content.js +207 -0
- package/dist/api/preview/content.js.map +1 -0
- package/dist/api/preview/index.d.ts +4 -0
- package/dist/api/preview/index.d.ts.map +1 -0
- package/dist/api/preview/index.js +11 -0
- package/dist/api/preview/index.js.map +1 -0
- package/dist/api/preview/live.d.ts +4 -0
- package/dist/api/preview/live.d.ts.map +1 -0
- package/dist/api/preview/live.js +41 -0
- package/dist/api/preview/live.js.map +1 -0
- package/dist/audit/logger.d.ts +13 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/logger.js +21 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/audit/middleware.d.ts +7 -0
- package/dist/audit/middleware.d.ts.map +1 -0
- package/dist/audit/middleware.js +39 -0
- package/dist/audit/middleware.js.map +1 -0
- package/dist/auth/jwt.d.ts +9 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +15 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +24 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +99 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/password.d.ts +3 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +9 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/rate-limit.d.ts +19 -0
- package/dist/auth/rate-limit.d.ts.map +1 -0
- package/dist/auth/rate-limit.js +77 -0
- package/dist/auth/rate-limit.js.map +1 -0
- package/dist/auth/rbac.d.ts +10 -0
- package/dist/auth/rbac.d.ts.map +1 -0
- package/dist/auth/rbac.js +61 -0
- package/dist/auth/rbac.js.map +1 -0
- package/dist/blocks/core-blocks.d.ts +13 -0
- package/dist/blocks/core-blocks.d.ts.map +1 -0
- package/dist/blocks/core-blocks.js +113 -0
- package/dist/blocks/core-blocks.js.map +1 -0
- package/dist/blocks/renderer-sdk.d.ts +75 -0
- package/dist/blocks/renderer-sdk.d.ts.map +1 -0
- package/dist/blocks/renderer-sdk.js +112 -0
- package/dist/blocks/renderer-sdk.js.map +1 -0
- package/dist/blocks/seed-core-blocks.d.ts +6 -0
- package/dist/blocks/seed-core-blocks.d.ts.map +1 -0
- package/dist/blocks/seed-core-blocks.js +37 -0
- package/dist/blocks/seed-core-blocks.js.map +1 -0
- package/dist/blocks/validator.d.ts +10 -0
- package/dist/blocks/validator.d.ts.map +1 -0
- package/dist/blocks/validator.js +111 -0
- package/dist/blocks/validator.js.map +1 -0
- package/dist/cache/cdn-purge.d.ts +41 -0
- package/dist/cache/cdn-purge.d.ts.map +1 -0
- package/dist/cache/cdn-purge.js +180 -0
- package/dist/cache/cdn-purge.js.map +1 -0
- package/dist/cache/observability.d.ts +36 -0
- package/dist/cache/observability.d.ts.map +1 -0
- package/dist/cache/observability.js +110 -0
- package/dist/cache/observability.js.map +1 -0
- package/dist/cache/tags.d.ts +28 -0
- package/dist/cache/tags.d.ts.map +1 -0
- package/dist/cache/tags.js +94 -0
- package/dist/cache/tags.js.map +1 -0
- package/dist/cli/commands/codegen.d.ts +2 -0
- package/dist/cli/commands/codegen.d.ts.map +1 -0
- package/dist/cli/commands/codegen.js +73 -0
- package/dist/cli/commands/codegen.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +2 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +60 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/help.d.ts +2 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +32 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +90 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +2 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +27 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/seed.d.ts +2 -0
- package/dist/cli/commands/seed.d.ts.map +1 -0
- package/dist/cli/commands/seed.js +28 -0
- package/dist/cli/commands/seed.js.map +1 -0
- package/dist/cli/index.d.ts +16 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +120 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/content/advanced-query.d.ts +37 -0
- package/dist/content/advanced-query.d.ts.map +1 -0
- package/dist/content/advanced-query.js +162 -0
- package/dist/content/advanced-query.js.map +1 -0
- package/dist/content/cache.d.ts +27 -0
- package/dist/content/cache.d.ts.map +1 -0
- package/dist/content/cache.js +100 -0
- package/dist/content/cache.js.map +1 -0
- package/dist/content/diff.d.ts +13 -0
- package/dist/content/diff.d.ts.map +1 -0
- package/dist/content/diff.js +80 -0
- package/dist/content/diff.js.map +1 -0
- package/dist/content/localization.d.ts +13 -0
- package/dist/content/localization.d.ts.map +1 -0
- package/dist/content/localization.js +42 -0
- package/dist/content/localization.js.map +1 -0
- package/dist/content/materializer.d.ts +26 -0
- package/dist/content/materializer.d.ts.map +1 -0
- package/dist/content/materializer.js +175 -0
- package/dist/content/materializer.js.map +1 -0
- package/dist/content/relationships.d.ts +30 -0
- package/dist/content/relationships.d.ts.map +1 -0
- package/dist/content/relationships.js +123 -0
- package/dist/content/relationships.js.map +1 -0
- package/dist/db.d.ts +5 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +5 -0
- package/dist/db.js.map +1 -0
- package/dist/events/emitter.d.ts +16 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/emitter.js +15 -0
- package/dist/events/emitter.js.map +1 -0
- package/dist/events/sse.d.ts +16 -0
- package/dist/events/sse.d.ts.map +1 -0
- package/dist/events/sse.js +37 -0
- package/dist/events/sse.js.map +1 -0
- package/dist/events/wire.d.ts +2 -0
- package/dist/events/wire.d.ts.map +1 -0
- package/dist/events/wire.js +27 -0
- package/dist/events/wire.js.map +1 -0
- package/dist/extensions/billing.d.ts +60 -0
- package/dist/extensions/billing.d.ts.map +1 -0
- package/dist/extensions/billing.js +98 -0
- package/dist/extensions/billing.js.map +1 -0
- package/dist/extensions/manifest.d.ts +43 -0
- package/dist/extensions/manifest.d.ts.map +1 -0
- package/dist/extensions/manifest.js +66 -0
- package/dist/extensions/manifest.js.map +1 -0
- package/dist/extensions/marketplace.d.ts +50 -0
- package/dist/extensions/marketplace.d.ts.map +1 -0
- package/dist/extensions/marketplace.js +676 -0
- package/dist/extensions/marketplace.js.map +1 -0
- package/dist/extensions/router.d.ts +4 -0
- package/dist/extensions/router.d.ts.map +1 -0
- package/dist/extensions/router.js +50 -0
- package/dist/extensions/router.js.map +1 -0
- package/dist/extensions/runtime.d.ts +29 -0
- package/dist/extensions/runtime.d.ts.map +1 -0
- package/dist/extensions/runtime.js +201 -0
- package/dist/extensions/runtime.js.map +1 -0
- package/dist/extensions/sdk.d.ts +146 -0
- package/dist/extensions/sdk.d.ts.map +1 -0
- package/dist/extensions/sdk.js +114 -0
- package/dist/extensions/sdk.js.map +1 -0
- package/dist/integrations/sheets.d.ts +41 -0
- package/dist/integrations/sheets.d.ts.map +1 -0
- package/dist/integrations/sheets.js +230 -0
- package/dist/integrations/sheets.js.map +1 -0
- package/dist/media/metadata.d.ts +9 -0
- package/dist/media/metadata.d.ts.map +1 -0
- package/dist/media/metadata.js +84 -0
- package/dist/media/metadata.js.map +1 -0
- package/dist/media/presets.d.ts +17 -0
- package/dist/media/presets.d.ts.map +1 -0
- package/dist/media/presets.js +21 -0
- package/dist/media/presets.js.map +1 -0
- package/dist/media/storage.d.ts +16 -0
- package/dist/media/storage.d.ts.map +1 -0
- package/dist/media/storage.js +39 -0
- package/dist/media/storage.js.map +1 -0
- package/dist/media/transforms-engine.d.ts +46 -0
- package/dist/media/transforms-engine.d.ts.map +1 -0
- package/dist/media/transforms-engine.js +91 -0
- package/dist/media/transforms-engine.js.map +1 -0
- package/dist/media/transforms.d.ts +15 -0
- package/dist/media/transforms.d.ts.map +1 -0
- package/dist/media/transforms.js +22 -0
- package/dist/media/transforms.js.map +1 -0
- package/dist/media/usage.d.ts +21 -0
- package/dist/media/usage.d.ts.map +1 -0
- package/dist/media/usage.js +105 -0
- package/dist/media/usage.js.map +1 -0
- package/dist/redis.d.ts +2 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +9 -0
- package/dist/redis.js.map +1 -0
- package/dist/schema/codegen.d.ts +6 -0
- package/dist/schema/codegen.d.ts.map +1 -0
- package/dist/schema/codegen.js +95 -0
- package/dist/schema/codegen.js.map +1 -0
- package/dist/schema/json-schema.d.ts +42 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +68 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/validator.d.ts +14 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +103 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/sdk/client.d.ts +86 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +117 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +59 -0
- package/dist/server.js.map +1 -0
- package/dist/spaces/premium-templates.d.ts +37 -0
- package/dist/spaces/premium-templates.d.ts.map +1 -0
- package/dist/spaces/premium-templates.js +1603 -0
- package/dist/spaces/premium-templates.js.map +1 -0
- package/dist/spaces/provisioner.d.ts +16 -0
- package/dist/spaces/provisioner.d.ts.map +1 -0
- package/dist/spaces/provisioner.js +143 -0
- package/dist/spaces/provisioner.js.map +1 -0
- package/dist/spaces/template-registry.d.ts +34 -0
- package/dist/spaces/template-registry.d.ts.map +1 -0
- package/dist/spaces/template-registry.js +55 -0
- package/dist/spaces/template-registry.js.map +1 -0
- package/dist/spaces/templates.d.ts +44 -0
- package/dist/spaces/templates.d.ts.map +1 -0
- package/dist/spaces/templates.js +201 -0
- package/dist/spaces/templates.js.map +1 -0
- package/dist/spaces/white-label.d.ts +20 -0
- package/dist/spaces/white-label.d.ts.map +1 -0
- package/dist/spaces/white-label.js +32 -0
- package/dist/spaces/white-label.js.map +1 -0
- package/dist/utils/query-shaping.d.ts +27 -0
- package/dist/utils/query-shaping.d.ts.map +1 -0
- package/dist/utils/query-shaping.js +69 -0
- package/dist/utils/query-shaping.js.map +1 -0
- package/dist/utils/space.d.ts +4 -0
- package/dist/utils/space.d.ts.map +1 -0
- package/dist/utils/space.js +17 -0
- package/dist/utils/space.js.map +1 -0
- package/dist/webhooks/dispatcher.d.ts +9 -0
- package/dist/webhooks/dispatcher.d.ts.map +1 -0
- package/dist/webhooks/dispatcher.js +102 -0
- package/dist/webhooks/dispatcher.js.map +1 -0
- package/package.json +84 -0
- package/prisma/migrations/20260403025542_init/migration.sql +315 -0
- package/prisma/migrations/20260403034855_add_blocks_and_patterns/migration.sql +40 -0
- package/prisma/migrations/20260403041936_add_published_documents/migration.sql +30 -0
- package/prisma/migrations/20260403042809_add_locales_and_taxonomies/migration.sql +58 -0
- package/prisma/migrations/20260403043033_add_scheduled_unpublish_at/migration.sql +2 -0
- package/prisma/migrations/20260403052801_add_environments_and_whitelabel/migration.sql +65 -0
- package/prisma/migrations/20260403055920_add_marketplace_and_extension_config/migration.sql +73 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +530 -0
- package/prisma/seed.ts +154 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { verifyJwt } from './jwt.js';
|
|
2
|
+
import { prisma } from '../db.js';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
function hashToken(token) {
|
|
5
|
+
return createHash('sha256').update(token).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
export function authenticate(options = {}) {
|
|
8
|
+
const { required = true, allowPreview = false, allowQueryToken = false } = options;
|
|
9
|
+
return async (req, res, next) => {
|
|
10
|
+
const authHeader = req.headers.authorization;
|
|
11
|
+
// Support ?token= query param for SSE (EventSource can't set headers)
|
|
12
|
+
const queryToken = allowQueryToken ? req.query['token'] : undefined;
|
|
13
|
+
if (!authHeader && !queryToken) {
|
|
14
|
+
if (required) {
|
|
15
|
+
res.status(401).json({ error: 'authentication_required', message: 'Bearer token required' });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
next();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const token = queryToken ?? authHeader.replace('Bearer ', '');
|
|
22
|
+
// Try API token (hle_ prefix)
|
|
23
|
+
if (token.startsWith('hle_')) {
|
|
24
|
+
const tokenHash = hashToken(token);
|
|
25
|
+
const apiToken = await prisma.apiToken.findUnique({
|
|
26
|
+
where: { tokenHash },
|
|
27
|
+
});
|
|
28
|
+
if (!apiToken || (apiToken.expiresAt && apiToken.expiresAt < new Date())) {
|
|
29
|
+
res.status(401).json({ error: 'invalid_token', message: 'Invalid or expired API token' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await prisma.apiToken.update({ where: { id: apiToken.id }, data: { lastUsedAt: new Date() } });
|
|
33
|
+
req.auth = {
|
|
34
|
+
userId: apiToken.createdById,
|
|
35
|
+
email: '',
|
|
36
|
+
type: 'api_token',
|
|
37
|
+
scopes: apiToken.scopes,
|
|
38
|
+
spaceId: apiToken.spaceId,
|
|
39
|
+
};
|
|
40
|
+
next();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Try preview token (hlp_ prefix)
|
|
44
|
+
if (allowPreview && token.startsWith('hlp_')) {
|
|
45
|
+
const tokenHash = hashToken(token);
|
|
46
|
+
const previewToken = await prisma.previewToken.findUnique({
|
|
47
|
+
where: { tokenHash },
|
|
48
|
+
});
|
|
49
|
+
if (!previewToken || previewToken.expiresAt < new Date()) {
|
|
50
|
+
res.status(401).json({ error: 'invalid_token', message: 'Invalid or expired preview token' });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
req.auth = {
|
|
54
|
+
userId: previewToken.createdById,
|
|
55
|
+
email: '',
|
|
56
|
+
type: 'preview_token',
|
|
57
|
+
spaceId: previewToken.spaceId,
|
|
58
|
+
previewEntryId: previewToken.entryId,
|
|
59
|
+
previewRoute: previewToken.route,
|
|
60
|
+
};
|
|
61
|
+
next();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Try JWT (user session)
|
|
65
|
+
try {
|
|
66
|
+
const payload = await verifyJwt(token);
|
|
67
|
+
req.auth = {
|
|
68
|
+
userId: payload.sub,
|
|
69
|
+
email: payload.email,
|
|
70
|
+
type: 'user',
|
|
71
|
+
};
|
|
72
|
+
next();
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
res.status(401).json({ error: 'invalid_token', message: 'Invalid or expired JWT' });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function requireScope(...scopes) {
|
|
80
|
+
return (req, res, next) => {
|
|
81
|
+
if (!req.auth) {
|
|
82
|
+
res.status(401).json({ error: 'authentication_required' });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (req.auth.type === 'user') {
|
|
86
|
+
next();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (req.auth.scopes) {
|
|
90
|
+
const hasScope = scopes.some(s => req.auth.scopes.includes(s));
|
|
91
|
+
if (hasScope) {
|
|
92
|
+
next();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
res.status(403).json({ error: 'insufficient_scope', message: `Requires one of: ${scopes.join(', ')}` });
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAErF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import bcrypt from 'bcryptjs';
|
|
2
|
+
const SALT_ROUNDS = 12;
|
|
3
|
+
export async function hashPassword(password) {
|
|
4
|
+
return bcrypt.hash(password, SALT_ROUNDS);
|
|
5
|
+
}
|
|
6
|
+
export async function verifyPassword(password, hash) {
|
|
7
|
+
return bcrypt.compare(password, hash);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAY;IACjE,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
interface RateLimiterOptions {
|
|
3
|
+
windowMs: number;
|
|
4
|
+
maxRequests: number;
|
|
5
|
+
keyFn?: (req: Request) => string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* In-memory sliding-window rate limiter.
|
|
9
|
+
* Uses a Map with periodic cleanup to avoid unbounded memory growth.
|
|
10
|
+
*/
|
|
11
|
+
export declare function rateLimiter(options: RateLimiterOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
12
|
+
/** 10 attempts per minute per IP — for login routes */
|
|
13
|
+
export declare const loginRateLimiter: (req: Request, res: Response, next: NextFunction) => void;
|
|
14
|
+
/** 1000 requests per minute per token/IP — for general CMA API */
|
|
15
|
+
export declare const apiRateLimiter: (req: Request, res: Response, next: NextFunction) => void;
|
|
16
|
+
/** 20 uploads per minute per token — for upload routes */
|
|
17
|
+
export declare const uploadRateLimiter: (req: Request, res: Response, next: NextFunction) => void;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/auth/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO/D,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,IAmB7C,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAgC/D;AAID,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,QArCd,OAAO,OAAO,QAAQ,QAAQ,YAAY,KAAG,IAwC1D,CAAC;AAEH,kEAAkE;AAClE,eAAO,MAAM,cAAc,QA3CZ,OAAO,OAAO,QAAQ,QAAQ,YAAY,KAAG,IAoD1D,CAAC;AAEH,0DAA0D;AAC1D,eAAO,MAAM,iBAAiB,QAvDf,OAAO,OAAO,QAAQ,QAAQ,YAAY,KAAG,IA+D1D,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory sliding-window rate limiter.
|
|
3
|
+
* Uses a Map with periodic cleanup to avoid unbounded memory growth.
|
|
4
|
+
*/
|
|
5
|
+
export function rateLimiter(options) {
|
|
6
|
+
const { windowMs, maxRequests, keyFn } = options;
|
|
7
|
+
const store = new Map();
|
|
8
|
+
// Periodic cleanup every 60 seconds
|
|
9
|
+
const cleanupInterval = setInterval(() => {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
for (const [key, entry] of store) {
|
|
12
|
+
if (entry.resetAt <= now) {
|
|
13
|
+
store.delete(key);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}, 60_000);
|
|
17
|
+
// Allow the timer to not prevent Node from exiting
|
|
18
|
+
if (cleanupInterval.unref) {
|
|
19
|
+
cleanupInterval.unref();
|
|
20
|
+
}
|
|
21
|
+
return (req, res, next) => {
|
|
22
|
+
const key = keyFn ? keyFn(req) : req.ip ?? 'unknown';
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
let entry = store.get(key);
|
|
25
|
+
if (!entry || entry.resetAt <= now) {
|
|
26
|
+
entry = { count: 0, resetAt: now + windowMs };
|
|
27
|
+
store.set(key, entry);
|
|
28
|
+
}
|
|
29
|
+
entry.count++;
|
|
30
|
+
// Set rate-limit headers
|
|
31
|
+
const remaining = Math.max(0, maxRequests - entry.count);
|
|
32
|
+
res.set('X-RateLimit-Limit', String(maxRequests));
|
|
33
|
+
res.set('X-RateLimit-Remaining', String(remaining));
|
|
34
|
+
res.set('X-RateLimit-Reset', String(Math.ceil(entry.resetAt / 1000)));
|
|
35
|
+
if (entry.count > maxRequests) {
|
|
36
|
+
const retryAfter = Math.ceil((entry.resetAt - now) / 1000);
|
|
37
|
+
res.set('Retry-After', String(retryAfter));
|
|
38
|
+
res.status(429).json({
|
|
39
|
+
error: 'too_many_requests',
|
|
40
|
+
message: 'Rate limit exceeded. Try again later.',
|
|
41
|
+
retryAfter,
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
next();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// ─── Pre-configured limiters ───
|
|
49
|
+
/** 10 attempts per minute per IP — for login routes */
|
|
50
|
+
export const loginRateLimiter = rateLimiter({
|
|
51
|
+
windowMs: 60_000,
|
|
52
|
+
maxRequests: 10,
|
|
53
|
+
});
|
|
54
|
+
/** 1000 requests per minute per token/IP — for general CMA API */
|
|
55
|
+
export const apiRateLimiter = rateLimiter({
|
|
56
|
+
windowMs: 60_000,
|
|
57
|
+
maxRequests: 1000,
|
|
58
|
+
keyFn: (req) => {
|
|
59
|
+
// Use the auth token (if present) as key, else fall back to IP
|
|
60
|
+
const auth = req.headers.authorization;
|
|
61
|
+
if (auth)
|
|
62
|
+
return auth;
|
|
63
|
+
return req.ip ?? 'unknown';
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
/** 20 uploads per minute per token — for upload routes */
|
|
67
|
+
export const uploadRateLimiter = rateLimiter({
|
|
68
|
+
windowMs: 60_000,
|
|
69
|
+
maxRequests: 20,
|
|
70
|
+
keyFn: (req) => {
|
|
71
|
+
const auth = req.headers.authorization;
|
|
72
|
+
if (auth)
|
|
73
|
+
return `upload:${auth}`;
|
|
74
|
+
return `upload:${req.ip ?? 'unknown'}`;
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/auth/rate-limit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware that checks if the authenticated user has the required permission
|
|
4
|
+
* in the requested space, based on their role bindings.
|
|
5
|
+
*
|
|
6
|
+
* Skips check for API tokens (they use scope-based auth via requireScope).
|
|
7
|
+
* Skips check for preview tokens (they are read-only by design).
|
|
8
|
+
*/
|
|
9
|
+
export declare function requirePermission(...permissions: string[]): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
10
|
+
//# sourceMappingURL=rbac.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../src/auth/rbac.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,WAAW,EAAE,MAAM,EAAE,IAC1C,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CA4D9E"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { prisma } from '../db.js';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware that checks if the authenticated user has the required permission
|
|
4
|
+
* in the requested space, based on their role bindings.
|
|
5
|
+
*
|
|
6
|
+
* Skips check for API tokens (they use scope-based auth via requireScope).
|
|
7
|
+
* Skips check for preview tokens (they are read-only by design).
|
|
8
|
+
*/
|
|
9
|
+
export function requirePermission(...permissions) {
|
|
10
|
+
return async (req, res, next) => {
|
|
11
|
+
if (!req.auth) {
|
|
12
|
+
res.status(401).json({ error: 'authentication_required' });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
// API tokens use scope-based auth, not RBAC
|
|
16
|
+
if (req.auth.type === 'api_token') {
|
|
17
|
+
next();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Preview tokens are read-only
|
|
21
|
+
if (req.auth.type === 'preview_token') {
|
|
22
|
+
next();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// For JWT users, check role bindings
|
|
26
|
+
const spaceId = (req.params.spaceId || req.headers['x-space-id']);
|
|
27
|
+
if (!spaceId) {
|
|
28
|
+
// No space context — skip RBAC (space will be validated by route)
|
|
29
|
+
next();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const bindings = await prisma.roleBinding.findMany({
|
|
33
|
+
where: {
|
|
34
|
+
userId: req.auth.userId,
|
|
35
|
+
spaceId,
|
|
36
|
+
},
|
|
37
|
+
include: { role: true },
|
|
38
|
+
});
|
|
39
|
+
if (bindings.length === 0) {
|
|
40
|
+
res.status(403).json({
|
|
41
|
+
error: 'forbidden',
|
|
42
|
+
message: 'You do not have access to this space',
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Check if any bound role has the required permission
|
|
47
|
+
const hasPermission = permissions.some((perm) => bindings.some((b) => {
|
|
48
|
+
const perms = b.role.permissions;
|
|
49
|
+
return perms[perm] === true;
|
|
50
|
+
}));
|
|
51
|
+
if (!hasPermission) {
|
|
52
|
+
res.status(403).json({
|
|
53
|
+
error: 'insufficient_permissions',
|
|
54
|
+
message: `Requires one of: ${permissions.join(', ')}`,
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
next();
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=rbac.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/auth/rbac.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,WAAqB;IACxD,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAiB,EAAE;QAC9E,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,4CAA4C;QAC5C,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAClC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QAED,+BAA+B;QAC/B,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACtC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QAED,qCAAqC;QACrC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAW,CAAC;QAC5E,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,kEAAkE;YAClE,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC;YACjD,KAAK,EAAE;gBACL,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;gBACvB,OAAO;aACR;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;SACxB,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,sCAAsC;aAChD,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,sDAAsD;QACtD,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC9C,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YAClB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,WAAsC,CAAC;YAC5D,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;QAC9B,CAAC,CAAC,CACH,CAAC;QAEF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,0BAA0B;gBACjC,OAAO,EAAE,oBAAoB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aACtD,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core block definitions shipped with HTMLess.
|
|
3
|
+
* Each entry carries a JSON Schema for its attributes.
|
|
4
|
+
*/
|
|
5
|
+
export interface CoreBlockDef {
|
|
6
|
+
key: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
icon: string;
|
|
10
|
+
attributesSchema: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export declare const coreBlocks: CoreBlockDef[];
|
|
13
|
+
//# sourceMappingURL=core-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-blocks.d.ts","sourceRoot":"","sources":["../../src/blocks/core-blocks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,eAAO,MAAM,UAAU,EAAE,YAAY,EA2GpC,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core block definitions shipped with HTMLess.
|
|
3
|
+
* Each entry carries a JSON Schema for its attributes.
|
|
4
|
+
*/
|
|
5
|
+
export const coreBlocks = [
|
|
6
|
+
{
|
|
7
|
+
key: 'paragraph',
|
|
8
|
+
title: 'Paragraph',
|
|
9
|
+
description: 'A block of body text.',
|
|
10
|
+
icon: 'pilcrow',
|
|
11
|
+
attributesSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
required: ['text'],
|
|
14
|
+
properties: {
|
|
15
|
+
text: { type: 'string' },
|
|
16
|
+
},
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: 'heading',
|
|
22
|
+
title: 'Heading',
|
|
23
|
+
description: 'Section heading (h1 - h6).',
|
|
24
|
+
icon: 'heading',
|
|
25
|
+
attributesSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['level', 'text'],
|
|
28
|
+
properties: {
|
|
29
|
+
level: { type: 'integer', minimum: 1, maximum: 6 },
|
|
30
|
+
text: { type: 'string' },
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: 'image',
|
|
37
|
+
title: 'Image',
|
|
38
|
+
description: 'Image block referencing an asset.',
|
|
39
|
+
icon: 'image',
|
|
40
|
+
attributesSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
required: ['assetId'],
|
|
43
|
+
properties: {
|
|
44
|
+
assetId: { type: 'string' },
|
|
45
|
+
alt: { type: 'string' },
|
|
46
|
+
caption: { type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: 'callout',
|
|
53
|
+
title: 'Callout',
|
|
54
|
+
description: 'Highlighted notice box (info, warning, success, danger).',
|
|
55
|
+
icon: 'megaphone',
|
|
56
|
+
attributesSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
required: ['tone', 'body'],
|
|
59
|
+
properties: {
|
|
60
|
+
tone: { type: 'string', enum: ['info', 'warning', 'success', 'danger'] },
|
|
61
|
+
title: { type: 'string' },
|
|
62
|
+
body: { type: 'string' },
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'embed',
|
|
69
|
+
title: 'Embed',
|
|
70
|
+
description: 'Embedded external content (video, tweet, etc.).',
|
|
71
|
+
icon: 'link',
|
|
72
|
+
attributesSchema: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
required: ['url'],
|
|
75
|
+
properties: {
|
|
76
|
+
url: { type: 'string', format: 'uri' },
|
|
77
|
+
type: { type: 'string' },
|
|
78
|
+
},
|
|
79
|
+
additionalProperties: false,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'list',
|
|
84
|
+
title: 'List',
|
|
85
|
+
description: 'Ordered or unordered list.',
|
|
86
|
+
icon: 'list',
|
|
87
|
+
attributesSchema: {
|
|
88
|
+
type: 'object',
|
|
89
|
+
required: ['ordered', 'items'],
|
|
90
|
+
properties: {
|
|
91
|
+
ordered: { type: 'boolean' },
|
|
92
|
+
items: { type: 'array', items: { type: 'string' } },
|
|
93
|
+
},
|
|
94
|
+
additionalProperties: false,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: 'code',
|
|
99
|
+
title: 'Code',
|
|
100
|
+
description: 'Code block with optional syntax highlighting.',
|
|
101
|
+
icon: 'code',
|
|
102
|
+
attributesSchema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
required: ['code'],
|
|
105
|
+
properties: {
|
|
106
|
+
language: { type: 'string' },
|
|
107
|
+
code: { type: 'string' },
|
|
108
|
+
},
|
|
109
|
+
additionalProperties: false,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
//# sourceMappingURL=core-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-blocks.js","sourceRoot":"","sources":["../../src/blocks/core-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTMLess Renderer SDK Contract
|
|
3
|
+
*
|
|
4
|
+
* This module defines the types and interfaces that frontend renderers
|
|
5
|
+
* must implement to render HTMLess block content.
|
|
6
|
+
*
|
|
7
|
+
* Usage in a Next.js/React frontend:
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import type { BlockInstance, BlockRenderer, BlockRendererMap } from '@htmless/core/blocks/renderer-sdk';
|
|
11
|
+
*
|
|
12
|
+
* const renderers: BlockRendererMap = {
|
|
13
|
+
* paragraph: ({ attrs }) => <p>{attrs.text}</p>,
|
|
14
|
+
* heading: ({ attrs }) => {
|
|
15
|
+
* const Tag = `h${attrs.level}` as keyof JSX.IntrinsicElements;
|
|
16
|
+
* return <Tag>{attrs.text}</Tag>;
|
|
17
|
+
* },
|
|
18
|
+
* image: ({ attrs }) => <img src={attrs.url} alt={attrs.alt || ''} />,
|
|
19
|
+
* callout: ({ attrs, children }) => (
|
|
20
|
+
* <aside className={`callout callout-${attrs.tone}`}>
|
|
21
|
+
* {attrs.title && <strong>{attrs.title}</strong>}
|
|
22
|
+
* <p>{attrs.body}</p>
|
|
23
|
+
* {children}
|
|
24
|
+
* </aside>
|
|
25
|
+
* ),
|
|
26
|
+
* // ... etc
|
|
27
|
+
* };
|
|
28
|
+
*
|
|
29
|
+
* function RenderBlocks({ blocks }: { blocks: BlockInstance[] }) {
|
|
30
|
+
* return <>{blocks.map((block, i) => renderBlock(block, renderers, i))}</>;
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export interface BlockInstance {
|
|
35
|
+
/** Block definition key (e.g. "paragraph", "heading", "image") */
|
|
36
|
+
typeKey: string;
|
|
37
|
+
/** Block definition version this instance was created with */
|
|
38
|
+
version?: string;
|
|
39
|
+
/** Block attributes — shape depends on the block definition's attributesSchema */
|
|
40
|
+
attrs: Record<string, unknown>;
|
|
41
|
+
/** Nested child blocks (for container blocks like callout, columns, etc.) */
|
|
42
|
+
children?: BlockInstance[];
|
|
43
|
+
}
|
|
44
|
+
export interface BlockRendererProps {
|
|
45
|
+
/** The block instance being rendered */
|
|
46
|
+
block: BlockInstance;
|
|
47
|
+
/** Block attributes (shortcut for block.attrs) */
|
|
48
|
+
attrs: Record<string, unknown>;
|
|
49
|
+
/** Rendered children (if the block has nested blocks) */
|
|
50
|
+
children?: unknown;
|
|
51
|
+
/** Block index in the parent array */
|
|
52
|
+
index: number;
|
|
53
|
+
}
|
|
54
|
+
/** A function that renders a single block type */
|
|
55
|
+
export type BlockRenderer = (props: BlockRendererProps) => unknown;
|
|
56
|
+
/** Map of block type keys to their renderer functions */
|
|
57
|
+
export type BlockRendererMap = Record<string, BlockRenderer>;
|
|
58
|
+
/**
|
|
59
|
+
* Renders a single block using the provided renderer map.
|
|
60
|
+
* Falls back to a default renderer if no matching renderer is found.
|
|
61
|
+
*/
|
|
62
|
+
export declare function renderBlock(block: BlockInstance, renderers: BlockRendererMap, index?: number): unknown;
|
|
63
|
+
/**
|
|
64
|
+
* Renders an array of blocks into an array of rendered outputs.
|
|
65
|
+
*/
|
|
66
|
+
export declare function renderBlocks(blocks: BlockInstance[], renderers: BlockRendererMap): unknown[];
|
|
67
|
+
/**
|
|
68
|
+
* Extracts plain text from a block tree (useful for search indexing, excerpts).
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractText(blocks: BlockInstance[]): string;
|
|
71
|
+
/**
|
|
72
|
+
* Collects all asset IDs referenced in a block tree (for preloading, CDN hints).
|
|
73
|
+
*/
|
|
74
|
+
export declare function collectAssetIds(blocks: BlockInstance[]): string[];
|
|
75
|
+
//# sourceMappingURL=renderer-sdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer-sdk.d.ts","sourceRoot":"","sources":["../../src/blocks/renderer-sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,KAAK,EAAE,aAAa,CAAC;IACrB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC;AAEnE,yDAAyD;AACzD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAI7D;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,gBAAgB,EAC3B,KAAK,GAAE,MAAU,GAChB,OAAO,CA0BT;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EAAE,EACvB,SAAS,EAAE,gBAAgB,GAC1B,OAAO,EAAE,CAEX;AAID;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAsB3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAajE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTMLess Renderer SDK Contract
|
|
3
|
+
*
|
|
4
|
+
* This module defines the types and interfaces that frontend renderers
|
|
5
|
+
* must implement to render HTMLess block content.
|
|
6
|
+
*
|
|
7
|
+
* Usage in a Next.js/React frontend:
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import type { BlockInstance, BlockRenderer, BlockRendererMap } from '@htmless/core/blocks/renderer-sdk';
|
|
11
|
+
*
|
|
12
|
+
* const renderers: BlockRendererMap = {
|
|
13
|
+
* paragraph: ({ attrs }) => <p>{attrs.text}</p>,
|
|
14
|
+
* heading: ({ attrs }) => {
|
|
15
|
+
* const Tag = `h${attrs.level}` as keyof JSX.IntrinsicElements;
|
|
16
|
+
* return <Tag>{attrs.text}</Tag>;
|
|
17
|
+
* },
|
|
18
|
+
* image: ({ attrs }) => <img src={attrs.url} alt={attrs.alt || ''} />,
|
|
19
|
+
* callout: ({ attrs, children }) => (
|
|
20
|
+
* <aside className={`callout callout-${attrs.tone}`}>
|
|
21
|
+
* {attrs.title && <strong>{attrs.title}</strong>}
|
|
22
|
+
* <p>{attrs.body}</p>
|
|
23
|
+
* {children}
|
|
24
|
+
* </aside>
|
|
25
|
+
* ),
|
|
26
|
+
* // ... etc
|
|
27
|
+
* };
|
|
28
|
+
*
|
|
29
|
+
* function RenderBlocks({ blocks }: { blocks: BlockInstance[] }) {
|
|
30
|
+
* return <>{blocks.map((block, i) => renderBlock(block, renderers, i))}</>;
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
// ─── Render Function ───
|
|
35
|
+
/**
|
|
36
|
+
* Renders a single block using the provided renderer map.
|
|
37
|
+
* Falls back to a default renderer if no matching renderer is found.
|
|
38
|
+
*/
|
|
39
|
+
export function renderBlock(block, renderers, index = 0) {
|
|
40
|
+
const renderer = renderers[block.typeKey];
|
|
41
|
+
// Recursively render children first
|
|
42
|
+
let children = undefined;
|
|
43
|
+
if (block.children && block.children.length > 0) {
|
|
44
|
+
children = block.children.map((child, i) => renderBlock(child, renderers, i));
|
|
45
|
+
}
|
|
46
|
+
if (!renderer) {
|
|
47
|
+
// Default: return the block data as-is for debugging/fallback
|
|
48
|
+
return {
|
|
49
|
+
_fallback: true,
|
|
50
|
+
typeKey: block.typeKey,
|
|
51
|
+
attrs: block.attrs,
|
|
52
|
+
children,
|
|
53
|
+
index,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return renderer({
|
|
57
|
+
block,
|
|
58
|
+
attrs: block.attrs,
|
|
59
|
+
children,
|
|
60
|
+
index,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Renders an array of blocks into an array of rendered outputs.
|
|
65
|
+
*/
|
|
66
|
+
export function renderBlocks(blocks, renderers) {
|
|
67
|
+
return blocks.map((block, index) => renderBlock(block, renderers, index));
|
|
68
|
+
}
|
|
69
|
+
// ─── Helpers ───
|
|
70
|
+
/**
|
|
71
|
+
* Extracts plain text from a block tree (useful for search indexing, excerpts).
|
|
72
|
+
*/
|
|
73
|
+
export function extractText(blocks) {
|
|
74
|
+
const parts = [];
|
|
75
|
+
for (const block of blocks) {
|
|
76
|
+
const attrs = block.attrs;
|
|
77
|
+
if (typeof attrs.text === 'string')
|
|
78
|
+
parts.push(attrs.text);
|
|
79
|
+
if (typeof attrs.body === 'string')
|
|
80
|
+
parts.push(attrs.body);
|
|
81
|
+
if (typeof attrs.title === 'string')
|
|
82
|
+
parts.push(attrs.title);
|
|
83
|
+
if (typeof attrs.code === 'string')
|
|
84
|
+
parts.push(attrs.code);
|
|
85
|
+
if (Array.isArray(attrs.items)) {
|
|
86
|
+
for (const item of attrs.items) {
|
|
87
|
+
if (typeof item === 'string')
|
|
88
|
+
parts.push(item);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (block.children) {
|
|
92
|
+
parts.push(extractText(block.children));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return parts.filter(Boolean).join(' ');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Collects all asset IDs referenced in a block tree (for preloading, CDN hints).
|
|
99
|
+
*/
|
|
100
|
+
export function collectAssetIds(blocks) {
|
|
101
|
+
const ids = [];
|
|
102
|
+
for (const block of blocks) {
|
|
103
|
+
if (typeof block.attrs.assetId === 'string') {
|
|
104
|
+
ids.push(block.attrs.assetId);
|
|
105
|
+
}
|
|
106
|
+
if (block.children) {
|
|
107
|
+
ids.push(...collectAssetIds(block.children));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return [...new Set(ids)];
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=renderer-sdk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer-sdk.js","sourceRoot":"","sources":["../../src/blocks/renderer-sdk.ts"],"names":[],"mappings":"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"}
|