@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,41 @@
|
|
|
1
|
+
export interface ParsedSheetUrl {
|
|
2
|
+
spreadsheetId: string;
|
|
3
|
+
gid?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SheetToEntriesResult {
|
|
6
|
+
entries: Record<string, unknown>[];
|
|
7
|
+
unmappedColumns: string[];
|
|
8
|
+
headers: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract spreadsheet ID and optional GID from a Google Sheets URL.
|
|
12
|
+
* Accepts standard share links, /edit links, and /pub links.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseSheetUrl(url: string): ParsedSheetUrl;
|
|
15
|
+
/**
|
|
16
|
+
* Convert a Google Sheets URL into its public CSV-export URL.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildCsvExportUrl(url: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Fetch sheet contents as raw CSV text via the public export endpoint.
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchSheetAsCsv(url: string): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Convert parsed CSV data into entry objects.
|
|
25
|
+
*
|
|
26
|
+
* @param csv Raw CSV string
|
|
27
|
+
* @param contentTypeKey Used for context in the result (not embedded in entries)
|
|
28
|
+
* @param fieldMapping Optional override: column header → field key
|
|
29
|
+
*/
|
|
30
|
+
export declare function sheetToEntries(csv: string, _contentTypeKey: string, fieldMapping?: Record<string, string>): SheetToEntriesResult;
|
|
31
|
+
export interface InferredSheetField {
|
|
32
|
+
key: string;
|
|
33
|
+
name: string;
|
|
34
|
+
type: string;
|
|
35
|
+
samples: unknown[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Analyze CSV data and infer field types for schema generation.
|
|
39
|
+
*/
|
|
40
|
+
export declare function inferFieldsFromCsv(csv: string): InferredSheetField[];
|
|
41
|
+
//# sourceMappingURL=sheets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheets.d.ts","sourceRoot":"","sources":["../../src/integrations/sheets.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACnC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAgBzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAelE;AA0DD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,oBAAoB,CA0DtB;AA0BD,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAmBpE"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// ─── Google Sheets → CMS Integration ───
|
|
2
|
+
//
|
|
3
|
+
// Works with the public CSV-export URL — no Google API key required.
|
|
4
|
+
// Users publish their sheet, paste the URL, and we turn rows into entries.
|
|
5
|
+
// ─── URL parsing ───────────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* Extract spreadsheet ID and optional GID from a Google Sheets URL.
|
|
8
|
+
* Accepts standard share links, /edit links, and /pub links.
|
|
9
|
+
*/
|
|
10
|
+
export function parseSheetUrl(url) {
|
|
11
|
+
// Match the spreadsheet ID from various URL formats
|
|
12
|
+
const idMatch = url.match(/\/spreadsheets\/d\/([a-zA-Z0-9_-]+)/);
|
|
13
|
+
if (!idMatch) {
|
|
14
|
+
throw new Error('Invalid Google Sheets URL — could not extract spreadsheet ID');
|
|
15
|
+
}
|
|
16
|
+
const spreadsheetId = idMatch[1];
|
|
17
|
+
// Try to extract GID from hash or query param
|
|
18
|
+
const gidMatch = url.match(/[#&?]gid=(\d+)/);
|
|
19
|
+
const gid = gidMatch ? gidMatch[1] : undefined;
|
|
20
|
+
return { spreadsheetId, gid };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert a Google Sheets URL into its public CSV-export URL.
|
|
24
|
+
*/
|
|
25
|
+
export function buildCsvExportUrl(url) {
|
|
26
|
+
const { spreadsheetId, gid } = parseSheetUrl(url);
|
|
27
|
+
const base = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/export?format=csv`;
|
|
28
|
+
return gid ? `${base}&gid=${gid}` : base;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetch sheet contents as raw CSV text via the public export endpoint.
|
|
32
|
+
*/
|
|
33
|
+
export async function fetchSheetAsCsv(url) {
|
|
34
|
+
const csvUrl = buildCsvExportUrl(url);
|
|
35
|
+
const response = await fetch(csvUrl, {
|
|
36
|
+
headers: { Accept: 'text/csv' },
|
|
37
|
+
redirect: 'follow',
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(`Failed to fetch sheet (HTTP ${response.status}). Make sure the sheet is published to the web.`);
|
|
41
|
+
}
|
|
42
|
+
return response.text();
|
|
43
|
+
}
|
|
44
|
+
// ─── CSV parsing (lightweight, no dependency) ──────────────────────────
|
|
45
|
+
function parseCsvLine(line) {
|
|
46
|
+
const fields = [];
|
|
47
|
+
let current = '';
|
|
48
|
+
let inQuotes = false;
|
|
49
|
+
for (let i = 0; i < line.length; i++) {
|
|
50
|
+
const ch = line[i];
|
|
51
|
+
if (inQuotes) {
|
|
52
|
+
if (ch === '"') {
|
|
53
|
+
// Check for escaped quote
|
|
54
|
+
if (i + 1 < line.length && line[i + 1] === '"') {
|
|
55
|
+
current += '"';
|
|
56
|
+
i++; // skip the second quote
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
inQuotes = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
current += ch;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
if (ch === '"') {
|
|
68
|
+
inQuotes = true;
|
|
69
|
+
}
|
|
70
|
+
else if (ch === ',') {
|
|
71
|
+
fields.push(current.trim());
|
|
72
|
+
current = '';
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
current += ch;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
fields.push(current.trim());
|
|
80
|
+
return fields;
|
|
81
|
+
}
|
|
82
|
+
function parseCsv(csv) {
|
|
83
|
+
const lines = csv.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
84
|
+
return lines.map(parseCsvLine);
|
|
85
|
+
}
|
|
86
|
+
// ─── Column header → field key mapping ─────────────────────────────────
|
|
87
|
+
function headerToCamelCase(header) {
|
|
88
|
+
return header
|
|
89
|
+
.trim()
|
|
90
|
+
.toLowerCase()
|
|
91
|
+
.replace(/[^a-z0-9]+(.)/g, (_, c) => c.toUpperCase())
|
|
92
|
+
.replace(/^[^a-z]/, (c) => c.toLowerCase())
|
|
93
|
+
.replace(/[^a-zA-Z0-9]/g, '');
|
|
94
|
+
}
|
|
95
|
+
// ─── Sheet → Entries ───────────────────────────────────────────────────
|
|
96
|
+
/**
|
|
97
|
+
* Convert parsed CSV data into entry objects.
|
|
98
|
+
*
|
|
99
|
+
* @param csv Raw CSV string
|
|
100
|
+
* @param contentTypeKey Used for context in the result (not embedded in entries)
|
|
101
|
+
* @param fieldMapping Optional override: column header → field key
|
|
102
|
+
*/
|
|
103
|
+
export function sheetToEntries(csv, _contentTypeKey, fieldMapping) {
|
|
104
|
+
const rows = parseCsv(csv);
|
|
105
|
+
if (rows.length < 2) {
|
|
106
|
+
return { entries: [], unmappedColumns: [], headers: [] };
|
|
107
|
+
}
|
|
108
|
+
const headers = rows[0];
|
|
109
|
+
const dataRows = rows.slice(1);
|
|
110
|
+
// Build mapping: column index → field key
|
|
111
|
+
const mapping = headers.map((header) => {
|
|
112
|
+
if (fieldMapping && fieldMapping[header]) {
|
|
113
|
+
return fieldMapping[header];
|
|
114
|
+
}
|
|
115
|
+
const camel = headerToCamelCase(header);
|
|
116
|
+
return camel || null;
|
|
117
|
+
});
|
|
118
|
+
// Track unmapped columns
|
|
119
|
+
const unmappedColumns = [];
|
|
120
|
+
headers.forEach((header, idx) => {
|
|
121
|
+
if (mapping[idx] === null) {
|
|
122
|
+
unmappedColumns.push(header);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Convert rows to entry objects
|
|
126
|
+
const entries = [];
|
|
127
|
+
for (const row of dataRows) {
|
|
128
|
+
const entry = {};
|
|
129
|
+
let hasData = false;
|
|
130
|
+
for (let i = 0; i < headers.length; i++) {
|
|
131
|
+
const fieldKey = mapping[i];
|
|
132
|
+
if (!fieldKey)
|
|
133
|
+
continue;
|
|
134
|
+
const rawValue = row[i] ?? '';
|
|
135
|
+
// Basic type coercion
|
|
136
|
+
const value = coerceValue(rawValue);
|
|
137
|
+
if (value !== '' && value !== null) {
|
|
138
|
+
hasData = true;
|
|
139
|
+
}
|
|
140
|
+
entry[fieldKey] = value;
|
|
141
|
+
}
|
|
142
|
+
if (hasData) {
|
|
143
|
+
entries.push(entry);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
entries,
|
|
148
|
+
unmappedColumns,
|
|
149
|
+
headers,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// ─── Value coercion ────────────────────────────────────────────────────
|
|
153
|
+
function coerceValue(raw) {
|
|
154
|
+
if (raw === '')
|
|
155
|
+
return '';
|
|
156
|
+
// Boolean
|
|
157
|
+
if (raw.toLowerCase() === 'true')
|
|
158
|
+
return true;
|
|
159
|
+
if (raw.toLowerCase() === 'false')
|
|
160
|
+
return false;
|
|
161
|
+
// Number
|
|
162
|
+
const num = Number(raw);
|
|
163
|
+
if (!isNaN(num) && raw.trim() !== '')
|
|
164
|
+
return num;
|
|
165
|
+
// ISO date
|
|
166
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(raw)) {
|
|
167
|
+
const d = new Date(raw);
|
|
168
|
+
if (!isNaN(d.getTime()))
|
|
169
|
+
return d.toISOString();
|
|
170
|
+
}
|
|
171
|
+
return raw;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Analyze CSV data and infer field types for schema generation.
|
|
175
|
+
*/
|
|
176
|
+
export function inferFieldsFromCsv(csv) {
|
|
177
|
+
const rows = parseCsv(csv);
|
|
178
|
+
if (rows.length < 2)
|
|
179
|
+
return [];
|
|
180
|
+
const headers = rows[0];
|
|
181
|
+
const dataRows = rows.slice(1, 11); // sample first 10
|
|
182
|
+
return headers.map((header, colIdx) => {
|
|
183
|
+
const key = headerToCamelCase(header);
|
|
184
|
+
const samples = dataRows.map((row) => coerceValue(row[colIdx] ?? ''));
|
|
185
|
+
const type = inferColumnType(samples);
|
|
186
|
+
return {
|
|
187
|
+
key: key || header.toLowerCase().replace(/\s+/g, '_'),
|
|
188
|
+
name: header.trim(),
|
|
189
|
+
type,
|
|
190
|
+
samples: samples.slice(0, 3),
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function inferColumnType(samples) {
|
|
195
|
+
const types = samples
|
|
196
|
+
.filter((s) => s !== '' && s !== null && s !== undefined)
|
|
197
|
+
.map((s) => {
|
|
198
|
+
if (typeof s === 'boolean')
|
|
199
|
+
return 'boolean';
|
|
200
|
+
if (typeof s === 'number')
|
|
201
|
+
return 'number';
|
|
202
|
+
if (typeof s === 'string') {
|
|
203
|
+
if (/^\d{4}-\d{2}-\d{2}T/.test(s))
|
|
204
|
+
return 'date';
|
|
205
|
+
if (/^https?:\/\//i.test(s) && /\.(jpe?g|png|gif|webp|svg)/i.test(s))
|
|
206
|
+
return 'media';
|
|
207
|
+
if (s.length > 500)
|
|
208
|
+
return 'richtext';
|
|
209
|
+
return 'text';
|
|
210
|
+
}
|
|
211
|
+
return 'text';
|
|
212
|
+
});
|
|
213
|
+
if (types.length === 0)
|
|
214
|
+
return 'text';
|
|
215
|
+
// Majority vote
|
|
216
|
+
const counts = new Map();
|
|
217
|
+
for (const t of types) {
|
|
218
|
+
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
219
|
+
}
|
|
220
|
+
let best = 'text';
|
|
221
|
+
let bestCount = 0;
|
|
222
|
+
for (const [t, c] of counts) {
|
|
223
|
+
if (c > bestCount) {
|
|
224
|
+
best = t;
|
|
225
|
+
bestCount = c;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return best;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=sheets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheets.js","sourceRoot":"","sources":["../../src/integrations/sheets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract basic metadata (dimensions) from an image buffer without any
|
|
3
|
+
* external dependencies. Supports PNG and JPEG header parsing.
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractMetadata(buffer: Buffer, mimeType: string): Promise<{
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/media/metadata.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAe9C"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract basic metadata (dimensions) from an image buffer without any
|
|
3
|
+
* external dependencies. Supports PNG and JPEG header parsing.
|
|
4
|
+
*/
|
|
5
|
+
export async function extractMetadata(buffer, mimeType) {
|
|
6
|
+
if (mimeType === 'image/png') {
|
|
7
|
+
return parsePngDimensions(buffer);
|
|
8
|
+
}
|
|
9
|
+
if (mimeType === 'image/jpeg' || mimeType === 'image/jpg') {
|
|
10
|
+
return parseJpegDimensions(buffer);
|
|
11
|
+
}
|
|
12
|
+
if (mimeType === 'image/gif') {
|
|
13
|
+
return parseGifDimensions(buffer);
|
|
14
|
+
}
|
|
15
|
+
// Non-image or unsupported format
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
// ─── PNG ────────────────────────────────────────────────────────────
|
|
19
|
+
// PNG IHDR chunk starts at byte 16. Width at offset 16 (4 bytes BE),
|
|
20
|
+
// height at offset 20 (4 bytes BE).
|
|
21
|
+
function parsePngDimensions(buf) {
|
|
22
|
+
// Minimum valid PNG is ~33 bytes (signature + IHDR)
|
|
23
|
+
if (buf.length < 24)
|
|
24
|
+
return {};
|
|
25
|
+
// Check PNG signature: 89 50 4E 47 0D 0A 1A 0A
|
|
26
|
+
if (buf[0] !== 0x89 ||
|
|
27
|
+
buf[1] !== 0x50 ||
|
|
28
|
+
buf[2] !== 0x4e ||
|
|
29
|
+
buf[3] !== 0x47) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
const width = buf.readUInt32BE(16);
|
|
33
|
+
const height = buf.readUInt32BE(20);
|
|
34
|
+
return { width, height };
|
|
35
|
+
}
|
|
36
|
+
// ─── JPEG ───────────────────────────────────────────────────────────
|
|
37
|
+
// Walk SOF markers to find frame dimensions.
|
|
38
|
+
function parseJpegDimensions(buf) {
|
|
39
|
+
if (buf.length < 4)
|
|
40
|
+
return {};
|
|
41
|
+
// Check JPEG SOI marker: FF D8
|
|
42
|
+
if (buf[0] !== 0xff || buf[1] !== 0xd8)
|
|
43
|
+
return {};
|
|
44
|
+
let offset = 2;
|
|
45
|
+
while (offset < buf.length - 1) {
|
|
46
|
+
// Find next marker
|
|
47
|
+
if (buf[offset] !== 0xff) {
|
|
48
|
+
offset++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const marker = buf[offset + 1];
|
|
52
|
+
// SOF markers (SOF0 through SOF15, except SOF4/DHT and SOF12/DAC)
|
|
53
|
+
if ((marker >= 0xc0 && marker <= 0xc3) ||
|
|
54
|
+
(marker >= 0xc5 && marker <= 0xc7) ||
|
|
55
|
+
(marker >= 0xc9 && marker <= 0xcb) ||
|
|
56
|
+
(marker >= 0xcd && marker <= 0xcf)) {
|
|
57
|
+
if (offset + 9 > buf.length)
|
|
58
|
+
return {};
|
|
59
|
+
const height = buf.readUInt16BE(offset + 5);
|
|
60
|
+
const width = buf.readUInt16BE(offset + 7);
|
|
61
|
+
return { width, height };
|
|
62
|
+
}
|
|
63
|
+
// Skip to next marker — segment length is at offset+2 (2 bytes BE)
|
|
64
|
+
if (offset + 3 >= buf.length)
|
|
65
|
+
return {};
|
|
66
|
+
const segmentLength = buf.readUInt16BE(offset + 2);
|
|
67
|
+
offset += 2 + segmentLength;
|
|
68
|
+
}
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
// ─── GIF ────────────────────────────────────────────────────────────
|
|
72
|
+
// Width at byte 6 (LE uint16), height at byte 8 (LE uint16).
|
|
73
|
+
function parseGifDimensions(buf) {
|
|
74
|
+
if (buf.length < 10)
|
|
75
|
+
return {};
|
|
76
|
+
// Check GIF signature
|
|
77
|
+
const sig = buf.subarray(0, 3).toString('ascii');
|
|
78
|
+
if (sig !== 'GIF')
|
|
79
|
+
return {};
|
|
80
|
+
const width = buf.readUInt16LE(6);
|
|
81
|
+
const height = buf.readUInt16LE(8);
|
|
82
|
+
return { width, height };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/media/metadata.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,QAAgB;IAEhB,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC1D,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,kCAAkC;IAClC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,uEAAuE;AACvE,qEAAqE;AACrE,oCAAoC;AAEpC,SAAS,kBAAkB,CAAC,GAAW;IACrC,oDAAoD;IACpD,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,EAAE,CAAC;IAE/B,+CAA+C;IAC/C,IACE,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;QACf,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;QACf,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;QACf,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EACf,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,uEAAuE;AACvE,6CAA6C;AAE7C,SAAS,mBAAmB,CAAC,GAAW;IACtC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9B,+BAA+B;IAC/B,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAElD,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,mBAAmB;QACnB,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,EAAE,CAAC;YACT,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/B,kEAAkE;QAClE,IACE,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;YAClC,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;YAClC,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;YAClC,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,EAClC,CAAC;YACD,IAAI,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM;gBAAE,OAAO,EAAE,CAAC;YAEvC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAC3B,CAAC;QAED,mEAAmE;QACnE,IAAI,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACxC,MAAM,aAAa,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnD,MAAM,IAAI,CAAC,GAAG,aAAa,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,uEAAuE;AACvE,6DAA6D;AAE7D,SAAS,kBAAkB,CAAC,GAAW;IACrC,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,EAAE,CAAC;IAE/B,sBAAsB;IACtB,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IAE7B,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAEnC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ImagePreset {
|
|
2
|
+
name: string;
|
|
3
|
+
w: number;
|
|
4
|
+
h: number;
|
|
5
|
+
fit: string;
|
|
6
|
+
fm: string;
|
|
7
|
+
q: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get a built-in image preset by name.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getPreset(name: string): ImagePreset | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Get all built-in presets.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAllPresets(): ImagePreset[];
|
|
17
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/media/presets.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;CACX;AAUD;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE/D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,WAAW,EAAE,CAE7C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// ─── Image Presets ───────────────────────────────────────────────────
|
|
2
|
+
const BUILT_IN_PRESETS = [
|
|
3
|
+
{ name: 'thumbnail', w: 150, h: 150, fit: 'cover', fm: 'webp', q: 80 },
|
|
4
|
+
{ name: 'small', w: 400, h: 300, fit: 'cover', fm: 'webp', q: 80 },
|
|
5
|
+
{ name: 'medium', w: 800, h: 600, fit: 'cover', fm: 'webp', q: 80 },
|
|
6
|
+
{ name: 'large', w: 1200, h: 900, fit: 'cover', fm: 'webp', q: 80 },
|
|
7
|
+
{ name: 'hero', w: 1920, h: 1080, fit: 'cover', fm: 'webp', q: 85 },
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* Get a built-in image preset by name.
|
|
11
|
+
*/
|
|
12
|
+
export function getPreset(name) {
|
|
13
|
+
return BUILT_IN_PRESETS.find((p) => p.name === name);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get all built-in presets.
|
|
17
|
+
*/
|
|
18
|
+
export function getAllPresets() {
|
|
19
|
+
return [...BUILT_IN_PRESETS];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/media/presets.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAWxE,MAAM,gBAAgB,GAAkB;IACtC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,EAAG,CAAC,EAAE,GAAG,EAAG,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;IACxE,EAAE,IAAI,EAAE,OAAO,EAAM,CAAC,EAAE,GAAG,EAAG,CAAC,EAAE,GAAG,EAAG,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;IACxE,EAAE,IAAI,EAAE,QAAQ,EAAK,CAAC,EAAE,GAAG,EAAG,CAAC,EAAE,GAAG,EAAG,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;IACxE,EAAE,IAAI,EAAE,OAAO,EAAM,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAG,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;IACxE,EAAE,IAAI,EAAE,MAAM,EAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE;CACzE,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,GAAG,gBAAgB,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface StorageProvider {
|
|
2
|
+
upload(key: string, buffer: Buffer, mimeType: string): Promise<void>;
|
|
3
|
+
delete(key: string): Promise<void>;
|
|
4
|
+
getUrl(key: string): string;
|
|
5
|
+
}
|
|
6
|
+
export declare class LocalStorageProvider implements StorageProvider {
|
|
7
|
+
private readonly baseDir;
|
|
8
|
+
constructor(baseDir?: string);
|
|
9
|
+
upload(key: string, buffer: Buffer, _mimeType: string): Promise<void>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
getUrl(key: string): string;
|
|
12
|
+
/** Resolve a storage key to an absolute path on disk. */
|
|
13
|
+
resolve(key: string): string;
|
|
14
|
+
}
|
|
15
|
+
export declare function getStorageProvider(): StorageProvider;
|
|
16
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/media/storage.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAID,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,SAAc;IAI3B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI3B,yDAAyD;IACzD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAG7B;AAMD,wBAAgB,kBAAkB,IAAI,eAAe,CAKpD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { mkdirSync, existsSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
// ─── Local filesystem provider ──────────────────────────────────────
|
|
4
|
+
export class LocalStorageProvider {
|
|
5
|
+
baseDir;
|
|
6
|
+
constructor(baseDir = './uploads') {
|
|
7
|
+
this.baseDir = baseDir;
|
|
8
|
+
}
|
|
9
|
+
async upload(key, buffer, _mimeType) {
|
|
10
|
+
const filePath = join(this.baseDir, key);
|
|
11
|
+
const dir = dirname(filePath);
|
|
12
|
+
if (!existsSync(dir)) {
|
|
13
|
+
mkdirSync(dir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
writeFileSync(filePath, buffer);
|
|
16
|
+
}
|
|
17
|
+
async delete(key) {
|
|
18
|
+
const filePath = join(this.baseDir, key);
|
|
19
|
+
if (existsSync(filePath)) {
|
|
20
|
+
unlinkSync(filePath);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
getUrl(key) {
|
|
24
|
+
return `/cda/v1/media/${key}`;
|
|
25
|
+
}
|
|
26
|
+
/** Resolve a storage key to an absolute path on disk. */
|
|
27
|
+
resolve(key) {
|
|
28
|
+
return join(this.baseDir, key);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// ─── Factory ────────────────────────────────────────────────────────
|
|
32
|
+
let _provider;
|
|
33
|
+
export function getStorageProvider() {
|
|
34
|
+
if (!_provider) {
|
|
35
|
+
_provider = new LocalStorageProvider();
|
|
36
|
+
}
|
|
37
|
+
return _provider;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/media/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAgB,UAAU,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAUrC,uEAAuE;AAEvE,MAAM,OAAO,oBAAoB;IACd,OAAO,CAAS;IAEjC,YAAY,OAAO,GAAG,WAAW;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,MAAc,EAAE,SAAiB;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAEzC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,OAAO,iBAAiB,GAAG,EAAE,CAAC;IAChC,CAAC;IAED,yDAAyD;IACzD,OAAO,CAAC,GAAW;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;CACF;AAED,uEAAuE;AAEvE,IAAI,SAAsC,CAAC;AAE3C,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface FocalPoint {
|
|
2
|
+
/** Horizontal focal point, 0-1 range (0 = left, 1 = right) */
|
|
3
|
+
fp_x: number;
|
|
4
|
+
/** Vertical focal point, 0-1 range (0 = top, 1 = bottom) */
|
|
5
|
+
fp_y: number;
|
|
6
|
+
}
|
|
7
|
+
export interface TransformParams {
|
|
8
|
+
/** Target width in pixels */
|
|
9
|
+
w?: number;
|
|
10
|
+
/** Target height in pixels */
|
|
11
|
+
h?: number;
|
|
12
|
+
/** Resize fit mode: cover, contain, fill, inside, outside */
|
|
13
|
+
fit?: string;
|
|
14
|
+
/** Output format: jpeg, png, webp, avif, gif */
|
|
15
|
+
fm?: string;
|
|
16
|
+
/** Quality (1-100) */
|
|
17
|
+
q?: number;
|
|
18
|
+
/** Focal point X (0-1) */
|
|
19
|
+
fp_x?: number;
|
|
20
|
+
/** Focal point Y (0-1) */
|
|
21
|
+
fp_y?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface TransformResult {
|
|
24
|
+
buffer: Buffer;
|
|
25
|
+
/** Headers describing which transforms were requested (for pass-through mode) */
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Transform an image buffer according to the given params.
|
|
30
|
+
*
|
|
31
|
+
* Currently a pass-through: returns the original buffer unchanged and
|
|
32
|
+
* records the requested transforms in `headers`. Once sharp is added as
|
|
33
|
+
* a dependency, this function will perform actual resize/format/quality
|
|
34
|
+
* operations.
|
|
35
|
+
*/
|
|
36
|
+
export declare function transformImage(buffer: Buffer, params: TransformParams): Promise<Buffer>;
|
|
37
|
+
/**
|
|
38
|
+
* Build response headers describing the transforms that were applied
|
|
39
|
+
* (or requested in pass-through mode).
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildTransformHeaders(params: TransformParams): Record<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Parse transform query params from a request query object.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseTransformParams(query: Record<string, string | undefined>): TransformParams;
|
|
46
|
+
//# sourceMappingURL=transforms-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transforms-engine.d.ts","sourceRoot":"","sources":["../../src/media/transforms-engine.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,8BAA8B;IAC9B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sBAAsB;IACtB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAKD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACxC,eAAe,CAYjB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ─── Image Transform Engine ──────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Provides a transform pipeline for image buffers. Currently a
|
|
4
|
+
// pass-through implementation that records requested transforms in
|
|
5
|
+
// response headers. Actual pixel manipulation (resize, format
|
|
6
|
+
// conversion) requires sharp/libvips which will be added later.
|
|
7
|
+
const VALID_FITS = ['cover', 'contain', 'fill', 'inside', 'outside'];
|
|
8
|
+
const VALID_FORMATS = ['jpeg', 'png', 'webp', 'avif', 'gif'];
|
|
9
|
+
/**
|
|
10
|
+
* Transform an image buffer according to the given params.
|
|
11
|
+
*
|
|
12
|
+
* Currently a pass-through: returns the original buffer unchanged and
|
|
13
|
+
* records the requested transforms in `headers`. Once sharp is added as
|
|
14
|
+
* a dependency, this function will perform actual resize/format/quality
|
|
15
|
+
* operations.
|
|
16
|
+
*/
|
|
17
|
+
export async function transformImage(buffer, params) {
|
|
18
|
+
// Validate params
|
|
19
|
+
if (params.w !== undefined && (params.w < 1 || params.w > 8192)) {
|
|
20
|
+
throw new Error('Width must be between 1 and 8192');
|
|
21
|
+
}
|
|
22
|
+
if (params.h !== undefined && (params.h < 1 || params.h > 8192)) {
|
|
23
|
+
throw new Error('Height must be between 1 and 8192');
|
|
24
|
+
}
|
|
25
|
+
if (params.fit !== undefined && !VALID_FITS.includes(params.fit)) {
|
|
26
|
+
throw new Error(`Invalid fit mode: ${params.fit}. Must be one of: ${VALID_FITS.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
if (params.fm !== undefined && !VALID_FORMATS.includes(params.fm)) {
|
|
29
|
+
throw new Error(`Invalid format: ${params.fm}. Must be one of: ${VALID_FORMATS.join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
if (params.q !== undefined && (params.q < 1 || params.q > 100)) {
|
|
32
|
+
throw new Error('Quality must be between 1 and 100');
|
|
33
|
+
}
|
|
34
|
+
if (params.fp_x !== undefined && (params.fp_x < 0 || params.fp_x > 1)) {
|
|
35
|
+
throw new Error('Focal point X must be between 0 and 1');
|
|
36
|
+
}
|
|
37
|
+
if (params.fp_y !== undefined && (params.fp_y < 0 || params.fp_y > 1)) {
|
|
38
|
+
throw new Error('Focal point Y must be between 0 and 1');
|
|
39
|
+
}
|
|
40
|
+
// Pass-through: return original buffer.
|
|
41
|
+
// In the future, sharp-based transforms will go here:
|
|
42
|
+
// const img = sharp(buffer);
|
|
43
|
+
// if (params.w || params.h) img.resize(params.w, params.h, { fit, position });
|
|
44
|
+
// if (params.fm) img.toFormat(params.fm, { quality: params.q });
|
|
45
|
+
// return img.toBuffer();
|
|
46
|
+
return buffer;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build response headers describing the transforms that were applied
|
|
50
|
+
* (or requested in pass-through mode).
|
|
51
|
+
*/
|
|
52
|
+
export function buildTransformHeaders(params) {
|
|
53
|
+
const headers = {};
|
|
54
|
+
if (params.w !== undefined)
|
|
55
|
+
headers['X-Transform-Width'] = String(params.w);
|
|
56
|
+
if (params.h !== undefined)
|
|
57
|
+
headers['X-Transform-Height'] = String(params.h);
|
|
58
|
+
if (params.fit)
|
|
59
|
+
headers['X-Transform-Fit'] = params.fit;
|
|
60
|
+
if (params.fm)
|
|
61
|
+
headers['X-Transform-Format'] = params.fm;
|
|
62
|
+
if (params.q !== undefined)
|
|
63
|
+
headers['X-Transform-Quality'] = String(params.q);
|
|
64
|
+
if (params.fp_x !== undefined)
|
|
65
|
+
headers['X-Transform-FP-X'] = String(params.fp_x);
|
|
66
|
+
if (params.fp_y !== undefined)
|
|
67
|
+
headers['X-Transform-FP-Y'] = String(params.fp_y);
|
|
68
|
+
return headers;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse transform query params from a request query object.
|
|
72
|
+
*/
|
|
73
|
+
export function parseTransformParams(query) {
|
|
74
|
+
const params = {};
|
|
75
|
+
if (query.w)
|
|
76
|
+
params.w = parseInt(query.w, 10);
|
|
77
|
+
if (query.h)
|
|
78
|
+
params.h = parseInt(query.h, 10);
|
|
79
|
+
if (query.fit)
|
|
80
|
+
params.fit = query.fit;
|
|
81
|
+
if (query.fm)
|
|
82
|
+
params.fm = query.fm;
|
|
83
|
+
if (query.q)
|
|
84
|
+
params.q = parseInt(query.q, 10);
|
|
85
|
+
if (query.fp_x)
|
|
86
|
+
params.fp_x = parseFloat(query.fp_x);
|
|
87
|
+
if (query.fp_y)
|
|
88
|
+
params.fp_y = parseFloat(query.fp_y);
|
|
89
|
+
return params;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=transforms-engine.js.map
|