@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,639 @@
|
|
|
1
|
+
import { promises as fs, constants } from 'fs';
|
|
2
|
+
import * as fsExtra from 'fs-extra';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { SecurityValidator, InvalidInputError, createLogger } from '../../core/index.js';
|
|
5
|
+
export class FilesystemMediaAdapter {
|
|
6
|
+
config;
|
|
7
|
+
logger = createLogger('adapter', 'FilesystemMediaAdapter');
|
|
8
|
+
// Security limits
|
|
9
|
+
MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.config = {
|
|
12
|
+
mediaDir: config.mediaDir || './media',
|
|
13
|
+
createDirs: config.createDirs ?? true,
|
|
14
|
+
prettyJson: config.prettyJson ?? true,
|
|
15
|
+
jsonSpaces: config.jsonSpaces ?? 2,
|
|
16
|
+
syncWrites: config.syncWrites ?? false,
|
|
17
|
+
fileMode: config.fileMode ?? 0o644,
|
|
18
|
+
dirMode: config.dirMode ?? 0o755,
|
|
19
|
+
silent: config.silent ?? false,
|
|
20
|
+
mediaBaseUrl: config.mediaBaseUrl
|
|
21
|
+
};
|
|
22
|
+
// Initialize directories
|
|
23
|
+
if (this.config.createDirs) {
|
|
24
|
+
this.initializeDirectories();
|
|
25
|
+
}
|
|
26
|
+
if (!this.config.silent) {
|
|
27
|
+
this.logger.info('FilesystemMediaAdapter initialized', {
|
|
28
|
+
mediaDir: this.config.mediaDir
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async initializeDirectories() {
|
|
33
|
+
try {
|
|
34
|
+
await fsExtra.ensureDir(this.config.mediaDir, { mode: this.config.dirMode });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (!this.config.silent) {
|
|
38
|
+
this.logger.error('Failed to initialize media directories', error);
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ==========================================================================
|
|
44
|
+
// FILE OPERATIONS
|
|
45
|
+
// ==========================================================================
|
|
46
|
+
async uploadFile(file, metadata) {
|
|
47
|
+
try {
|
|
48
|
+
// Validate media metadata
|
|
49
|
+
this.validateMediaMetadata(metadata);
|
|
50
|
+
// Use secure path methods
|
|
51
|
+
const filePath = this.getMediaPath(metadata.id, metadata.extension);
|
|
52
|
+
const metadataPath = this.getMediaMetadataPath(metadata.id);
|
|
53
|
+
// Ensure media directory exists
|
|
54
|
+
await fsExtra.ensureDir(path.dirname(filePath), { mode: this.config.dirMode });
|
|
55
|
+
await fsExtra.ensureDir(path.dirname(metadataPath), { mode: this.config.dirMode });
|
|
56
|
+
// Write file content
|
|
57
|
+
const buffer = await this.fileToBuffer(file);
|
|
58
|
+
// Validate file size
|
|
59
|
+
if (buffer.length > this.MAX_FILE_SIZE) {
|
|
60
|
+
throw new InvalidInputError(`File too large (${buffer.length} bytes). Maximum size is ${this.MAX_FILE_SIZE} bytes.`, 'size');
|
|
61
|
+
}
|
|
62
|
+
await fs.writeFile(filePath, buffer, { mode: this.config.fileMode });
|
|
63
|
+
const now = new Date();
|
|
64
|
+
const fileMetadata = {
|
|
65
|
+
id: metadata.id,
|
|
66
|
+
filename: metadata.filename,
|
|
67
|
+
contentType: metadata.contentType,
|
|
68
|
+
size: metadata.size,
|
|
69
|
+
extension: metadata.extension,
|
|
70
|
+
originalPath: filePath,
|
|
71
|
+
createdAt: now,
|
|
72
|
+
updatedAt: now
|
|
73
|
+
};
|
|
74
|
+
// Write metadata atomically
|
|
75
|
+
const metadataContent = this.formatJson(fileMetadata);
|
|
76
|
+
await this.atomicWriteFile(metadataPath, metadataContent);
|
|
77
|
+
// Generate file URL (relative path for portability)
|
|
78
|
+
const relativeUrl = path.relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
79
|
+
const mediaFile = {
|
|
80
|
+
id: metadata.id,
|
|
81
|
+
filename: metadata.filename,
|
|
82
|
+
contentType: metadata.contentType,
|
|
83
|
+
size: metadata.size,
|
|
84
|
+
metadata: {
|
|
85
|
+
path: relativeUrl,
|
|
86
|
+
extension: metadata.extension,
|
|
87
|
+
originalFilename: metadata.filename
|
|
88
|
+
},
|
|
89
|
+
_createdAt: now
|
|
90
|
+
};
|
|
91
|
+
if (!this.config.silent) {
|
|
92
|
+
this.logger.info('File uploaded', {
|
|
93
|
+
id: metadata.id,
|
|
94
|
+
filename: metadata.filename,
|
|
95
|
+
size: metadata.size
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return mediaFile;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.logger.error(`Failed to upload file ${metadata.filename}`, error);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async getFile(id) {
|
|
106
|
+
try {
|
|
107
|
+
SecurityValidator.validateDocumentId(id);
|
|
108
|
+
const metadataPath = this.getMediaMetadataPath(id);
|
|
109
|
+
// Check if metadata file exists
|
|
110
|
+
try {
|
|
111
|
+
await fs.access(metadataPath, constants.F_OK);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const metadataContent = await fs.readFile(metadataPath, 'utf-8');
|
|
117
|
+
const fileMetadata = this.safeParseJSON(metadataContent);
|
|
118
|
+
const filePath = this.getMediaPath(id, fileMetadata.extension);
|
|
119
|
+
// Check if actual file exists
|
|
120
|
+
try {
|
|
121
|
+
await fs.access(filePath, constants.F_OK);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Metadata exists but file is missing
|
|
125
|
+
this.logger.warn(`Media file ${id} metadata found but file is missing`);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const relativeUrl = path.relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
129
|
+
const mediaFile = {
|
|
130
|
+
id: fileMetadata.id,
|
|
131
|
+
filename: fileMetadata.filename,
|
|
132
|
+
contentType: fileMetadata.contentType,
|
|
133
|
+
size: fileMetadata.size,
|
|
134
|
+
metadata: {
|
|
135
|
+
path: relativeUrl,
|
|
136
|
+
extension: fileMetadata.extension,
|
|
137
|
+
originalFilename: fileMetadata.filename,
|
|
138
|
+
title: fileMetadata.title,
|
|
139
|
+
alt: fileMetadata.alt,
|
|
140
|
+
author: fileMetadata.author,
|
|
141
|
+
credit: fileMetadata.credit,
|
|
142
|
+
tags: fileMetadata.tags,
|
|
143
|
+
imageVariants: fileMetadata.imageVariants ?
|
|
144
|
+
await this.updateVariantUrls(fileMetadata.imageVariants, fileMetadata.id) :
|
|
145
|
+
undefined,
|
|
146
|
+
originalDimensions: fileMetadata.originalDimensions
|
|
147
|
+
},
|
|
148
|
+
_createdAt: fileMetadata.createdAt
|
|
149
|
+
};
|
|
150
|
+
return mediaFile;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
this.logger.error(`Failed to get file ${id}`, error);
|
|
154
|
+
throw new Error(`Failed to get file: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async updateFile(id, metadata) {
|
|
158
|
+
try {
|
|
159
|
+
SecurityValidator.validateDocumentId(id);
|
|
160
|
+
const metadataPath = this.getMediaMetadataPath(id);
|
|
161
|
+
// Check if metadata file exists
|
|
162
|
+
try {
|
|
163
|
+
await fs.access(metadataPath, constants.F_OK);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
throw new Error(`Media file ${id} not found`);
|
|
167
|
+
}
|
|
168
|
+
const metadataContent = await fs.readFile(metadataPath, 'utf-8');
|
|
169
|
+
const fileMetadata = this.safeParseJSON(metadataContent);
|
|
170
|
+
// Update metadata
|
|
171
|
+
const updatedMetadata = {
|
|
172
|
+
...fileMetadata,
|
|
173
|
+
...metadata,
|
|
174
|
+
id: fileMetadata.id, // Ensure ID cannot be changed
|
|
175
|
+
updatedAt: new Date()
|
|
176
|
+
};
|
|
177
|
+
// Write updated metadata
|
|
178
|
+
const jsonContent = this.formatJson(updatedMetadata);
|
|
179
|
+
await this.atomicWriteFile(metadataPath, jsonContent);
|
|
180
|
+
if (!this.config.silent) {
|
|
181
|
+
this.logger.info('File metadata updated', { id });
|
|
182
|
+
}
|
|
183
|
+
// Return updated media file
|
|
184
|
+
return (await this.getFile(id));
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
this.logger.error(`Failed to update file ${id}`, error);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async getFileContent(id) {
|
|
192
|
+
try {
|
|
193
|
+
SecurityValidator.validateDocumentId(id);
|
|
194
|
+
const mediaFile = await this.getFile(id);
|
|
195
|
+
if (!mediaFile) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
const filePath = this.getMediaPath(id, mediaFile.metadata?.extension);
|
|
199
|
+
try {
|
|
200
|
+
const buffer = await fs.readFile(filePath);
|
|
201
|
+
const sliced = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
202
|
+
// Ensure we return ArrayBuffer, not SharedArrayBuffer
|
|
203
|
+
if (sliced instanceof ArrayBuffer) {
|
|
204
|
+
return sliced;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
// Copy SharedArrayBuffer to ArrayBuffer
|
|
208
|
+
const arrayBuffer = new ArrayBuffer(sliced.byteLength);
|
|
209
|
+
new Uint8Array(arrayBuffer).set(new Uint8Array(sliced));
|
|
210
|
+
return arrayBuffer;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
this.logger.error(`Failed to get file content for ${id}`, error);
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async listMedia(options = {}) {
|
|
223
|
+
try {
|
|
224
|
+
// Check if media directory exists
|
|
225
|
+
try {
|
|
226
|
+
await fs.access(this.config.mediaDir, constants.F_OK);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return { items: [], total: 0 };
|
|
230
|
+
}
|
|
231
|
+
const files = await fs.readdir(this.config.mediaDir);
|
|
232
|
+
const metadataFiles = files.filter(file => file.endsWith('.meta.json'));
|
|
233
|
+
const mediaFiles = [];
|
|
234
|
+
for (const metadataFile of metadataFiles) {
|
|
235
|
+
try {
|
|
236
|
+
const id = metadataFile.replace('.meta.json', '');
|
|
237
|
+
// Read metadata directly - trust metadata as source of truth for listing
|
|
238
|
+
const metadataPath = this.getMediaMetadataPath(id);
|
|
239
|
+
const metadataContent = await fs.readFile(metadataPath, 'utf-8');
|
|
240
|
+
const fileMetadata = this.safeParseJSON(metadataContent);
|
|
241
|
+
// Check if actual file exists for logging purposes, but don't filter it out
|
|
242
|
+
const filePath = this.getMediaPath(id, fileMetadata.extension);
|
|
243
|
+
let fileExists = false;
|
|
244
|
+
try {
|
|
245
|
+
await fs.access(filePath, constants.F_OK);
|
|
246
|
+
fileExists = true;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// File doesn't exist, but we'll still include it in the listing
|
|
250
|
+
// Individual file serving will handle the missing file error when accessed
|
|
251
|
+
this.logger.warn(`Media file ${id} has metadata but file is missing at ${filePath}`);
|
|
252
|
+
}
|
|
253
|
+
const relativeUrl = path.relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
254
|
+
const mediaFile = {
|
|
255
|
+
id: fileMetadata.id,
|
|
256
|
+
filename: fileMetadata.filename,
|
|
257
|
+
contentType: fileMetadata.contentType,
|
|
258
|
+
size: fileMetadata.size,
|
|
259
|
+
metadata: {
|
|
260
|
+
path: relativeUrl,
|
|
261
|
+
extension: fileMetadata.extension,
|
|
262
|
+
originalFilename: fileMetadata.filename,
|
|
263
|
+
title: fileMetadata.title,
|
|
264
|
+
alt: fileMetadata.alt,
|
|
265
|
+
author: fileMetadata.author,
|
|
266
|
+
credit: fileMetadata.credit,
|
|
267
|
+
tags: fileMetadata.tags,
|
|
268
|
+
imageVariants: fileMetadata.imageVariants ?
|
|
269
|
+
await this.updateVariantUrls(fileMetadata.imageVariants, fileMetadata.id) :
|
|
270
|
+
undefined,
|
|
271
|
+
originalDimensions: fileMetadata.originalDimensions,
|
|
272
|
+
// Add file existence status for debugging
|
|
273
|
+
_fileExists: fileExists
|
|
274
|
+
},
|
|
275
|
+
_createdAt: fileMetadata.createdAt
|
|
276
|
+
};
|
|
277
|
+
mediaFiles.push(mediaFile);
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
this.logger.warn(`Skipping invalid metadata file ${metadataFile}`, error);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Apply filters
|
|
285
|
+
let filteredFiles = mediaFiles;
|
|
286
|
+
if (options.contentType) {
|
|
287
|
+
filteredFiles = filteredFiles.filter(file => file.contentType.includes(options.contentType));
|
|
288
|
+
}
|
|
289
|
+
if (options.sizeRange) {
|
|
290
|
+
filteredFiles = filteredFiles.filter(file => {
|
|
291
|
+
const size = file.size;
|
|
292
|
+
if (options.sizeRange.min && size < options.sizeRange.min)
|
|
293
|
+
return false;
|
|
294
|
+
if (options.sizeRange.max && size > options.sizeRange.max)
|
|
295
|
+
return false;
|
|
296
|
+
return true;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (options.dateRange) {
|
|
300
|
+
filteredFiles = filteredFiles.filter(file => {
|
|
301
|
+
const date = file._createdAt;
|
|
302
|
+
if (options.dateRange.from && date < options.dateRange.from)
|
|
303
|
+
return false;
|
|
304
|
+
if (options.dateRange.to && date > options.dateRange.to)
|
|
305
|
+
return false;
|
|
306
|
+
return true;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// Apply sorting - default to newest first if no sort specified
|
|
310
|
+
if (options.sort) {
|
|
311
|
+
this.sortMediaFiles(filteredFiles, options.sort, options.sortDirection);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
// Default: sort by date descending (newest first)
|
|
315
|
+
this.sortMediaFiles(filteredFiles, 'date', 'desc');
|
|
316
|
+
}
|
|
317
|
+
// Store total count before pagination
|
|
318
|
+
const total = filteredFiles.length;
|
|
319
|
+
// Apply pagination
|
|
320
|
+
const { offset = 0, limit } = options;
|
|
321
|
+
const start = offset;
|
|
322
|
+
const end = limit ? start + limit : undefined;
|
|
323
|
+
const items = filteredFiles.slice(start, end);
|
|
324
|
+
return { items, total };
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
this.logger.error('Failed to list media files', error);
|
|
328
|
+
throw new Error(`Failed to list media: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async deleteFile(id) {
|
|
332
|
+
try {
|
|
333
|
+
SecurityValidator.validateDocumentId(id);
|
|
334
|
+
const mediaFile = await this.getFile(id);
|
|
335
|
+
if (!mediaFile) {
|
|
336
|
+
throw new Error(`Media file ${id} not found`);
|
|
337
|
+
}
|
|
338
|
+
const filePath = this.getMediaPath(id, mediaFile.metadata?.extension);
|
|
339
|
+
const metadataPath = this.getMediaMetadataPath(id);
|
|
340
|
+
// Delete variant files first
|
|
341
|
+
await this.deleteVariantFiles(id);
|
|
342
|
+
// Delete metadata FIRST, then main file
|
|
343
|
+
// This ensures if file deletion fails, the file won't show up in listMedia()
|
|
344
|
+
// since listMedia() uses metadata files as source of truth
|
|
345
|
+
try {
|
|
346
|
+
await fs.unlink(metadataPath);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
if (error.code !== 'ENOENT') {
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Then delete main file
|
|
354
|
+
try {
|
|
355
|
+
await fs.unlink(filePath);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
if (error.code !== 'ENOENT') {
|
|
359
|
+
// File deletion failed after metadata removal
|
|
360
|
+
// Log for manual cleanup, but metadata is already gone
|
|
361
|
+
this.logger.error('File deletion failed after metadata removal', {
|
|
362
|
+
id,
|
|
363
|
+
filePath,
|
|
364
|
+
error: error.message
|
|
365
|
+
});
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (!this.config.silent) {
|
|
370
|
+
this.logger.debug('File deleted', { id });
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
this.logger.error(`Failed to delete file ${id}`, error);
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// ==========================================================================
|
|
379
|
+
// VARIANT OPERATIONS
|
|
380
|
+
// ==========================================================================
|
|
381
|
+
async saveVariantFile(parentId, variantName, buffer, format) {
|
|
382
|
+
try {
|
|
383
|
+
SecurityValidator.validateDocumentId(parentId);
|
|
384
|
+
SecurityValidator.validateDocumentId(variantName);
|
|
385
|
+
// Create variants directory if it doesn't exist
|
|
386
|
+
const variantsDir = path.join(this.config.mediaDir, 'variants');
|
|
387
|
+
await fsExtra.ensureDir(variantsDir, { mode: this.config.dirMode });
|
|
388
|
+
// Create parent directory for this image's variants
|
|
389
|
+
const parentVariantsDir = path.join(variantsDir, parentId);
|
|
390
|
+
await fsExtra.ensureDir(parentVariantsDir, { mode: this.config.dirMode });
|
|
391
|
+
// Save variant file
|
|
392
|
+
const variantFilename = `${variantName}.${format}`;
|
|
393
|
+
const variantPath = path.join(parentVariantsDir, variantFilename);
|
|
394
|
+
await fs.writeFile(variantPath, buffer, { mode: this.config.fileMode });
|
|
395
|
+
if (!this.config.silent) {
|
|
396
|
+
this.logger.info('Variant file saved', { parentId, variantName, format });
|
|
397
|
+
}
|
|
398
|
+
// Return relative path for URL generation
|
|
399
|
+
return `variants/${parentId}/${variantFilename}`;
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
this.logger.error(`Failed to save variant file ${parentId}/${variantName}`, error);
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async getVariantContent(parentId, variantName) {
|
|
407
|
+
try {
|
|
408
|
+
SecurityValidator.validateDocumentId(parentId);
|
|
409
|
+
SecurityValidator.validateDocumentId(variantName);
|
|
410
|
+
// First check if the parent media file exists
|
|
411
|
+
const mediaFile = await this.getFile(parentId);
|
|
412
|
+
if (!mediaFile) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
// Get variant info from metadata to determine format
|
|
416
|
+
const variants = mediaFile.metadata?.imageVariants;
|
|
417
|
+
if (!variants || !variants[variantName]) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
const variantInfo = variants[variantName];
|
|
421
|
+
const variantFilename = `${variantName}.${variantInfo.format || 'webp'}`;
|
|
422
|
+
const variantPath = path.join(this.config.mediaDir, 'variants', parentId, variantFilename);
|
|
423
|
+
// Security check: ensure the resolved path is still within the media directory
|
|
424
|
+
const resolvedPath = path.resolve(variantPath);
|
|
425
|
+
const mediaBaseDir = path.resolve(this.config.mediaDir);
|
|
426
|
+
if (!resolvedPath.startsWith(mediaBaseDir)) {
|
|
427
|
+
throw new Error('Access denied: path traversal detected');
|
|
428
|
+
}
|
|
429
|
+
// Check if variant file exists
|
|
430
|
+
try {
|
|
431
|
+
await fs.access(resolvedPath, constants.F_OK);
|
|
432
|
+
const stats = await fs.stat(resolvedPath);
|
|
433
|
+
if (!stats.isFile()) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
// Read and return variant file content
|
|
441
|
+
const buffer = await fs.readFile(resolvedPath);
|
|
442
|
+
const sliced = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
443
|
+
// Ensure we return ArrayBuffer, not SharedArrayBuffer
|
|
444
|
+
if (sliced instanceof ArrayBuffer) {
|
|
445
|
+
return sliced;
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
// Copy SharedArrayBuffer to ArrayBuffer
|
|
449
|
+
const arrayBuffer = new ArrayBuffer(sliced.byteLength);
|
|
450
|
+
new Uint8Array(arrayBuffer).set(new Uint8Array(sliced));
|
|
451
|
+
return arrayBuffer;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
this.logger.error(`Failed to get variant content for ${parentId}/${variantName}`, error);
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async deleteVariantFiles(parentId) {
|
|
460
|
+
try {
|
|
461
|
+
SecurityValidator.validateDocumentId(parentId);
|
|
462
|
+
const parentVariantsDir = path.join(this.config.mediaDir, 'variants', parentId);
|
|
463
|
+
// Check if directory exists before trying to delete
|
|
464
|
+
try {
|
|
465
|
+
await fs.access(parentVariantsDir, constants.F_OK);
|
|
466
|
+
await fs.rm(parentVariantsDir, { recursive: true, force: true });
|
|
467
|
+
if (!this.config.silent) {
|
|
468
|
+
this.logger.debug('Variant files deleted', { parentId });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
// Directory doesn't exist, nothing to delete
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
this.logger.error(`Failed to delete variant files for ${parentId}`, error);
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// ==========================================================================
|
|
481
|
+
// UTILITY OPERATIONS
|
|
482
|
+
// ==========================================================================
|
|
483
|
+
async healthCheck() {
|
|
484
|
+
try {
|
|
485
|
+
// Test directory access
|
|
486
|
+
await fs.access(this.config.mediaDir, constants.R_OK | constants.W_OK);
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
this.logger.error('Health check failed', error);
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// ==========================================================================
|
|
495
|
+
// PRIVATE HELPER METHODS
|
|
496
|
+
// ==========================================================================
|
|
497
|
+
getMediaPath(id, extension) {
|
|
498
|
+
SecurityValidator.validateDocumentId(id);
|
|
499
|
+
// Basic validation for extension (no need for full document ID validation)
|
|
500
|
+
if (!extension || typeof extension !== 'string' || extension.length > 10) {
|
|
501
|
+
throw new InvalidInputError('Invalid file extension', 'extension');
|
|
502
|
+
}
|
|
503
|
+
return path.join(this.config.mediaDir, `${id}.${extension}`);
|
|
504
|
+
}
|
|
505
|
+
getMediaMetadataPath(id) {
|
|
506
|
+
SecurityValidator.validateDocumentId(id);
|
|
507
|
+
return path.join(this.config.mediaDir, `${id}.meta.json`);
|
|
508
|
+
}
|
|
509
|
+
validateMediaMetadata(metadata) {
|
|
510
|
+
if (!metadata.id || typeof metadata.id !== 'string') {
|
|
511
|
+
throw new InvalidInputError('Media metadata must have a valid ID', 'id');
|
|
512
|
+
}
|
|
513
|
+
if (!metadata.filename || typeof metadata.filename !== 'string') {
|
|
514
|
+
throw new InvalidInputError('Media metadata must have a valid filename', 'filename');
|
|
515
|
+
}
|
|
516
|
+
if (!metadata.contentType || typeof metadata.contentType !== 'string') {
|
|
517
|
+
throw new InvalidInputError('Media metadata must have a valid content type', 'contentType');
|
|
518
|
+
}
|
|
519
|
+
if (!metadata.extension || typeof metadata.extension !== 'string') {
|
|
520
|
+
throw new InvalidInputError('Media metadata must have a valid extension', 'extension');
|
|
521
|
+
}
|
|
522
|
+
if (typeof metadata.size !== 'number' || metadata.size <= 0) {
|
|
523
|
+
throw new InvalidInputError('Media metadata must have a valid size', 'size');
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
formatJson(data) {
|
|
527
|
+
if (this.config.prettyJson) {
|
|
528
|
+
return JSON.stringify(data, this.dateReplacer, this.config.jsonSpaces);
|
|
529
|
+
}
|
|
530
|
+
return JSON.stringify(data, this.dateReplacer);
|
|
531
|
+
}
|
|
532
|
+
dateReplacer(key, value) {
|
|
533
|
+
if (value instanceof Date) {
|
|
534
|
+
return value.toISOString();
|
|
535
|
+
}
|
|
536
|
+
return value;
|
|
537
|
+
}
|
|
538
|
+
dateReviver(key, value) {
|
|
539
|
+
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
|
|
540
|
+
return new Date(value);
|
|
541
|
+
}
|
|
542
|
+
return value;
|
|
543
|
+
}
|
|
544
|
+
safeParseJSON(content) {
|
|
545
|
+
try {
|
|
546
|
+
return JSON.parse(content, this.dateReviver);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
throw new Error(`Invalid JSON content: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
async atomicWriteFile(filePath, content) {
|
|
553
|
+
const tempPath = `${filePath}.tmp`;
|
|
554
|
+
try {
|
|
555
|
+
await fs.writeFile(tempPath, content, {
|
|
556
|
+
mode: this.config.fileMode,
|
|
557
|
+
encoding: 'utf8'
|
|
558
|
+
});
|
|
559
|
+
if (this.config.syncWrites) {
|
|
560
|
+
const fd = await fs.open(tempPath, 'r+');
|
|
561
|
+
await fd.sync();
|
|
562
|
+
await fd.close();
|
|
563
|
+
}
|
|
564
|
+
await fs.rename(tempPath, filePath);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
// Clean up temp file on error
|
|
568
|
+
try {
|
|
569
|
+
await fs.unlink(tempPath);
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
// Ignore cleanup errors
|
|
573
|
+
}
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async fileToBuffer(file) {
|
|
578
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
579
|
+
return Buffer.from(arrayBuffer);
|
|
580
|
+
}
|
|
581
|
+
async getVariantUrl(parentId, variantName) {
|
|
582
|
+
try {
|
|
583
|
+
SecurityValidator.validateDocumentId(parentId);
|
|
584
|
+
SecurityValidator.validateDocumentId(variantName);
|
|
585
|
+
if (this.config.mediaBaseUrl) {
|
|
586
|
+
return ''; // No URL generation - let frontend handle URL construction
|
|
587
|
+
}
|
|
588
|
+
return `file://${path.resolve(this.config.mediaDir, 'variants', parentId, variantName)}`;
|
|
589
|
+
}
|
|
590
|
+
catch (error) {
|
|
591
|
+
this.logger.error(`Failed to get variant URL for ${parentId}/${variantName}`, error);
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
async updateVariantUrls(imageVariants, parentId) {
|
|
596
|
+
const updatedVariants = {};
|
|
597
|
+
for (const [variantName, variantData] of Object.entries(imageVariants)) {
|
|
598
|
+
const url = await this.getVariantUrl(parentId, variantName);
|
|
599
|
+
updatedVariants[variantName] = {
|
|
600
|
+
...variantData,
|
|
601
|
+
url: url || variantData.url // Fall back to existing URL if generation fails
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
return updatedVariants;
|
|
605
|
+
}
|
|
606
|
+
sortMediaFiles(files, sortBy, direction = 'asc') {
|
|
607
|
+
files.sort((a, b) => {
|
|
608
|
+
let aValue;
|
|
609
|
+
let bValue;
|
|
610
|
+
switch (sortBy) {
|
|
611
|
+
case 'name':
|
|
612
|
+
aValue = a.filename.toLowerCase();
|
|
613
|
+
bValue = b.filename.toLowerCase();
|
|
614
|
+
break;
|
|
615
|
+
case 'size':
|
|
616
|
+
aValue = a.size;
|
|
617
|
+
bValue = b.size;
|
|
618
|
+
break;
|
|
619
|
+
case 'date':
|
|
620
|
+
aValue = a._createdAt;
|
|
621
|
+
bValue = b._createdAt;
|
|
622
|
+
break;
|
|
623
|
+
case 'type':
|
|
624
|
+
aValue = a.contentType;
|
|
625
|
+
bValue = b.contentType;
|
|
626
|
+
break;
|
|
627
|
+
default:
|
|
628
|
+
return 0;
|
|
629
|
+
}
|
|
630
|
+
let comparison = 0;
|
|
631
|
+
if (aValue < bValue)
|
|
632
|
+
comparison = -1;
|
|
633
|
+
else if (aValue > bValue)
|
|
634
|
+
comparison = 1;
|
|
635
|
+
return direction === 'desc' ? -comparison : comparison;
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
//# sourceMappingURL=filesystem-media-adapter.js.map
|