@trokky/trokky 2.0.3
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/adapters/filesystem/filesystem-adapter.d.ts +80 -0
- package/dist/adapters/filesystem/filesystem-adapter.d.ts.map +1 -0
- package/dist/adapters/filesystem/filesystem-adapter.js +1370 -0
- package/dist/adapters/filesystem/filesystem-adapter.js.map +1 -0
- package/dist/adapters/filesystem/index.d.ts +29 -0
- package/dist/adapters/filesystem/index.d.ts.map +1 -0
- package/dist/adapters/filesystem/index.js +31 -0
- package/dist/adapters/filesystem/index.js.map +1 -0
- package/dist/adapters/filesystem/types.d.ts +111 -0
- package/dist/adapters/filesystem/types.d.ts.map +1 -0
- package/dist/adapters/filesystem/types.js +2 -0
- package/dist/adapters/filesystem/types.js.map +1 -0
- package/dist/adapters/filesystem-data/filesystem-data-adapter.d.ts +111 -0
- package/dist/adapters/filesystem-data/filesystem-data-adapter.d.ts.map +1 -0
- package/dist/adapters/filesystem-data/filesystem-data-adapter.js +1363 -0
- package/dist/adapters/filesystem-data/filesystem-data-adapter.js.map +1 -0
- package/dist/adapters/filesystem-data/index.d.ts +3 -0
- package/dist/adapters/filesystem-data/index.d.ts.map +1 -0
- package/dist/adapters/filesystem-data/index.js +13 -0
- package/dist/adapters/filesystem-data/index.js.map +1 -0
- package/dist/adapters/filesystem-data/types.d.ts +147 -0
- package/dist/adapters/filesystem-data/types.d.ts.map +1 -0
- package/dist/adapters/filesystem-data/types.js +2 -0
- package/dist/adapters/filesystem-data/types.js.map +1 -0
- package/dist/adapters/filesystem-media/filesystem-media-adapter.d.ts +32 -0
- package/dist/adapters/filesystem-media/filesystem-media-adapter.d.ts.map +1 -0
- package/dist/adapters/filesystem-media/filesystem-media-adapter.js +639 -0
- package/dist/adapters/filesystem-media/filesystem-media-adapter.js.map +1 -0
- package/dist/adapters/filesystem-media/index.d.ts +3 -0
- package/dist/adapters/filesystem-media/index.d.ts.map +1 -0
- package/dist/adapters/filesystem-media/index.js +13 -0
- package/dist/adapters/filesystem-media/index.js.map +1 -0
- package/dist/adapters/filesystem-media/types.d.ts +76 -0
- package/dist/adapters/filesystem-media/types.d.ts.map +1 -0
- package/dist/adapters/filesystem-media/types.js +2 -0
- package/dist/adapters/filesystem-media/types.js.map +1 -0
- package/dist/adapters/postgres-data/index.d.ts +3 -0
- package/dist/adapters/postgres-data/index.d.ts.map +1 -0
- package/dist/adapters/postgres-data/index.js +13 -0
- package/dist/adapters/postgres-data/index.js.map +1 -0
- package/dist/adapters/postgres-data/postgres-data-adapter.d.ts +154 -0
- package/dist/adapters/postgres-data/postgres-data-adapter.d.ts.map +1 -0
- package/dist/adapters/postgres-data/postgres-data-adapter.js +1432 -0
- package/dist/adapters/postgres-data/postgres-data-adapter.js.map +1 -0
- package/dist/adapters/postgres-data/types.d.ts +139 -0
- package/dist/adapters/postgres-data/types.d.ts.map +1 -0
- package/dist/adapters/postgres-data/types.js +2 -0
- package/dist/adapters/postgres-data/types.js.map +1 -0
- package/dist/core/adapters/registry.d.ts +79 -0
- package/dist/core/adapters/registry.d.ts.map +1 -0
- package/dist/core/adapters/registry.js +149 -0
- package/dist/core/adapters/registry.js.map +1 -0
- package/dist/core/core/engine.d.ts +551 -0
- package/dist/core/core/engine.d.ts.map +1 -0
- package/dist/core/core/engine.js +1074 -0
- package/dist/core/core/engine.js.map +1 -0
- package/dist/core/crypto/adapter.d.ts +63 -0
- package/dist/core/crypto/adapter.d.ts.map +1 -0
- package/dist/core/crypto/adapter.js +63 -0
- package/dist/core/crypto/adapter.js.map +1 -0
- package/dist/core/crypto/fallback-adapter.d.ts +23 -0
- package/dist/core/crypto/fallback-adapter.d.ts.map +1 -0
- package/dist/core/crypto/fallback-adapter.js +195 -0
- package/dist/core/crypto/fallback-adapter.js.map +1 -0
- package/dist/core/crypto/node-adapter.d.ts +20 -0
- package/dist/core/crypto/node-adapter.d.ts.map +1 -0
- package/dist/core/crypto/node-adapter.js +85 -0
- package/dist/core/crypto/node-adapter.js.map +1 -0
- package/dist/core/crypto/password-hash.d.ts +73 -0
- package/dist/core/crypto/password-hash.d.ts.map +1 -0
- package/dist/core/crypto/password-hash.js +244 -0
- package/dist/core/crypto/password-hash.js.map +1 -0
- package/dist/core/crypto/webcrypto-adapter.d.ts +24 -0
- package/dist/core/crypto/webcrypto-adapter.d.ts.map +1 -0
- package/dist/core/crypto/webcrypto-adapter.js +158 -0
- package/dist/core/crypto/webcrypto-adapter.js.map +1 -0
- package/dist/core/errors/index.d.ts +30 -0
- package/dist/core/errors/index.d.ts.map +1 -0
- package/dist/core/errors/index.js +61 -0
- package/dist/core/errors/index.js.map +1 -0
- package/dist/core/events/event-bus.d.ts +121 -0
- package/dist/core/events/event-bus.d.ts.map +1 -0
- package/dist/core/events/event-bus.js +631 -0
- package/dist/core/events/event-bus.js.map +1 -0
- package/dist/core/events/index.d.ts +17 -0
- package/dist/core/events/index.d.ts.map +1 -0
- package/dist/core/events/index.js +22 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/events/memory-storage.d.ts +57 -0
- package/dist/core/events/memory-storage.d.ts.map +1 -0
- package/dist/core/events/memory-storage.js +175 -0
- package/dist/core/events/memory-storage.js.map +1 -0
- package/dist/core/events/types.d.ts +434 -0
- package/dist/core/events/types.d.ts.map +1 -0
- package/dist/core/events/types.js +9 -0
- package/dist/core/events/types.js.map +1 -0
- package/dist/core/events/utils.d.ts +134 -0
- package/dist/core/events/utils.d.ts.map +1 -0
- package/dist/core/events/utils.js +333 -0
- package/dist/core/events/utils.js.map +1 -0
- package/dist/core/fields/conditional.d.ts +115 -0
- package/dist/core/fields/conditional.d.ts.map +1 -0
- package/dist/core/fields/conditional.js +296 -0
- package/dist/core/fields/conditional.js.map +1 -0
- package/dist/core/fields/field-type.d.ts +218 -0
- package/dist/core/fields/field-type.d.ts.map +1 -0
- package/dist/core/fields/field-type.js +17 -0
- package/dist/core/fields/field-type.js.map +1 -0
- package/dist/core/fields/helpers.d.ts +86 -0
- package/dist/core/fields/helpers.d.ts.map +1 -0
- package/dist/core/fields/helpers.js +260 -0
- package/dist/core/fields/helpers.js.map +1 -0
- package/dist/core/fields/index.d.ts +5 -0
- package/dist/core/fields/index.d.ts.map +1 -0
- package/dist/core/fields/index.js +6 -0
- package/dist/core/fields/index.js.map +1 -0
- package/dist/core/fields/registry.d.ts +78 -0
- package/dist/core/fields/registry.d.ts.map +1 -0
- package/dist/core/fields/registry.js +185 -0
- package/dist/core/fields/registry.js.map +1 -0
- package/dist/core/index.d.ts +39 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +57 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/media/image-processor.d.ts +24 -0
- package/dist/core/media/image-processor.d.ts.map +1 -0
- package/dist/core/media/image-processor.js +69 -0
- package/dist/core/media/image-processor.js.map +1 -0
- package/dist/core/media/processors/cloudflare-images.d.ts +83 -0
- package/dist/core/media/processors/cloudflare-images.d.ts.map +1 -0
- package/dist/core/media/processors/cloudflare-images.js +241 -0
- package/dist/core/media/processors/cloudflare-images.js.map +1 -0
- package/dist/core/media/processors/cloudflare-transform-store.d.ts +127 -0
- package/dist/core/media/processors/cloudflare-transform-store.d.ts.map +1 -0
- package/dist/core/media/processors/cloudflare-transform-store.js +237 -0
- package/dist/core/media/processors/cloudflare-transform-store.js.map +1 -0
- package/dist/core/media/processors/cloudflare-transformations.d.ts +81 -0
- package/dist/core/media/processors/cloudflare-transformations.d.ts.map +1 -0
- package/dist/core/media/processors/cloudflare-transformations.js +144 -0
- package/dist/core/media/processors/cloudflare-transformations.js.map +1 -0
- package/dist/core/media/processors/index.d.ts +9 -0
- package/dist/core/media/processors/index.d.ts.map +1 -0
- package/dist/core/media/processors/index.js +13 -0
- package/dist/core/media/processors/index.js.map +1 -0
- package/dist/core/media/processors/noop.d.ts +22 -0
- package/dist/core/media/processors/noop.d.ts.map +1 -0
- package/dist/core/media/processors/noop.js +38 -0
- package/dist/core/media/processors/noop.js.map +1 -0
- package/dist/core/media/processors/sharp.d.ts +30 -0
- package/dist/core/media/processors/sharp.d.ts.map +1 -0
- package/dist/core/media/processors/sharp.js +126 -0
- package/dist/core/media/processors/sharp.js.map +1 -0
- package/dist/core/media/processors/types.d.ts +67 -0
- package/dist/core/media/processors/types.d.ts.map +1 -0
- package/dist/core/media/processors/types.js +42 -0
- package/dist/core/media/processors/types.js.map +1 -0
- package/dist/core/media/processors/workers-images.d.ts +112 -0
- package/dist/core/media/processors/workers-images.d.ts.map +1 -0
- package/dist/core/media/processors/workers-images.js +257 -0
- package/dist/core/media/processors/workers-images.js.map +1 -0
- package/dist/core/schema/registry.d.ts +41 -0
- package/dist/core/schema/registry.d.ts.map +1 -0
- package/dist/core/schema/registry.js +248 -0
- package/dist/core/schema/registry.js.map +1 -0
- package/dist/core/schema/singleton.d.ts +107 -0
- package/dist/core/schema/singleton.d.ts.map +1 -0
- package/dist/core/schema/singleton.js +180 -0
- package/dist/core/schema/singleton.js.map +1 -0
- package/dist/core/security/auth.d.ts +120 -0
- package/dist/core/security/auth.d.ts.map +1 -0
- package/dist/core/security/auth.js +274 -0
- package/dist/core/security/auth.js.map +1 -0
- package/dist/core/security/captcha/index.d.ts +21 -0
- package/dist/core/security/captcha/index.d.ts.map +1 -0
- package/dist/core/security/captcha/index.js +34 -0
- package/dist/core/security/captcha/index.js.map +1 -0
- package/dist/core/security/captcha/recaptcha.d.ts +41 -0
- package/dist/core/security/captcha/recaptcha.d.ts.map +1 -0
- package/dist/core/security/captcha/recaptcha.js +89 -0
- package/dist/core/security/captcha/recaptcha.js.map +1 -0
- package/dist/core/security/captcha/turnstile.d.ts +41 -0
- package/dist/core/security/captcha/turnstile.d.ts.map +1 -0
- package/dist/core/security/captcha/turnstile.js +90 -0
- package/dist/core/security/captcha/turnstile.js.map +1 -0
- package/dist/core/security/captcha/types.d.ts +66 -0
- package/dist/core/security/captcha/types.d.ts.map +1 -0
- package/dist/core/security/captcha/types.js +7 -0
- package/dist/core/security/captcha/types.js.map +1 -0
- package/dist/core/security/mfa/email-otp.d.ts +91 -0
- package/dist/core/security/mfa/email-otp.d.ts.map +1 -0
- package/dist/core/security/mfa/email-otp.js +264 -0
- package/dist/core/security/mfa/email-otp.js.map +1 -0
- package/dist/core/security/mfa/index.d.ts +8 -0
- package/dist/core/security/mfa/index.d.ts.map +1 -0
- package/dist/core/security/mfa/index.js +8 -0
- package/dist/core/security/mfa/index.js.map +1 -0
- package/dist/core/security/mfa/totp.d.ts +87 -0
- package/dist/core/security/mfa/totp.d.ts.map +1 -0
- package/dist/core/security/mfa/totp.js +293 -0
- package/dist/core/security/mfa/totp.js.map +1 -0
- package/dist/core/security/middleware.d.ts +102 -0
- package/dist/core/security/middleware.d.ts.map +1 -0
- package/dist/core/security/middleware.js +261 -0
- package/dist/core/security/middleware.js.map +1 -0
- package/dist/core/security/oauth/google.d.ts +76 -0
- package/dist/core/security/oauth/google.d.ts.map +1 -0
- package/dist/core/security/oauth/google.js +154 -0
- package/dist/core/security/oauth/google.js.map +1 -0
- package/dist/core/security/oauth/index.d.ts +8 -0
- package/dist/core/security/oauth/index.d.ts.map +1 -0
- package/dist/core/security/oauth/index.js +7 -0
- package/dist/core/security/oauth/index.js.map +1 -0
- package/dist/core/security/oauth2/authorization-server.d.ts +195 -0
- package/dist/core/security/oauth2/authorization-server.d.ts.map +1 -0
- package/dist/core/security/oauth2/authorization-server.js +569 -0
- package/dist/core/security/oauth2/authorization-server.js.map +1 -0
- package/dist/core/security/oauth2/index.d.ts +9 -0
- package/dist/core/security/oauth2/index.d.ts.map +1 -0
- package/dist/core/security/oauth2/index.js +9 -0
- package/dist/core/security/oauth2/index.js.map +1 -0
- package/dist/core/security/rate-limiter.d.ts +15 -0
- package/dist/core/security/rate-limiter.d.ts.map +1 -0
- package/dist/core/security/rate-limiter.js +48 -0
- package/dist/core/security/rate-limiter.js.map +1 -0
- package/dist/core/security/validation.d.ts +20 -0
- package/dist/core/security/validation.d.ts.map +1 -0
- package/dist/core/security/validation.js +273 -0
- package/dist/core/security/validation.js.map +1 -0
- package/dist/core/services/auth-service.d.ts +128 -0
- package/dist/core/services/auth-service.d.ts.map +1 -0
- package/dist/core/services/auth-service.js +530 -0
- package/dist/core/services/auth-service.js.map +1 -0
- package/dist/core/services/captcha-service.d.ts +44 -0
- package/dist/core/services/captcha-service.d.ts.map +1 -0
- package/dist/core/services/captcha-service.js +82 -0
- package/dist/core/services/captcha-service.js.map +1 -0
- package/dist/core/services/document-service.d.ts +59 -0
- package/dist/core/services/document-service.d.ts.map +1 -0
- package/dist/core/services/document-service.js +269 -0
- package/dist/core/services/document-service.js.map +1 -0
- package/dist/core/services/media-service.d.ts +40 -0
- package/dist/core/services/media-service.d.ts.map +1 -0
- package/dist/core/services/media-service.js +396 -0
- package/dist/core/services/media-service.js.map +1 -0
- package/dist/core/services/mfa-service.d.ts +123 -0
- package/dist/core/services/mfa-service.d.ts.map +1 -0
- package/dist/core/services/mfa-service.js +606 -0
- package/dist/core/services/mfa-service.js.map +1 -0
- package/dist/core/services/oauth-service.d.ts +58 -0
- package/dist/core/services/oauth-service.d.ts.map +1 -0
- package/dist/core/services/oauth-service.js +253 -0
- package/dist/core/services/oauth-service.js.map +1 -0
- package/dist/core/services/oauth2-server-service.d.ts +61 -0
- package/dist/core/services/oauth2-server-service.d.ts.map +1 -0
- package/dist/core/services/oauth2-server-service.js +259 -0
- package/dist/core/services/oauth2-server-service.js.map +1 -0
- package/dist/core/services/passkey-service.d.ts +59 -0
- package/dist/core/services/passkey-service.d.ts.map +1 -0
- package/dist/core/services/passkey-service.js +238 -0
- package/dist/core/services/passkey-service.js.map +1 -0
- package/dist/core/services/token-service.d.ts +31 -0
- package/dist/core/services/token-service.d.ts.map +1 -0
- package/dist/core/services/token-service.js +132 -0
- package/dist/core/services/token-service.js.map +1 -0
- package/dist/core/services/trusted-device-service.d.ts +39 -0
- package/dist/core/services/trusted-device-service.d.ts.map +1 -0
- package/dist/core/services/trusted-device-service.js +123 -0
- package/dist/core/services/trusted-device-service.js.map +1 -0
- package/dist/core/services/user-service.d.ts +38 -0
- package/dist/core/services/user-service.d.ts.map +1 -0
- package/dist/core/services/user-service.js +265 -0
- package/dist/core/services/user-service.js.map +1 -0
- package/dist/core/studio/integration.d.ts +54 -0
- package/dist/core/studio/integration.d.ts.map +1 -0
- package/dist/core/studio/integration.js +326 -0
- package/dist/core/studio/integration.js.map +1 -0
- package/dist/core/types/index.d.ts +282 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +83 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/types/mail.d.ts +90 -0
- package/dist/core/types/mail.d.ts.map +1 -0
- package/dist/core/types/mail.js +7 -0
- package/dist/core/types/mail.js.map +1 -0
- package/dist/core/types/oauth2.d.ts +9 -0
- package/dist/core/types/oauth2.d.ts.map +1 -0
- package/dist/core/types/oauth2.js +7 -0
- package/dist/core/types/oauth2.js.map +1 -0
- package/dist/core/types/storage-adapters.d.ts +611 -0
- package/dist/core/types/storage-adapters.d.ts.map +1 -0
- package/dist/core/types/storage-adapters.js +14 -0
- package/dist/core/types/storage-adapters.js.map +1 -0
- package/dist/core/types/user.d.ts +10 -0
- package/dist/core/types/user.d.ts.map +1 -0
- package/dist/core/types/user.js +45 -0
- package/dist/core/types/user.js.map +1 -0
- package/dist/core/utils/id-generator.d.ts +16 -0
- package/dist/core/utils/id-generator.d.ts.map +1 -0
- package/dist/core/utils/id-generator.js +61 -0
- package/dist/core/utils/id-generator.js.map +1 -0
- package/dist/core/utils/logger.d.ts +100 -0
- package/dist/core/utils/logger.d.ts.map +1 -0
- package/dist/core/utils/logger.js +212 -0
- package/dist/core/utils/logger.js.map +1 -0
- package/dist/core/utils/reference-expander.d.ts +57 -0
- package/dist/core/utils/reference-expander.d.ts.map +1 -0
- package/dist/core/utils/reference-expander.js +192 -0
- package/dist/core/utils/reference-expander.js.map +1 -0
- package/dist/core/utils/universal-crypto.d.ts +46 -0
- package/dist/core/utils/universal-crypto.d.ts.map +1 -0
- package/dist/core/utils/universal-crypto.js +171 -0
- package/dist/core/utils/universal-crypto.js.map +1 -0
- package/dist/core/validation/validator.d.ts +11 -0
- package/dist/core/validation/validator.d.ts.map +1 -0
- package/dist/core/validation/validator.js +164 -0
- package/dist/core/validation/validator.js.map +1 -0
- package/dist/i18n/config.d.ts +4077 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/config.js +116 -0
- package/dist/i18n/config.js.map +1 -0
- package/dist/i18n/hooks.d.ts +86 -0
- package/dist/i18n/hooks.d.ts.map +1 -0
- package/dist/i18n/hooks.js +122 -0
- package/dist/i18n/hooks.js.map +1 -0
- package/dist/i18n/index.d.ts +39 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +40 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locales/en/auth.json +108 -0
- package/dist/i18n/locales/en/common.json +100 -0
- package/dist/i18n/locales/en/errors.json +55 -0
- package/dist/i18n/locales/en/fields.json +456 -0
- package/dist/i18n/locales/en/studio.json +1329 -0
- package/dist/i18n/locales/fr/auth.json +108 -0
- package/dist/i18n/locales/fr/common.json +100 -0
- package/dist/i18n/locales/fr/errors.json +55 -0
- package/dist/i18n/locales/fr/fields.json +456 -0
- package/dist/i18n/locales/fr/studio.json +1274 -0
- package/dist/i18n/provider.d.ts +45 -0
- package/dist/i18n/provider.d.ts.map +1 -0
- package/dist/i18n/provider.js +49 -0
- package/dist/i18n/provider.js.map +1 -0
- package/dist/i18n/types.d.ts +8 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +7 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/express/adapter.d.ts +33 -0
- package/dist/integrations/express/adapter.d.ts.map +1 -0
- package/dist/integrations/express/adapter.js +203 -0
- package/dist/integrations/express/adapter.js.map +1 -0
- package/dist/integrations/express/config.d.ts +599 -0
- package/dist/integrations/express/config.d.ts.map +1 -0
- package/dist/integrations/express/config.js +166 -0
- package/dist/integrations/express/config.js.map +1 -0
- package/dist/integrations/express/index.d.ts +10 -0
- package/dist/integrations/express/index.d.ts.map +1 -0
- package/dist/integrations/express/index.js +9 -0
- package/dist/integrations/express/index.js.map +1 -0
- package/dist/integrations/express/integration.d.ts +111 -0
- package/dist/integrations/express/integration.d.ts.map +1 -0
- package/dist/integrations/express/integration.js +730 -0
- package/dist/integrations/express/integration.js.map +1 -0
- package/dist/integrations/express/media-rewrite-middleware.d.ts +78 -0
- package/dist/integrations/express/media-rewrite-middleware.d.ts.map +1 -0
- package/dist/integrations/express/media-rewrite-middleware.js +211 -0
- package/dist/integrations/express/media-rewrite-middleware.js.map +1 -0
- package/dist/integrations/express/media-url-generator.d.ts +52 -0
- package/dist/integrations/express/media-url-generator.d.ts.map +1 -0
- package/dist/integrations/express/media-url-generator.js +107 -0
- package/dist/integrations/express/media-url-generator.js.map +1 -0
- package/dist/integrations/express/middleware.d.ts +25 -0
- package/dist/integrations/express/middleware.d.ts.map +1 -0
- package/dist/integrations/express/middleware.js +130 -0
- package/dist/integrations/express/middleware.js.map +1 -0
- package/dist/integrations/express/server.d.ts +99 -0
- package/dist/integrations/express/server.d.ts.map +1 -0
- package/dist/integrations/express/server.js +597 -0
- package/dist/integrations/express/server.js.map +1 -0
- package/dist/integrations/express/types.d.ts +106 -0
- package/dist/integrations/express/types.d.ts.map +1 -0
- package/dist/integrations/express/types.js +2 -0
- package/dist/integrations/express/types.js.map +1 -0
- package/dist/mail/adapters/console.d.ts +30 -0
- package/dist/mail/adapters/console.d.ts.map +1 -0
- package/dist/mail/adapters/console.js +169 -0
- package/dist/mail/adapters/console.js.map +1 -0
- package/dist/mail/adapters/resend.d.ts +18 -0
- package/dist/mail/adapters/resend.d.ts.map +1 -0
- package/dist/mail/adapters/resend.js +148 -0
- package/dist/mail/adapters/resend.js.map +1 -0
- package/dist/mail/adapters/smtp.d.ts +22 -0
- package/dist/mail/adapters/smtp.d.ts.map +1 -0
- package/dist/mail/adapters/smtp.js +180 -0
- package/dist/mail/adapters/smtp.js.map +1 -0
- package/dist/mail/index.d.ts +15 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +13 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/mail-service.d.ts +180 -0
- package/dist/mail/mail-service.d.ts.map +1 -0
- package/dist/mail/mail-service.js +370 -0
- package/dist/mail/mail-service.js.map +1 -0
- package/dist/mail/notification-service.d.ts +82 -0
- package/dist/mail/notification-service.d.ts.map +1 -0
- package/dist/mail/notification-service.js +262 -0
- package/dist/mail/notification-service.js.map +1 -0
- package/dist/mail/templates/built-in-templates.d.ts +47 -0
- package/dist/mail/templates/built-in-templates.d.ts.map +1 -0
- package/dist/mail/templates/built-in-templates.js +416 -0
- package/dist/mail/templates/built-in-templates.js.map +1 -0
- package/dist/mail/templates/custom-template-renderer.d.ts +115 -0
- package/dist/mail/templates/custom-template-renderer.d.ts.map +1 -0
- package/dist/mail/templates/custom-template-renderer.js +225 -0
- package/dist/mail/templates/custom-template-renderer.js.map +1 -0
- package/dist/mail/types.d.ts +7 -0
- package/dist/mail/types.d.ts.map +1 -0
- package/dist/mail/types.js +7 -0
- package/dist/mail/types.js.map +1 -0
- package/dist/routes/auth/captcha.d.ts +33 -0
- package/dist/routes/auth/captcha.d.ts.map +1 -0
- package/dist/routes/auth/captcha.js +102 -0
- package/dist/routes/auth/captcha.js.map +1 -0
- package/dist/routes/auth/change-password.d.ts +17 -0
- package/dist/routes/auth/change-password.d.ts.map +1 -0
- package/dist/routes/auth/change-password.js +121 -0
- package/dist/routes/auth/change-password.js.map +1 -0
- package/dist/routes/auth/index.d.ts +13 -0
- package/dist/routes/auth/index.d.ts.map +1 -0
- package/dist/routes/auth/index.js +35 -0
- package/dist/routes/auth/index.js.map +1 -0
- package/dist/routes/auth/mfa.d.ts +121 -0
- package/dist/routes/auth/mfa.d.ts.map +1 -0
- package/dist/routes/auth/mfa.js +1143 -0
- package/dist/routes/auth/mfa.js.map +1 -0
- package/dist/routes/auth/oauth.d.ts +37 -0
- package/dist/routes/auth/oauth.d.ts.map +1 -0
- package/dist/routes/auth/oauth.js +420 -0
- package/dist/routes/auth/oauth.js.map +1 -0
- package/dist/routes/auth/oauth2-server.d.ts +70 -0
- package/dist/routes/auth/oauth2-server.d.ts.map +1 -0
- package/dist/routes/auth/oauth2-server.js +775 -0
- package/dist/routes/auth/oauth2-server.js.map +1 -0
- package/dist/routes/auth/passkey.d.ts +65 -0
- package/dist/routes/auth/passkey.d.ts.map +1 -0
- package/dist/routes/auth/passkey.js +910 -0
- package/dist/routes/auth/passkey.js.map +1 -0
- package/dist/routes/auth/password-reset.d.ts +23 -0
- package/dist/routes/auth/password-reset.d.ts.map +1 -0
- package/dist/routes/auth/password-reset.js +336 -0
- package/dist/routes/auth/password-reset.js.map +1 -0
- package/dist/routes/handlers/audit.d.ts +21 -0
- package/dist/routes/handlers/audit.d.ts.map +1 -0
- package/dist/routes/handlers/audit.js +124 -0
- package/dist/routes/handlers/audit.js.map +1 -0
- package/dist/routes/handlers/auth.d.ts +150 -0
- package/dist/routes/handlers/auth.d.ts.map +1 -0
- package/dist/routes/handlers/auth.js +512 -0
- package/dist/routes/handlers/auth.js.map +1 -0
- package/dist/routes/handlers/base.d.ts +34 -0
- package/dist/routes/handlers/base.d.ts.map +1 -0
- package/dist/routes/handlers/base.js +366 -0
- package/dist/routes/handlers/base.js.map +1 -0
- package/dist/routes/handlers/config.d.ts +31 -0
- package/dist/routes/handlers/config.d.ts.map +1 -0
- package/dist/routes/handlers/config.js +483 -0
- package/dist/routes/handlers/config.js.map +1 -0
- package/dist/routes/handlers/documents.d.ts +50 -0
- package/dist/routes/handlers/documents.d.ts.map +1 -0
- package/dist/routes/handlers/documents.js +708 -0
- package/dist/routes/handlers/documents.js.map +1 -0
- package/dist/routes/handlers/index.d.ts +12 -0
- package/dist/routes/handlers/index.d.ts.map +1 -0
- package/dist/routes/handlers/index.js +11 -0
- package/dist/routes/handlers/index.js.map +1 -0
- package/dist/routes/handlers/media.d.ts +24 -0
- package/dist/routes/handlers/media.d.ts.map +1 -0
- package/dist/routes/handlers/media.js +432 -0
- package/dist/routes/handlers/media.js.map +1 -0
- package/dist/routes/handlers/search.d.ts +10 -0
- package/dist/routes/handlers/search.d.ts.map +1 -0
- package/dist/routes/handlers/search.js +153 -0
- package/dist/routes/handlers/search.js.map +1 -0
- package/dist/routes/handlers/tokens.d.ts +14 -0
- package/dist/routes/handlers/tokens.d.ts.map +1 -0
- package/dist/routes/handlers/tokens.js +109 -0
- package/dist/routes/handlers/tokens.js.map +1 -0
- package/dist/routes/handlers/types.d.ts +13 -0
- package/dist/routes/handlers/types.d.ts.map +1 -0
- package/dist/routes/handlers/types.js +5 -0
- package/dist/routes/handlers/types.js.map +1 -0
- package/dist/routes/handlers/users.d.ts +16 -0
- package/dist/routes/handlers/users.d.ts.map +1 -0
- package/dist/routes/handlers/users.js +198 -0
- package/dist/routes/handlers/users.js.map +1 -0
- package/dist/routes/handlers/webhooks.d.ts +37 -0
- package/dist/routes/handlers/webhooks.d.ts.map +1 -0
- package/dist/routes/handlers/webhooks.js +343 -0
- package/dist/routes/handlers/webhooks.js.map +1 -0
- package/dist/routes/index.d.ts +5 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +5 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/routes.d.ts +29 -0
- package/dist/routes/routes.d.ts.map +1 -0
- package/dist/routes/routes.js +531 -0
- package/dist/routes/routes.js.map +1 -0
- package/dist/routes/slug-processor.d.ts +32 -0
- package/dist/routes/slug-processor.d.ts.map +1 -0
- package/dist/routes/slug-processor.js +328 -0
- package/dist/routes/slug-processor.js.map +1 -0
- package/dist/routes/types.d.ts +31 -0
- package/dist/routes/types.d.ts.map +1 -0
- package/dist/routes/types.js +7 -0
- package/dist/routes/types.js.map +1 -0
- package/dist/routes/users/index.d.ts +7 -0
- package/dist/routes/users/index.d.ts.map +1 -0
- package/dist/routes/users/index.js +7 -0
- package/dist/routes/users/index.js.map +1 -0
- package/dist/structure/builder/StructureBuilder.d.ts +209 -0
- package/dist/structure/builder/StructureBuilder.d.ts.map +1 -0
- package/dist/structure/builder/StructureBuilder.js +425 -0
- package/dist/structure/builder/StructureBuilder.js.map +1 -0
- package/dist/structure/builder/index.d.ts +8 -0
- package/dist/structure/builder/index.d.ts.map +1 -0
- package/dist/structure/builder/index.js +6 -0
- package/dist/structure/builder/index.js.map +1 -0
- package/dist/structure/builder/navigation-tree-builder.d.ts +33 -0
- package/dist/structure/builder/navigation-tree-builder.d.ts.map +1 -0
- package/dist/structure/builder/navigation-tree-builder.js +284 -0
- package/dist/structure/builder/navigation-tree-builder.js.map +1 -0
- package/dist/structure/errors/index.d.ts +72 -0
- package/dist/structure/errors/index.d.ts.map +1 -0
- package/dist/structure/errors/index.js +136 -0
- package/dist/structure/errors/index.js.map +1 -0
- package/dist/structure/index.d.ts +14 -0
- package/dist/structure/index.d.ts.map +1 -0
- package/dist/structure/index.js +16 -0
- package/dist/structure/index.js.map +1 -0
- package/dist/structure/types/filters.d.ts +167 -0
- package/dist/structure/types/filters.d.ts.map +1 -0
- package/dist/structure/types/filters.js +38 -0
- package/dist/structure/types/filters.js.map +1 -0
- package/dist/structure/types/index.d.ts +11 -0
- package/dist/structure/types/index.d.ts.map +1 -0
- package/dist/structure/types/index.js +7 -0
- package/dist/structure/types/index.js.map +1 -0
- package/dist/structure/types/permissions.d.ts +159 -0
- package/dist/structure/types/permissions.d.ts.map +1 -0
- package/dist/structure/types/permissions.js +49 -0
- package/dist/structure/types/permissions.js.map +1 -0
- package/dist/structure/types/structure.d.ts +342 -0
- package/dist/structure/types/structure.d.ts.map +1 -0
- package/dist/structure/types/structure.js +6 -0
- package/dist/structure/types/structure.js.map +1 -0
- package/dist/structure/types/views.d.ts +278 -0
- package/dist/structure/types/views.d.ts.map +1 -0
- package/dist/structure/types/views.js +6 -0
- package/dist/structure/types/views.js.map +1 -0
- package/dist/structure/utils/hash.d.ts +61 -0
- package/dist/structure/utils/hash.d.ts.map +1 -0
- package/dist/structure/utils/hash.js +118 -0
- package/dist/structure/utils/hash.js.map +1 -0
- package/dist/structure/utils/index.d.ts +10 -0
- package/dist/structure/utils/index.d.ts.map +1 -0
- package/dist/structure/utils/index.js +7 -0
- package/dist/structure/utils/index.js.map +1 -0
- package/dist/structure/utils/permission-checker.d.ts +57 -0
- package/dist/structure/utils/permission-checker.d.ts.map +1 -0
- package/dist/structure/utils/permission-checker.js +286 -0
- package/dist/structure/utils/permission-checker.js.map +1 -0
- package/dist/structure/utils/query-builder.d.ts +82 -0
- package/dist/structure/utils/query-builder.d.ts.map +1 -0
- package/dist/structure/utils/query-builder.js +489 -0
- package/dist/structure/utils/query-builder.js.map +1 -0
- package/dist/structure/utils/structure-merger.d.ts +91 -0
- package/dist/structure/utils/structure-merger.d.ts.map +1 -0
- package/dist/structure/utils/structure-merger.js +445 -0
- package/dist/structure/utils/structure-merger.js.map +1 -0
- package/dist/structure/validation/schemas.d.ts +3107 -0
- package/dist/structure/validation/schemas.d.ts.map +1 -0
- package/dist/structure/validation/schemas.js +436 -0
- package/dist/structure/validation/schemas.js.map +1 -0
- package/dist/types/api-requests.d.ts +334 -0
- package/dist/types/api-requests.d.ts.map +1 -0
- package/dist/types/api-requests.js +8 -0
- package/dist/types/api-requests.js.map +1 -0
- package/dist/types/auth.d.ts +394 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +8 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/document.d.ts +49 -0
- package/dist/types/document.d.ts.map +1 -0
- package/dist/types/document.js +6 -0
- package/dist/types/document.js.map +1 -0
- package/dist/types/field-system.d.ts +197 -0
- package/dist/types/field-system.d.ts.map +1 -0
- package/dist/types/field-system.js +8 -0
- package/dist/types/field-system.js.map +1 -0
- package/dist/types/fields.d.ts +17 -0
- package/dist/types/fields.d.ts.map +1 -0
- package/dist/types/fields.js +21 -0
- package/dist/types/fields.js.map +1 -0
- package/dist/types/http.d.ts +162 -0
- package/dist/types/http.d.ts.map +1 -0
- package/dist/types/http.js +8 -0
- package/dist/types/http.js.map +1 -0
- package/dist/types/i18n.d.ts +56 -0
- package/dist/types/i18n.d.ts.map +1 -0
- package/dist/types/i18n.js +25 -0
- package/dist/types/i18n.js.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mail.d.ts +224 -0
- package/dist/types/mail.d.ts.map +1 -0
- package/dist/types/mail.js +8 -0
- package/dist/types/mail.js.map +1 -0
- package/dist/types/media.d.ts +56 -0
- package/dist/types/media.d.ts.map +1 -0
- package/dist/types/media.js +6 -0
- package/dist/types/media.js.map +1 -0
- package/dist/types/oauth2.d.ts +287 -0
- package/dist/types/oauth2.d.ts.map +1 -0
- package/dist/types/oauth2.js +43 -0
- package/dist/types/oauth2.js.map +1 -0
- package/dist/types/passkey.d.ts +217 -0
- package/dist/types/passkey.d.ts.map +1 -0
- package/dist/types/passkey.js +8 -0
- package/dist/types/passkey.js.map +1 -0
- package/dist/types/slug.d.ts +99 -0
- package/dist/types/slug.d.ts.map +1 -0
- package/dist/types/slug.js +8 -0
- package/dist/types/slug.js.map +1 -0
- package/package.json +183 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentRoutes - Collection and document route handlers
|
|
3
|
+
*/
|
|
4
|
+
import { SecurityValidator, InvalidInputError, expandDocumentReferences, parseExpandParam } from '../../core/index.js';
|
|
5
|
+
import { processSlugFields } from '../slug-processor.js';
|
|
6
|
+
import { isSingletonSchema, collectStructureSingletons } from '../../core/schema/singleton.js';
|
|
7
|
+
import { BaseRoutes } from './base.js';
|
|
8
|
+
/** System fields that clients may send back but must never overwrite storage-managed values */
|
|
9
|
+
const PRESERVED_SYSTEM_FIELDS = new Set(['_status', '_type']);
|
|
10
|
+
/**
|
|
11
|
+
* Remove client-sent system fields (keys starting with "_") from document data.
|
|
12
|
+
* _status and _type are content-level fields and are preserved.
|
|
13
|
+
*/
|
|
14
|
+
function stripSystemFields(data) {
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const [key, value] of Object.entries(data)) {
|
|
17
|
+
if (key.startsWith('_') && !PRESERVED_SYSTEM_FIELDS.has(key)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
result[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
export class DocumentRoutes extends BaseRoutes {
|
|
25
|
+
getRoutes() {
|
|
26
|
+
const basePath = this.config.basePath || '';
|
|
27
|
+
return this.defineRoutes([
|
|
28
|
+
['GET', `${basePath}/collections`, this.listCollections.bind(this)],
|
|
29
|
+
['GET', `${basePath}/collections/:collection`, this.listDocuments.bind(this)],
|
|
30
|
+
['POST', `${basePath}/collections/:collection`, this.createDocument.bind(this)],
|
|
31
|
+
['GET', `${basePath}/collections/:collection/:id`, this.getDocument.bind(this)],
|
|
32
|
+
['PUT', `${basePath}/collections/:collection/:id`, this.updateDocument.bind(this)],
|
|
33
|
+
['DELETE', `${basePath}/collections/:collection/:id`, this.deleteDocument.bind(this)],
|
|
34
|
+
['GET', `${basePath}/stats/:collection`, this.getCollectionStats.bind(this)],
|
|
35
|
+
['GET', `${basePath}/slugs/check-unique`, this.checkSlugUniqueness.bind(this)]
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
// Route handlers
|
|
39
|
+
async listCollections(request) {
|
|
40
|
+
try {
|
|
41
|
+
// SECURITY: Validate authentication before processing
|
|
42
|
+
await this.validateAuthentication(request);
|
|
43
|
+
// Get all schemas from the core engine
|
|
44
|
+
const schemas = this.core.getAllSchemas();
|
|
45
|
+
this.logger.debug('Collections listed', {
|
|
46
|
+
count: schemas.length,
|
|
47
|
+
collections: schemas.map(s => s.name)
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
status: 200,
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
...this.buildCorsHeaders()
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
success: true,
|
|
57
|
+
data: {
|
|
58
|
+
collections: schemas
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
this.logger.error('Failed to list collections', { error: error instanceof Error ? error.message : String(error) });
|
|
65
|
+
// Delegate to errorResponse so authentication failures map to 401
|
|
66
|
+
// rather than being flattened into 400 here.
|
|
67
|
+
if (error instanceof InvalidInputError) {
|
|
68
|
+
return this.errorResponse(error);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
status: 500,
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
success: false,
|
|
75
|
+
error: {
|
|
76
|
+
code: 'INTERNAL_ERROR',
|
|
77
|
+
message: 'Failed to list collections'
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async listDocuments(request) {
|
|
84
|
+
try {
|
|
85
|
+
// SECURITY: Validate authentication and schema read permissions
|
|
86
|
+
await this.validateAuthentication(request);
|
|
87
|
+
const { collection } = request.params;
|
|
88
|
+
await this.validateSchemaAccess(request, collection, 'read');
|
|
89
|
+
const { limit, offset, filter, sort, page, search } = request.query;
|
|
90
|
+
// Validate collection name
|
|
91
|
+
SecurityValidator.validateCollectionName(collection);
|
|
92
|
+
// Build list options - handle both offset and page-based pagination
|
|
93
|
+
const options = {};
|
|
94
|
+
// Handle pagination (page-based or offset-based)
|
|
95
|
+
if (page && limit) {
|
|
96
|
+
const pageNum = parseInt(String(page), 10);
|
|
97
|
+
const limitNum = parseInt(String(limit), 10);
|
|
98
|
+
options.limit = limitNum;
|
|
99
|
+
options.offset = (pageNum - 1) * limitNum;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
if (limit)
|
|
103
|
+
options.limit = parseInt(String(limit), 10);
|
|
104
|
+
if (offset)
|
|
105
|
+
options.offset = parseInt(String(offset), 10);
|
|
106
|
+
}
|
|
107
|
+
// Handle filters - parse bracket notation from query params
|
|
108
|
+
// Studio sends filter[field]=value which Express parses as nested object
|
|
109
|
+
if (filter) {
|
|
110
|
+
try {
|
|
111
|
+
if (typeof filter === 'string') {
|
|
112
|
+
// Try parsing as JSON string
|
|
113
|
+
options.filter = JSON.parse(filter);
|
|
114
|
+
}
|
|
115
|
+
else if (typeof filter === 'object' && filter !== null) {
|
|
116
|
+
// Already parsed by Express query parser
|
|
117
|
+
options.filter = filter;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new InvalidInputError('Invalid filter format', 'filter');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Handle sorting - convert prefix notation to field.direction
|
|
125
|
+
// Studio sends "-field" for desc, "field" for asc
|
|
126
|
+
if (sort) {
|
|
127
|
+
if (typeof sort === 'string' && sort.startsWith('-')) {
|
|
128
|
+
options.sort = `${sort.substring(1)}.desc`;
|
|
129
|
+
}
|
|
130
|
+
else if (typeof sort === 'string' && !sort.includes('.') && !sort.includes(':')) {
|
|
131
|
+
options.sort = `${sort}.asc`;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
options.sort = sort;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let documents = await this.core.listDocuments(collection, options);
|
|
138
|
+
// Get total count BEFORE search filtering (but after listDocuments)
|
|
139
|
+
// Call dataStorage directly since countDocuments is optional and not on core
|
|
140
|
+
const dataStorage = this.core.dataStorage;
|
|
141
|
+
let totalCount;
|
|
142
|
+
if (dataStorage && dataStorage.countDocuments) {
|
|
143
|
+
// Use adapter's count method with the same filter
|
|
144
|
+
totalCount = await dataStorage.countDocuments(collection, options.filter || {});
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Fallback to document length if countDocuments not available
|
|
148
|
+
totalCount = documents.length;
|
|
149
|
+
}
|
|
150
|
+
// Handle search filtering - simple client-side text search
|
|
151
|
+
if (search && typeof search === 'string' && search.trim()) {
|
|
152
|
+
const searchLower = search.trim().toLowerCase();
|
|
153
|
+
documents = documents.filter(doc => {
|
|
154
|
+
// Search across common text fields
|
|
155
|
+
const searchableText = [
|
|
156
|
+
doc.name,
|
|
157
|
+
doc.title,
|
|
158
|
+
doc.description,
|
|
159
|
+
doc.excerpt,
|
|
160
|
+
doc.bio,
|
|
161
|
+
doc.slug,
|
|
162
|
+
doc._id
|
|
163
|
+
].filter(Boolean).join(' ').toLowerCase();
|
|
164
|
+
return searchableText.includes(searchLower);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Handle reference expansion if requested
|
|
168
|
+
const { expand } = request.query;
|
|
169
|
+
if (expand && documents.length > 0) {
|
|
170
|
+
const schema = this.core.getSchema(collection);
|
|
171
|
+
const expandFields = parseExpandParam(expand, schema || undefined);
|
|
172
|
+
if (expandFields.length > 0) {
|
|
173
|
+
// Create a document fetcher that uses the core
|
|
174
|
+
const fetchDocument = async (refCollection, refId) => {
|
|
175
|
+
return this.core.getDocument(refCollection, refId);
|
|
176
|
+
};
|
|
177
|
+
// Expand references in all documents
|
|
178
|
+
documents = await Promise.all(documents.map(doc => expandDocumentReferences(doc, { fields: expandFields }, fetchDocument)));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Use actual database count, not filtered result length
|
|
182
|
+
const total = totalCount;
|
|
183
|
+
// Calculate pagination metadata
|
|
184
|
+
const currentPage = page ? parseInt(String(page), 10) : 1;
|
|
185
|
+
const pageSize = options.limit || 25;
|
|
186
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
187
|
+
return this.successResponse({
|
|
188
|
+
documents,
|
|
189
|
+
pagination: {
|
|
190
|
+
page: currentPage,
|
|
191
|
+
limit: pageSize,
|
|
192
|
+
total,
|
|
193
|
+
pages: totalPages
|
|
194
|
+
},
|
|
195
|
+
// Legacy meta for backward compatibility
|
|
196
|
+
meta: {
|
|
197
|
+
total,
|
|
198
|
+
limit: options.limit,
|
|
199
|
+
offset: options.offset
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
return this.errorResponse(error);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async createDocument(request) {
|
|
208
|
+
try {
|
|
209
|
+
// SECURITY: Validate authentication and schema write permissions
|
|
210
|
+
await this.validateAuthentication(request);
|
|
211
|
+
const { collection } = request.params;
|
|
212
|
+
await this.validateSchemaAccess(request, collection, 'write');
|
|
213
|
+
// Get current user for audit context
|
|
214
|
+
const currentUser = await this.getCurrentUser(request);
|
|
215
|
+
const auditContext = currentUser ? {
|
|
216
|
+
userId: currentUser.id,
|
|
217
|
+
userType: 'USER',
|
|
218
|
+
username: currentUser.username,
|
|
219
|
+
ipAddress: request.headers['x-forwarded-for'] || request.headers['x-real-ip'],
|
|
220
|
+
userAgent: request.headers['user-agent']
|
|
221
|
+
} : undefined;
|
|
222
|
+
// SECURITY: Validate request body structure before type assertion
|
|
223
|
+
if (!request.body || typeof request.body !== 'object') {
|
|
224
|
+
throw new InvalidInputError('Request body is required', 'body');
|
|
225
|
+
}
|
|
226
|
+
const body = request.body;
|
|
227
|
+
if (!('data' in body) || !body.data || typeof body.data !== 'object') {
|
|
228
|
+
throw new InvalidInputError('Document data is required', 'data');
|
|
229
|
+
}
|
|
230
|
+
const { data, id } = body;
|
|
231
|
+
// Validate inputs
|
|
232
|
+
SecurityValidator.validateCollectionName(collection);
|
|
233
|
+
SecurityValidator.validateDocumentData(data);
|
|
234
|
+
this.logger.debug('Creating document', { collection, data, id });
|
|
235
|
+
// SINGLETON VALIDATION: Check if this collection is a singleton and prevent duplicate creation
|
|
236
|
+
await this.validateSingletonCreation(collection, id);
|
|
237
|
+
// Strip client-sent system fields so they cannot shadow storage-managed values
|
|
238
|
+
const cleanData = stripSystemFields(data);
|
|
239
|
+
// Process slug fields - auto-generate slugs from source fields if not provided
|
|
240
|
+
const processedData = await processSlugFields(this.core, collection, cleanData);
|
|
241
|
+
const document = await this.core.saveDocument(collection, { ...processedData, id }, auditContext);
|
|
242
|
+
return this.successResponse({ document }, 201);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
this.logger.error('Failed to create document', {
|
|
246
|
+
collection: request.params.collection,
|
|
247
|
+
error: error instanceof Error ? error.message : String(error),
|
|
248
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
249
|
+
requestBody: request.body
|
|
250
|
+
});
|
|
251
|
+
return this.errorResponse(error);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async getDocument(request) {
|
|
255
|
+
try {
|
|
256
|
+
// SECURITY: Validate authentication and schema read permissions
|
|
257
|
+
await this.validateAuthentication(request);
|
|
258
|
+
const { collection, id } = request.params;
|
|
259
|
+
await this.validateSchemaAccess(request, collection, 'read');
|
|
260
|
+
// Validate inputs
|
|
261
|
+
SecurityValidator.validateCollectionName(collection);
|
|
262
|
+
SecurityValidator.validateDocumentId(id);
|
|
263
|
+
let document = await this.core.getDocument(collection, id);
|
|
264
|
+
// If document not found, check if this is a singleton that should be auto-created
|
|
265
|
+
if (!document) {
|
|
266
|
+
const singletonDocument = await this.tryAutoCreateSingleton(collection, id);
|
|
267
|
+
if (singletonDocument) {
|
|
268
|
+
document = singletonDocument;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
return this.errorResponse(new Error(`Document ${collection}/${id} not found`), 404);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Handle reference expansion if requested
|
|
275
|
+
const { expand } = request.query;
|
|
276
|
+
if (expand && document) {
|
|
277
|
+
const schema = this.core.getSchema(collection);
|
|
278
|
+
const expandFields = parseExpandParam(expand, schema || undefined);
|
|
279
|
+
if (expandFields.length > 0) {
|
|
280
|
+
// Create a document fetcher that uses the core
|
|
281
|
+
const fetchDocument = async (refCollection, refId) => {
|
|
282
|
+
return this.core.getDocument(refCollection, refId);
|
|
283
|
+
};
|
|
284
|
+
document = await expandDocumentReferences(document, { fields: expandFields }, fetchDocument);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return this.successResponse({ document });
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
return this.errorResponse(error);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async updateDocument(request) {
|
|
294
|
+
try {
|
|
295
|
+
// SECURITY: Validate authentication and schema write permissions
|
|
296
|
+
await this.validateAuthentication(request);
|
|
297
|
+
const { collection, id } = request.params;
|
|
298
|
+
await this.validateSchemaAccess(request, collection, 'write');
|
|
299
|
+
// Get current user for audit context
|
|
300
|
+
const currentUser = await this.getCurrentUser(request);
|
|
301
|
+
const auditContext = currentUser ? {
|
|
302
|
+
userId: currentUser.id,
|
|
303
|
+
userType: 'USER',
|
|
304
|
+
username: currentUser.username,
|
|
305
|
+
ipAddress: request.headers['x-forwarded-for'] || request.headers['x-real-ip'],
|
|
306
|
+
userAgent: request.headers['user-agent']
|
|
307
|
+
} : undefined;
|
|
308
|
+
// SECURITY: Validate request body structure before type assertion
|
|
309
|
+
if (!request.body || typeof request.body !== 'object') {
|
|
310
|
+
throw new InvalidInputError('Request body is required', 'body');
|
|
311
|
+
}
|
|
312
|
+
const body = request.body;
|
|
313
|
+
if (!('data' in body) || !body.data || typeof body.data !== 'object') {
|
|
314
|
+
throw new InvalidInputError('Document data is required', 'data');
|
|
315
|
+
}
|
|
316
|
+
const { data } = body;
|
|
317
|
+
// Validate inputs
|
|
318
|
+
SecurityValidator.validateCollectionName(collection);
|
|
319
|
+
SecurityValidator.validateDocumentId(id);
|
|
320
|
+
SecurityValidator.validateDocumentData(data);
|
|
321
|
+
// Strip client-sent system fields so they cannot shadow storage-managed values
|
|
322
|
+
const cleanData = stripSystemFields(data);
|
|
323
|
+
// Get existing document to merge with updates
|
|
324
|
+
// For singletons, allow upsert (create if doesn't exist)
|
|
325
|
+
const schema = this.core.getSchema(collection);
|
|
326
|
+
const isSingleton = isSingletonSchema(schema);
|
|
327
|
+
const existingDoc = await this.core.getDocument(collection, id);
|
|
328
|
+
if (!existingDoc && !isSingleton) {
|
|
329
|
+
return this.errorResponse(new Error(`Document ${collection}/${id} not found`), 404);
|
|
330
|
+
}
|
|
331
|
+
// SECURITY: Check publish permission if status is being changed to/from 'published'
|
|
332
|
+
// This enforces the content:publish permission for publishing/unpublishing actions
|
|
333
|
+
const newStatus = cleanData._status;
|
|
334
|
+
const currentStatus = existingDoc?._status;
|
|
335
|
+
const isPublishing = newStatus === 'published' && currentStatus !== 'published';
|
|
336
|
+
const isUnpublishing = newStatus !== 'published' && currentStatus === 'published' && newStatus !== undefined;
|
|
337
|
+
if (isPublishing || isUnpublishing) {
|
|
338
|
+
await this.validateSchemaAccess(request, collection, 'publish');
|
|
339
|
+
}
|
|
340
|
+
// Merge data (excluding system fields including audit fields, but preserve _status)
|
|
341
|
+
let mergedData;
|
|
342
|
+
if (existingDoc) {
|
|
343
|
+
const { _id, _collection, _createdAt, _updatedAt, _revision, _createdBy, _updatedBy, _createdByType, _updatedByType, ...existingData } = existingDoc;
|
|
344
|
+
// Preserve _status from existing document if not explicitly provided in update data
|
|
345
|
+
if (!('_status' in cleanData) && existingDoc._status) {
|
|
346
|
+
mergedData = { ...existingData, ...cleanData, _status: existingDoc._status };
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
mergedData = { ...existingData, ...cleanData };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
// Singleton doesn't exist yet - create with provided data
|
|
354
|
+
mergedData = cleanData;
|
|
355
|
+
}
|
|
356
|
+
// Process slug fields - auto-generate slugs from source fields if not provided
|
|
357
|
+
// Pass the document ID to exclude it from uniqueness checks during updates
|
|
358
|
+
const processedData = await processSlugFields(this.core, collection, mergedData, id);
|
|
359
|
+
const document = await this.core.saveDocument(collection, { ...processedData, id }, auditContext);
|
|
360
|
+
return this.successResponse({ document });
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
return this.errorResponse(error);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
async deleteDocument(request) {
|
|
367
|
+
try {
|
|
368
|
+
// SECURITY: Validate authentication
|
|
369
|
+
await this.validateAuthentication(request);
|
|
370
|
+
const { collection, id } = request.params;
|
|
371
|
+
// Validate inputs
|
|
372
|
+
SecurityValidator.validateCollectionName(collection);
|
|
373
|
+
SecurityValidator.validateDocumentId(id);
|
|
374
|
+
// Get current user for ownership check
|
|
375
|
+
const currentUser = await this.getCurrentUser(request);
|
|
376
|
+
// Check if user has general delete permission
|
|
377
|
+
let hasDeletePermission = false;
|
|
378
|
+
try {
|
|
379
|
+
await this.validateSchemaAccess(request, collection, 'delete');
|
|
380
|
+
hasDeletePermission = true;
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// User doesn't have general delete permission, check ownership
|
|
384
|
+
hasDeletePermission = false;
|
|
385
|
+
}
|
|
386
|
+
// If no delete permission, check if user owns the document
|
|
387
|
+
if (!hasDeletePermission) {
|
|
388
|
+
if (!currentUser) {
|
|
389
|
+
throw new InvalidInputError('Insufficient permissions to delete this document', 'permissions');
|
|
390
|
+
}
|
|
391
|
+
// Fetch the document to check ownership
|
|
392
|
+
const document = await this.core.getDocument(collection, id);
|
|
393
|
+
if (!document) {
|
|
394
|
+
throw new InvalidInputError('Document not found', 'id');
|
|
395
|
+
}
|
|
396
|
+
// Check if user is the document creator
|
|
397
|
+
const isOwner = document._createdBy === currentUser.id ||
|
|
398
|
+
document._createdBy === currentUser.username;
|
|
399
|
+
if (!isOwner) {
|
|
400
|
+
throw new InvalidInputError('Insufficient permissions to delete this document. You can only delete documents you created.', 'permissions');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Get audit context from current user
|
|
404
|
+
const auditContext = currentUser ? {
|
|
405
|
+
userId: currentUser.id,
|
|
406
|
+
userType: 'USER',
|
|
407
|
+
username: currentUser.username,
|
|
408
|
+
ipAddress: request.headers['x-forwarded-for'] || request.headers['x-real-ip'],
|
|
409
|
+
userAgent: request.headers['user-agent']
|
|
410
|
+
} : undefined;
|
|
411
|
+
await this.core.deleteDocument(collection, id, auditContext);
|
|
412
|
+
return this.successResponse({ message: 'Document deleted successfully' });
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
return this.errorResponse(error);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async getCollectionStats(request) {
|
|
419
|
+
try {
|
|
420
|
+
// SECURITY: Validate authentication before processing
|
|
421
|
+
await this.validateAuthentication(request);
|
|
422
|
+
const { collection } = request.params;
|
|
423
|
+
// Validate collection name
|
|
424
|
+
SecurityValidator.validateCollectionName(collection);
|
|
425
|
+
// Use countDocuments to avoid loading all documents into memory
|
|
426
|
+
const [totalDocuments, publishedDocuments] = await Promise.all([
|
|
427
|
+
this.core.countDocuments(collection),
|
|
428
|
+
this.core.countDocuments(collection, { _status: 'published' })
|
|
429
|
+
]);
|
|
430
|
+
const draftDocuments = totalDocuments - publishedDocuments;
|
|
431
|
+
const stats = {
|
|
432
|
+
collection,
|
|
433
|
+
totalDocuments,
|
|
434
|
+
publishedDocuments,
|
|
435
|
+
draftDocuments
|
|
436
|
+
};
|
|
437
|
+
this.logger.debug('Collection stats calculated', { collection, stats });
|
|
438
|
+
return this.successResponse({ stats });
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
return this.errorResponse(error);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async checkSlugUniqueness(request) {
|
|
445
|
+
try {
|
|
446
|
+
// SECURITY: Validate authentication before processing
|
|
447
|
+
await this.validateAuthentication(request);
|
|
448
|
+
const { slug, collection, excludeId } = request.query;
|
|
449
|
+
if (!slug || typeof slug !== 'string') {
|
|
450
|
+
throw new InvalidInputError('Slug parameter is required', 'slug');
|
|
451
|
+
}
|
|
452
|
+
if (!collection || typeof collection !== 'string') {
|
|
453
|
+
throw new InvalidInputError('Collection parameter is required', 'collection');
|
|
454
|
+
}
|
|
455
|
+
// Validate collection name and slug format
|
|
456
|
+
SecurityValidator.validateCollectionName(collection);
|
|
457
|
+
// Removed overly restrictive slug format validation
|
|
458
|
+
// Slug format should be validated by the schema field definition, not here
|
|
459
|
+
// This allows slugs to respect schema-level options like allowSlashes, preserveCase, allowedChars
|
|
460
|
+
// Basic check: just ensure it's not empty
|
|
461
|
+
if (!slug || slug.trim() === '') {
|
|
462
|
+
return this.successResponse({
|
|
463
|
+
unique: false,
|
|
464
|
+
reason: 'Slug cannot be empty'
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
// Check if slug exists in the collection
|
|
468
|
+
const documents = await this.core.listDocuments(collection, {
|
|
469
|
+
filter: { slug: slug }
|
|
470
|
+
});
|
|
471
|
+
// If excludeId is provided, filter out that document (for updates)
|
|
472
|
+
const conflictingDocs = excludeId
|
|
473
|
+
? documents.filter(doc => doc._id !== excludeId)
|
|
474
|
+
: documents;
|
|
475
|
+
const isUnique = conflictingDocs.length === 0;
|
|
476
|
+
const responseData = {
|
|
477
|
+
unique: isUnique,
|
|
478
|
+
slug: slug,
|
|
479
|
+
collection: collection,
|
|
480
|
+
...(isUnique ? {} : { reason: 'Slug already exists in collection' })
|
|
481
|
+
};
|
|
482
|
+
return this.successResponse(responseData);
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
this.logger.error('Error in checkSlugUniqueness', error);
|
|
486
|
+
return this.errorResponse(error);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Auto-create a singleton document the first time it is read.
|
|
491
|
+
*
|
|
492
|
+
* The schema decides whether the collection is a singleton. The structure only decides
|
|
493
|
+
* which document id that singleton lives under, and whether auto-creation is wanted at
|
|
494
|
+
* all; without a structure entry the id defaults to the collection name.
|
|
495
|
+
*/
|
|
496
|
+
async tryAutoCreateSingleton(collection, documentId) {
|
|
497
|
+
try {
|
|
498
|
+
if (!isSingletonSchema(this.core.getSchema(collection))) {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
// A structure may carry more than one entry for a collection; prefer the one that names
|
|
502
|
+
// the requested id so each entry's own document stays reachable.
|
|
503
|
+
const entries = (await this.resolveStructureSingletons()).filter(candidate => candidate.collection === collection);
|
|
504
|
+
const entry = entries.find(candidate => candidate.documentId === documentId) ?? entries[0];
|
|
505
|
+
// Only the singleton's own document is conjured up; any other id stays a 404.
|
|
506
|
+
const singletonId = entry?.documentId ?? collection;
|
|
507
|
+
if (documentId !== singletonId) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
if (entry && !entry.autoCreate) {
|
|
511
|
+
this.logger.debug('Singleton auto-creation disabled by structure', { collection, documentId });
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
// Never conjure up a second document. A singleton whose stored document sits under a
|
|
515
|
+
// different id than the structure asks for would otherwise gain an empty duplicate on
|
|
516
|
+
// the first read, which is the invariant the create guard exists to protect.
|
|
517
|
+
const existingDocuments = await this.core.listDocuments(collection, { limit: 1 });
|
|
518
|
+
if (existingDocuments && existingDocuments.length > 0) {
|
|
519
|
+
this.logger.warn('Not auto-creating singleton: the collection already holds a document', {
|
|
520
|
+
collection,
|
|
521
|
+
documentId,
|
|
522
|
+
existingDocument: existingDocuments[0].id
|
|
523
|
+
});
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
this.logger.info('Auto-creating singleton document', { collection, documentId });
|
|
527
|
+
// Create the singleton document with sensible defaults
|
|
528
|
+
const singletonData = {
|
|
529
|
+
id: documentId,
|
|
530
|
+
_type: collection,
|
|
531
|
+
title: this.formatSchemaTitle(collection),
|
|
532
|
+
slug: documentId, // Use documentId as slug for singletons
|
|
533
|
+
...this.getDefaultSingletonData(collection, documentId)
|
|
534
|
+
};
|
|
535
|
+
// Auto-created singleton uses system context
|
|
536
|
+
const systemContext = {
|
|
537
|
+
userId: 'system',
|
|
538
|
+
userType: 'SYSTEM',
|
|
539
|
+
username: 'system'
|
|
540
|
+
};
|
|
541
|
+
const document = await this.core.saveDocument(collection, singletonData, systemContext);
|
|
542
|
+
this.logger.info('Singleton document auto-created', { collection, documentId });
|
|
543
|
+
return document;
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
this.logger.error('Failed to auto-create singleton', { collection, documentId, error });
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Resolve the project's structure and collect its singleton entries.
|
|
552
|
+
*
|
|
553
|
+
* The structure is only consulted for presentation details — which id a singleton lives
|
|
554
|
+
* under and whether to auto-create it — never to decide whether a collection is one.
|
|
555
|
+
* A structure that cannot be resolved yields no entries rather than an error, so reads
|
|
556
|
+
* keep working on the schema alone.
|
|
557
|
+
*/
|
|
558
|
+
async resolveStructureSingletons() {
|
|
559
|
+
try {
|
|
560
|
+
const customStructure = this.getCustomStructureFunction();
|
|
561
|
+
if (!customStructure)
|
|
562
|
+
return [];
|
|
563
|
+
if (typeof customStructure === 'function') {
|
|
564
|
+
const context = {
|
|
565
|
+
user: null,
|
|
566
|
+
schemas: this.core.getAllSchemas(),
|
|
567
|
+
core: this.core,
|
|
568
|
+
config: this.config
|
|
569
|
+
};
|
|
570
|
+
return collectStructureSingletons(await Promise.resolve(customStructure(context)));
|
|
571
|
+
}
|
|
572
|
+
return collectStructureSingletons(customStructure);
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
this.logger.warn('Failed to resolve structure for singleton lookup', {
|
|
576
|
+
error: error instanceof Error ? error.message : String(error)
|
|
577
|
+
});
|
|
578
|
+
return [];
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Validate singleton creation to prevent duplicates
|
|
583
|
+
*/
|
|
584
|
+
async validateSingletonCreation(collection, requestedId) {
|
|
585
|
+
try {
|
|
586
|
+
if (!isSingletonSchema(this.core.getSchema(collection))) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
// Check if a singleton document already exists for this collection
|
|
590
|
+
const existingDocuments = await this.core.listDocuments(collection, { limit: 1 });
|
|
591
|
+
if (existingDocuments && existingDocuments.length > 0) {
|
|
592
|
+
this.logger.warn('Attempted to create duplicate singleton document', {
|
|
593
|
+
collection,
|
|
594
|
+
requestedId,
|
|
595
|
+
existingDocument: existingDocuments[0].id
|
|
596
|
+
});
|
|
597
|
+
throw new InvalidInputError(`Singleton document already exists for collection '${collection}'. Only one document is allowed.`, 'singleton_duplicate');
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
// Re-throw InvalidInputError as-is, wrap other errors
|
|
602
|
+
if (error instanceof InvalidInputError) {
|
|
603
|
+
throw error;
|
|
604
|
+
}
|
|
605
|
+
this.logger.error('Failed to validate singleton creation', {
|
|
606
|
+
collection,
|
|
607
|
+
requestedId,
|
|
608
|
+
error: error instanceof Error ? error.message : String(error)
|
|
609
|
+
});
|
|
610
|
+
// Don't fail the creation if validation fails, just log the error
|
|
611
|
+
// This ensures backward compatibility
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Get default data for specific singleton types
|
|
617
|
+
*/
|
|
618
|
+
getDefaultSingletonData(collection, documentId) {
|
|
619
|
+
// Get schema to generate proper defaults
|
|
620
|
+
const schema = this.core.getSchema(collection);
|
|
621
|
+
if (schema) {
|
|
622
|
+
return this.generateSchemaDefaults(schema);
|
|
623
|
+
}
|
|
624
|
+
// Fallback to hardcoded defaults
|
|
625
|
+
switch (collection) {
|
|
626
|
+
case 'homePage':
|
|
627
|
+
return {
|
|
628
|
+
title: 'Home Page',
|
|
629
|
+
description: 'Welcome to our website',
|
|
630
|
+
content: '<p>Welcome to our website! This is the homepage content.</p>',
|
|
631
|
+
slug: 'home'
|
|
632
|
+
};
|
|
633
|
+
case 'settings':
|
|
634
|
+
return {
|
|
635
|
+
title: 'Site Settings',
|
|
636
|
+
siteName: 'My Website',
|
|
637
|
+
description: 'A website built with Trokky'
|
|
638
|
+
};
|
|
639
|
+
default:
|
|
640
|
+
return {};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Generate default values based on schema definition
|
|
645
|
+
*/
|
|
646
|
+
generateSchemaDefaults(schema) {
|
|
647
|
+
const defaults = {};
|
|
648
|
+
if (schema.fields) {
|
|
649
|
+
for (const [fieldName, fieldDef] of Object.entries(schema.fields)) {
|
|
650
|
+
const field = fieldDef;
|
|
651
|
+
// Skip fields that start with underscore (system fields)
|
|
652
|
+
if (fieldName.startsWith('_')) {
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
if (field.default !== undefined) {
|
|
656
|
+
defaults[fieldName] = field.default;
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
const defaultValue = this.getFieldTypeDefault(field);
|
|
660
|
+
// Only include fields that have non-null/non-undefined defaults
|
|
661
|
+
// This prevents validation errors for optional fields like media, references, etc.
|
|
662
|
+
if (defaultValue !== null && defaultValue !== undefined) {
|
|
663
|
+
defaults[fieldName] = defaultValue;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return defaults;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Get default value for a field type
|
|
672
|
+
*/
|
|
673
|
+
getFieldTypeDefault(field) {
|
|
674
|
+
switch (field.type) {
|
|
675
|
+
case 'string':
|
|
676
|
+
return '';
|
|
677
|
+
case 'slug':
|
|
678
|
+
// Slug fields are auto-generated from title, don't provide a default
|
|
679
|
+
return undefined;
|
|
680
|
+
case 'number':
|
|
681
|
+
return 0;
|
|
682
|
+
case 'boolean':
|
|
683
|
+
return false;
|
|
684
|
+
case 'date':
|
|
685
|
+
return new Date().toISOString();
|
|
686
|
+
case 'array':
|
|
687
|
+
// Create empty array - items will be added through UI with proper _type
|
|
688
|
+
return [];
|
|
689
|
+
case 'object':
|
|
690
|
+
// Set _type to the field's name — this identifies the object type
|
|
691
|
+
// in polymorphic contexts (e.g., array items of different types).
|
|
692
|
+
// Matches Studio's ArrayField behavior which uses itemDefinition.name.
|
|
693
|
+
const baseObject = {};
|
|
694
|
+
if (field.name) {
|
|
695
|
+
baseObject._type = field.name;
|
|
696
|
+
}
|
|
697
|
+
return baseObject;
|
|
698
|
+
case 'reference':
|
|
699
|
+
return undefined;
|
|
700
|
+
case 'media':
|
|
701
|
+
// Media fields are optional, don't provide a default
|
|
702
|
+
return undefined;
|
|
703
|
+
default:
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
//# sourceMappingURL=documents.js.map
|