arkos 2.0.0-next.3 → 2.0.0-next.30
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/README.md +146 -145
- package/cli.js +11 -20
- package/dist/esm/app.js +37 -35
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/components/arkos-gateway/arkos-gateway.js +362 -0
- package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -0
- package/dist/esm/components/arkos-gateway/socket-extensions.js +176 -0
- package/dist/esm/components/arkos-gateway/socket-extensions.js.map +1 -0
- package/dist/esm/components/arkos-gateway/types.js +3 -0
- package/dist/esm/components/arkos-gateway/types.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/helpers.js +105 -0
- package/dist/esm/components/arkos-gateway/utils/helpers.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js +45 -0
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js +40 -0
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/rate-limiter.js +13 -0
- package/dist/esm/components/arkos-gateway/utils/rate-limiter.js.map +1 -0
- package/dist/esm/components/arkos-loadable-registry/index.js +1 -3
- package/dist/esm/components/arkos-loadable-registry/index.js.map +1 -1
- package/dist/esm/components/arkos-policy/index.js +3 -1
- package/dist/esm/components/arkos-policy/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/index.js +30 -19
- package/dist/esm/components/arkos-route-hook/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
- package/dist/esm/exports/error-handler/index.js +1 -0
- package/dist/esm/exports/error-handler/index.js.map +1 -1
- package/dist/esm/exports/file-upload.js +2 -0
- package/dist/esm/exports/file-upload.js.map +1 -0
- package/dist/esm/exports/index.js +3 -3
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/exports/middlewares/index.js +1 -1
- package/dist/esm/exports/middlewares/index.js.map +1 -1
- package/dist/esm/exports/services/index.js +2 -2
- package/dist/esm/exports/services/index.js.map +1 -1
- package/dist/esm/exports/websockets.js +5 -0
- package/dist/esm/exports/websockets.js.map +1 -0
- package/dist/esm/generated.js.map +1 -1
- package/dist/esm/modules/auth/auth.controller.js +165 -230
- package/dist/esm/modules/auth/auth.controller.js.map +1 -1
- package/dist/esm/modules/auth/auth.router.js +28 -10
- package/dist/esm/modules/auth/auth.router.js.map +1 -1
- package/dist/esm/modules/auth/auth.service.js +202 -136
- package/dist/esm/modules/auth/auth.service.js.map +1 -1
- package/dist/esm/modules/auth/auth.types.js +2 -0
- package/dist/esm/modules/auth/auth.types.js.map +1 -0
- package/dist/esm/modules/auth/utils/auth-error-objects.js +2 -2
- package/dist/esm/modules/auth/utils/auth-error-objects.js.map +1 -1
- package/dist/esm/modules/auth/utils/auth-hooks-manager.js +148 -0
- package/dist/esm/modules/auth/utils/auth-hooks-manager.js.map +1 -0
- package/dist/esm/modules/auth/utils/auth-openapi-generator.js +367 -0
- package/dist/esm/modules/auth/utils/auth-openapi-generator.js.map +1 -0
- package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js +97 -0
- package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js.map +1 -0
- package/dist/esm/modules/auth/utils/docs-links.js +6 -0
- package/dist/esm/modules/auth/utils/docs-links.js.map +1 -0
- package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js +1 -0
- package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js.map +1 -1
- package/dist/esm/modules/auth/utils/services/auth-action.service.js +20 -16
- package/dist/esm/modules/auth/utils/services/auth-action.service.js.map +1 -1
- package/dist/esm/modules/auth/utils/token-extraction.js +57 -0
- package/dist/esm/modules/auth/utils/token-extraction.js.map +1 -0
- package/dist/esm/modules/base/base.controller.js +228 -202
- package/dist/esm/modules/base/base.controller.js.map +1 -1
- package/dist/esm/modules/base/base.middlewares.js +69 -86
- package/dist/esm/modules/base/base.middlewares.js.map +1 -1
- package/dist/esm/modules/base/base.router.js +23 -9
- package/dist/esm/modules/base/base.router.js.map +1 -1
- package/dist/esm/modules/base/base.service.js +92 -197
- package/dist/esm/modules/base/base.service.js.map +1 -1
- package/dist/esm/modules/base/types/base.service.types.js.map +1 -1
- package/dist/esm/modules/base/utils/error-prettifier.js +90 -30
- package/dist/esm/modules/base/utils/error-prettifier.js.map +1 -1
- package/dist/esm/modules/base/utils/helpers/base.service.helpers.js +26 -5
- package/dist/esm/modules/base/utils/helpers/base.service.helpers.js.map +1 -1
- package/dist/esm/modules/base/utils/model-openapi-generator.js +438 -0
- package/dist/esm/modules/base/utils/model-openapi-generator.js.map +1 -0
- package/dist/esm/modules/email/email.service.js +21 -12
- package/dist/esm/modules/email/email.service.js.map +1 -1
- package/dist/esm/modules/error-handler/error-handler.controller.js +24 -113
- package/dist/esm/modules/error-handler/error-handler.controller.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/app-error.js +5 -2
- package/dist/esm/modules/error-handler/utils/app-error.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/catch-async.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/error-handler.helpers.js +60 -110
- package/dist/esm/modules/error-handler/utils/error-handler.helpers.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/errors.js +127 -0
- package/dist/esm/modules/error-handler/utils/errors.js.map +1 -0
- package/dist/esm/modules/error-handler/utils/get-handled-error.js +73 -0
- package/dist/esm/modules/error-handler/utils/get-handled-error.js.map +1 -0
- package/dist/esm/modules/error-handler/utils/multer-error-handler.js +34 -0
- package/dist/esm/modules/error-handler/utils/multer-error-handler.js.map +1 -0
- package/dist/esm/modules/file-upload/file-upload.controller.js +227 -215
- package/dist/esm/modules/file-upload/file-upload.controller.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.router.js +54 -15
- package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.service.js +41 -26
- package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js +371 -0
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js +73 -35
- package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js +206 -0
- package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js +103 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js +212 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js +30 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js.map +1 -0
- package/dist/esm/modules/swagger/swagger.router.js +39 -22
- package/dist/esm/modules/swagger/swagger.router.js.map +1 -1
- package/dist/esm/modules/swagger/utils/get-open-api-login-html.js +305 -0
- package/dist/esm/modules/swagger/utils/get-open-api-login-html.js.map +1 -0
- package/dist/esm/modules/swagger/utils/helpers/class-validator-to-json-schema.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js +6 -7
- package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +47 -43
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
- package/dist/esm/server.js +1 -1
- package/dist/esm/server.js.map +1 -1
- package/dist/esm/types/arkos-config/utils.js +2 -0
- package/dist/esm/types/arkos-config/utils.js.map +1 -0
- package/dist/esm/types/arkos-prisma-input.js.map +1 -1
- package/dist/esm/types/arkos.js.map +1 -1
- package/dist/esm/types/auth.js.map +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/internal.js +2 -0
- package/dist/esm/types/internal.js.map +1 -0
- package/dist/esm/types/new-arkos-config.js.map +1 -1
- package/dist/esm/types/router-config.js.map +1 -1
- package/dist/esm/types/upload.js +2 -0
- package/dist/esm/types/upload.js.map +1 -0
- package/dist/esm/types/validation/validation-manager.js +57 -0
- package/dist/esm/types/validation/validation-manager.js.map +1 -0
- package/dist/esm/types/validation/validator.js +2 -0
- package/dist/esm/types/validation/validator.js.map +1 -0
- package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js +68 -34
- package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js.map +1 -1
- package/dist/esm/utils/arkos-router/index.js +58 -158
- package/dist/esm/utils/arkos-router/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/route-config-registry.js +2 -3
- package/dist/esm/utils/arkos-router/route-config-registry.js.map +1 -1
- package/dist/esm/utils/arkos-router/route-config-validator.js +11 -10
- package/dist/esm/utils/arkos-router/route-config-validator.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/openapi-config.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/upload-config.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js +198 -0
- package/dist/esm/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js.map +1 -0
- package/dist/esm/utils/arkos-router/utils/helpers/index.js +92 -29
- package/dist/esm/utils/arkos-router/utils/helpers/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +683 -119
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
- package/dist/esm/utils/bundler.js +6 -6
- package/dist/esm/utils/bundler.js.map +1 -1
- package/dist/esm/utils/cli/build.js +16 -9
- package/dist/esm/utils/cli/build.js.map +1 -1
- package/dist/esm/utils/cli/dev.js +33 -32
- package/dist/esm/utils/cli/dev.js.map +1 -1
- package/dist/esm/utils/cli/export-auth-action.js +7 -7
- package/dist/esm/utils/cli/export-auth-action.js.map +1 -1
- package/dist/esm/utils/cli/generate.js +77 -58
- package/dist/esm/utils/cli/generate.js.map +1 -1
- package/dist/esm/utils/cli/index.js +74 -56
- package/dist/esm/utils/cli/index.js.map +1 -1
- package/dist/esm/utils/cli/prisma-generate.js +66 -35
- package/dist/esm/utils/cli/prisma-generate.js.map +1 -1
- package/dist/esm/utils/cli/start.js +27 -16
- package/dist/esm/utils/cli/start.js.map +1 -1
- package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
- package/dist/esm/utils/cli/utils/dependency-version-check.js +39 -0
- package/dist/esm/utils/cli/utils/dependency-version-check.js.map +1 -0
- package/dist/esm/utils/cli/utils/runtime-cli-commander.js +7 -3
- package/dist/esm/utils/cli/utils/runtime-cli-commander.js.map +1 -1
- package/dist/esm/utils/cli/utils/smart-fs-watcher.js +3 -0
- package/dist/esm/utils/cli/utils/smart-fs-watcher.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js +307 -11
- package/dist/esm/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-controller-template.js +16 -7
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-controller-template.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-multiple-components.js +117 -65
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-multiple-components.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/policy-template.js +6 -8
- package/dist/esm/utils/cli/utils/template-generator/templates/policy-template.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js +13 -2
- package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/service-template.js +2 -2
- package/dist/esm/utils/cli/utils/template-generator/templates/service-template.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/zod-schema-generator.js +213 -19
- package/dist/esm/utils/cli/utils/template-generator/templates/zod-schema-generator.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generators.js +31 -18
- package/dist/esm/utils/cli/utils/template-generators.js.map +1 -1
- package/dist/esm/utils/cli/utils/watermark-stamper.js +1 -1
- package/dist/esm/utils/cli/utils/watermark-stamper.js.map +1 -1
- package/dist/esm/utils/define-config.js +15 -0
- package/dist/esm/utils/define-config.js.map +1 -1
- package/dist/esm/utils/docs-links.js +2 -0
- package/dist/esm/utils/docs-links.js.map +1 -0
- package/dist/esm/utils/dotenv.helpers.js +3 -7
- package/dist/esm/utils/dotenv.helpers.js.map +1 -1
- package/dist/esm/utils/dynamic-loader.js +6 -5
- package/dist/esm/utils/dynamic-loader.js.map +1 -1
- package/dist/esm/utils/features/api.features.js +46 -27
- package/dist/esm/utils/features/api.features.js.map +1 -1
- package/dist/esm/utils/features/port-and-host-allocator.js +4 -3
- package/dist/esm/utils/features/port-and-host-allocator.js.map +1 -1
- package/dist/esm/utils/helpers/api.features.helpers.js +20 -0
- package/dist/esm/utils/helpers/api.features.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/arkos-config.helpers.js +60 -24
- package/dist/esm/utils/helpers/arkos-config.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/exit-error.js +1 -0
- package/dist/esm/utils/helpers/exit-error.js.map +1 -1
- package/dist/esm/utils/helpers/fs.helpers.js +25 -32
- package/dist/esm/utils/helpers/fs.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/global.helpers.js +1 -1
- package/dist/esm/utils/helpers/global.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/prisma.helpers.js +10 -7
- package/dist/esm/utils/helpers/prisma.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/query-parser.helpers.js +7 -22
- package/dist/esm/utils/helpers/query-parser.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/routers.helpers.js +2 -2
- package/dist/esm/utils/helpers/routers.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/url-helpers.js +11 -0
- package/dist/esm/utils/helpers/url-helpers.js.map +1 -0
- package/dist/esm/utils/initialize-app.js +43 -17
- package/dist/esm/utils/initialize-app.js.map +1 -1
- package/dist/esm/utils/prisma/prisma-json-schema-generator.js +154 -226
- package/dist/esm/utils/prisma/prisma-json-schema-generator.js.map +1 -1
- package/dist/esm/utils/prisma/prisma-schema-parser.js +37 -11
- package/dist/esm/utils/prisma/prisma-schema-parser.js.map +1 -1
- package/dist/esm/utils/prisma/types.js.map +1 -1
- package/dist/esm/utils/remove-dir.js +1 -1
- package/dist/esm/utils/remove-dir.js.map +1 -1
- package/dist/esm/utils/setup-app.js +59 -42
- package/dist/esm/utils/setup-app.js.map +1 -1
- package/dist/esm/utils/validate-schema.js +25 -23
- package/dist/esm/utils/validate-schema.js.map +1 -1
- package/dist/types/app.d.ts +15 -10
- package/dist/types/components/arkos-gateway/arkos-gateway.d.ts +135 -0
- package/dist/types/components/arkos-gateway/socket-extensions.d.ts +80 -0
- package/dist/types/components/arkos-gateway/types.d.ts +467 -0
- package/dist/types/components/arkos-gateway/utils/helpers.d.ts +9 -0
- package/dist/types/components/arkos-gateway/utils/memory-gateway-store.d.ts +14 -0
- package/dist/types/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.d.ts +20 -0
- package/dist/types/components/arkos-gateway/utils/rate-limiter.d.ts +11 -0
- package/dist/types/components/arkos-route-hook/index.d.ts +13 -6
- package/dist/types/components/arkos-route-hook/reader.d.ts +4 -7
- package/dist/types/components/arkos-route-hook/types.d.ts +12 -5
- package/dist/types/exports/error-handler/index.d.ts +1 -0
- package/dist/types/exports/file-upload.d.ts +1 -0
- package/dist/types/exports/index.d.ts +4 -5
- package/dist/types/exports/middlewares/index.d.ts +1 -1
- package/dist/types/exports/services/index.d.ts +3 -3
- package/dist/types/exports/websockets.d.ts +5 -0
- package/dist/types/modules/auth/auth.controller.d.ts +10 -3
- package/dist/types/modules/auth/auth.service.d.ts +170 -51
- package/dist/types/modules/auth/auth.types.d.ts +72 -0
- package/dist/types/modules/auth/utils/auth-hooks-manager.d.ts +63 -0
- package/dist/types/modules/auth/utils/auth-openapi-generator.d.ts +9 -0
- package/dist/types/modules/auth/utils/auth-prisma-json-schema-generator.d.ts +13 -0
- package/dist/types/modules/auth/utils/docs-links.d.ts +3 -0
- package/dist/types/modules/auth/utils/helpers/auth.controller.helpers.d.ts +1 -0
- package/dist/types/modules/auth/utils/services/auth-action.service.d.ts +2 -2
- package/dist/types/modules/auth/utils/token-extraction.d.ts +53 -0
- package/dist/types/modules/base/base.controller.d.ts +7 -6
- package/dist/types/modules/base/base.middlewares.d.ts +3 -9
- package/dist/types/modules/base/base.service.d.ts +18 -26
- package/dist/types/modules/base/types/base.service.types.d.ts +11 -0
- package/dist/types/modules/base/utils/error-prettifier.d.ts +8 -0
- package/dist/types/modules/base/utils/helpers/base.service.helpers.d.ts +1 -1
- package/dist/types/modules/base/utils/model-openapi-generator.d.ts +12 -0
- package/dist/types/modules/email/email.service.d.ts +3 -1
- package/dist/types/modules/error-handler/utils/app-error.d.ts +0 -2
- package/dist/types/modules/error-handler/utils/catch-async.d.ts +2 -2
- package/dist/types/modules/error-handler/utils/error-handler.helpers.d.ts +2 -27
- package/dist/types/modules/error-handler/utils/errors.d.ts +176 -0
- package/dist/types/modules/error-handler/utils/get-handled-error.d.ts +1 -0
- package/dist/types/modules/error-handler/utils/multer-error-handler.d.ts +7 -0
- package/dist/types/modules/file-upload/file-upload.controller.d.ts +7 -2
- package/dist/types/modules/file-upload/file-upload.service.d.ts +2 -6
- package/dist/types/modules/file-upload/utils/file-upload-json-schema-generator.d.ts +12 -0
- package/dist/types/modules/file-upload/utils/helpers/file-upload.helpers.d.ts +21 -1
- package/dist/types/modules/file-upload/utils/helpers/serve-upload-dir.d.ts +43 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-path.helper.d.ts +14 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-serving-validation.d.ts +5 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-serving.registry.d.ts +31 -0
- package/dist/types/modules/swagger/swagger.router.d.ts +1 -2
- package/dist/types/modules/swagger/utils/get-open-api-login-html.d.ts +1 -0
- package/dist/types/modules/swagger/utils/helpers/get-swagger-default-configs.d.ts +48 -3
- package/dist/types/modules/swagger/utils/helpers/openapi-schema-converter.d.ts +8 -3
- package/dist/types/types/arkos-config/utils.d.ts +68 -0
- package/dist/types/types/arkos-prisma-input.d.ts +7 -3
- package/dist/types/types/arkos.d.ts +5 -15
- package/dist/types/types/auth.d.ts +4 -4
- package/dist/types/types/index.d.ts +15 -58
- package/dist/types/types/internal.d.ts +25 -0
- package/dist/types/types/new-arkos-config.d.ts +374 -67
- package/dist/types/types/router-config.d.ts +3 -66
- package/dist/types/types/upload.d.ts +45 -0
- package/dist/types/types/validation/validation-manager.d.ts +25 -0
- package/dist/types/types/validation/validator.d.ts +2 -0
- package/dist/types/utils/arkos-router/arkos-router-openapi-manager.d.ts +14 -1
- package/dist/types/utils/arkos-router/index.d.ts +86 -11
- package/dist/types/utils/arkos-router/types/index.d.ts +83 -31
- package/dist/types/utils/arkos-router/types/openapi-config.d.ts +3 -2
- package/dist/types/utils/arkos-router/types/upload-config.d.ts +158 -10
- package/dist/types/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.d.ts +6 -0
- package/dist/types/utils/arkos-router/utils/helpers/index.d.ts +4 -6
- package/dist/types/utils/arkos-router/utils/helpers/upload-manager.d.ts +21 -36
- package/dist/types/utils/bundler.d.ts +1 -1
- package/dist/types/utils/cli/build.d.ts +1 -1
- package/dist/types/utils/cli/generate.d.ts +15 -6
- package/dist/types/utils/cli/start.d.ts +3 -1
- package/dist/types/utils/cli/utils/dependency-version-check.d.ts +15 -0
- package/dist/types/utils/cli/utils/template-generator/templates/class-validator-dto-generator.d.ts +11 -0
- package/dist/types/utils/cli/utils/template-generator/templates/zod-schema-generator.d.ts +4 -0
- package/dist/types/utils/define-config.d.ts +57 -3
- package/dist/types/utils/docs-links.d.ts +1 -0
- package/dist/types/utils/dotenv.helpers.d.ts +1 -0
- package/dist/types/utils/dynamic-loader.d.ts +2 -2
- package/dist/types/utils/features/api.features.d.ts +1 -2
- package/dist/types/utils/helpers/arkos-config.helpers.d.ts +9 -1
- package/dist/types/utils/helpers/fs.helpers.d.ts +1 -16
- package/dist/types/utils/helpers/global.helpers.d.ts +1 -0
- package/dist/types/utils/helpers/prisma.helpers.d.ts +1 -1
- package/dist/types/utils/helpers/query-parser.helpers.d.ts +1 -1
- package/dist/types/utils/helpers/url-helpers.d.ts +1 -0
- package/dist/types/utils/initialize-app.d.ts +1 -0
- package/dist/types/utils/prisma/prisma-json-schema-generator.d.ts +12 -30
- package/dist/types/utils/prisma/prisma-schema-parser.d.ts +4 -0
- package/dist/types/utils/prisma/types.d.ts +3 -2
- package/dist/types/utils/validate-schema.d.ts +1 -1
- package/package.json +84 -75
- package/dist/cjs/app.js +0 -79
- package/dist/cjs/app.js.map +0 -1
- package/dist/cjs/components/arkos-loadable-registry/index.js +0 -28
- package/dist/cjs/components/arkos-loadable-registry/index.js.map +0 -1
- package/dist/cjs/components/arkos-loadable-translator/index.js +0 -144
- package/dist/cjs/components/arkos-loadable-translator/index.js.map +0 -1
- package/dist/cjs/components/arkos-policy/index.js +0 -36
- package/dist/cjs/components/arkos-policy/index.js.map +0 -1
- package/dist/cjs/components/arkos-policy/types.js +0 -3
- package/dist/cjs/components/arkos-policy/types.js.map +0 -1
- package/dist/cjs/components/arkos-route-hook/index.js +0 -50
- package/dist/cjs/components/arkos-route-hook/index.js.map +0 -1
- package/dist/cjs/components/arkos-route-hook/reader.js +0 -47
- package/dist/cjs/components/arkos-route-hook/reader.js.map +0 -1
- package/dist/cjs/components/arkos-route-hook/types.js +0 -3
- package/dist/cjs/components/arkos-route-hook/types.js.map +0 -1
- package/dist/cjs/components/arkos-service-hook/index.js +0 -35
- package/dist/cjs/components/arkos-service-hook/index.js.map +0 -1
- package/dist/cjs/components/arkos-service-hook/reader.js +0 -30
- package/dist/cjs/components/arkos-service-hook/reader.js.map +0 -1
- package/dist/cjs/components/arkos-service-hook/types.js +0 -3
- package/dist/cjs/components/arkos-service-hook/types.js.map +0 -1
- package/dist/cjs/exports/auth/index.js +0 -6
- package/dist/cjs/exports/auth/index.js.map +0 -1
- package/dist/cjs/exports/config.js +0 -6
- package/dist/cjs/exports/config.js.map +0 -1
- package/dist/cjs/exports/controllers/index.js +0 -42
- package/dist/cjs/exports/controllers/index.js.map +0 -1
- package/dist/cjs/exports/error-handler/index.js +0 -11
- package/dist/cjs/exports/error-handler/index.js.map +0 -1
- package/dist/cjs/exports/index.js +0 -23
- package/dist/cjs/exports/index.js.map +0 -1
- package/dist/cjs/exports/middlewares/index.js +0 -7
- package/dist/cjs/exports/middlewares/index.js.map +0 -1
- package/dist/cjs/exports/prisma/index.js +0 -13
- package/dist/cjs/exports/prisma/index.js.map +0 -1
- package/dist/cjs/exports/services/index.js +0 -53
- package/dist/cjs/exports/services/index.js.map +0 -1
- package/dist/cjs/exports/utils/index.js +0 -26
- package/dist/cjs/exports/utils/index.js.map +0 -1
- package/dist/cjs/exports/validation/index.js +0 -11
- package/dist/cjs/exports/validation/index.js.map +0 -1
- package/dist/cjs/generated.js +0 -7
- package/dist/cjs/generated.js.map +0 -1
- package/dist/cjs/modules/auth/auth.controller.js +0 -254
- package/dist/cjs/modules/auth/auth.controller.js.map +0 -1
- package/dist/cjs/modules/auth/auth.router.js +0 -113
- package/dist/cjs/modules/auth/auth.router.js.map +0 -1
- package/dist/cjs/modules/auth/auth.service.js +0 -277
- package/dist/cjs/modules/auth/auth.service.js.map +0 -1
- package/dist/cjs/modules/auth/utils/auth-error-objects.js +0 -10
- package/dist/cjs/modules/auth/utils/auth-error-objects.js.map +0 -1
- package/dist/cjs/modules/auth/utils/helpers/auth.controller.helpers.js +0 -83
- package/dist/cjs/modules/auth/utils/helpers/auth.controller.helpers.js.map +0 -1
- package/dist/cjs/modules/auth/utils/services/auth-action.service.js +0 -150
- package/dist/cjs/modules/auth/utils/services/auth-action.service.js.map +0 -1
- package/dist/cjs/modules/base/base.controller.js +0 -275
- package/dist/cjs/modules/base/base.controller.js.map +0 -1
- package/dist/cjs/modules/base/base.middlewares.js +0 -231
- package/dist/cjs/modules/base/base.middlewares.js.map +0 -1
- package/dist/cjs/modules/base/base.router.js +0 -112
- package/dist/cjs/modules/base/base.router.js.map +0 -1
- package/dist/cjs/modules/base/base.service.js +0 -432
- package/dist/cjs/modules/base/base.service.js.map +0 -1
- package/dist/cjs/modules/base/types/base.service.types.js +0 -3
- package/dist/cjs/modules/base/types/base.service.types.js.map +0 -1
- package/dist/cjs/modules/base/utils/error-prettifier.js +0 -188
- package/dist/cjs/modules/base/utils/error-prettifier.js.map +0 -1
- package/dist/cjs/modules/base/utils/helpers/base.middlewares.helpers.js +0 -49
- package/dist/cjs/modules/base/utils/helpers/base.middlewares.helpers.js.map +0 -1
- package/dist/cjs/modules/base/utils/helpers/base.router.helpers.js +0 -13
- package/dist/cjs/modules/base/utils/helpers/base.router.helpers.js.map +0 -1
- package/dist/cjs/modules/base/utils/helpers/base.service.helpers.js +0 -222
- package/dist/cjs/modules/base/utils/helpers/base.service.helpers.js.map +0 -1
- package/dist/cjs/modules/base/utils/router-validator.js +0 -13
- package/dist/cjs/modules/base/utils/router-validator.js.map +0 -1
- package/dist/cjs/modules/base/utils/service-hooks-manager.js +0 -19
- package/dist/cjs/modules/base/utils/service-hooks-manager.js.map +0 -1
- package/dist/cjs/modules/debugger/debugger.service.js +0 -59
- package/dist/cjs/modules/debugger/debugger.service.js.map +0 -1
- package/dist/cjs/modules/email/email.service.js +0 -106
- package/dist/cjs/modules/email/email.service.js.map +0 -1
- package/dist/cjs/modules/error-handler/error-handler.controller.js +0 -192
- package/dist/cjs/modules/error-handler/error-handler.controller.js.map +0 -1
- package/dist/cjs/modules/error-handler/utils/app-error.js +0 -28
- package/dist/cjs/modules/error-handler/utils/app-error.js.map +0 -1
- package/dist/cjs/modules/error-handler/utils/catch-async.js +0 -21
- package/dist/cjs/modules/error-handler/utils/catch-async.js.map +0 -1
- package/dist/cjs/modules/error-handler/utils/error-handler.helpers.js +0 -218
- package/dist/cjs/modules/error-handler/utils/error-handler.helpers.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.controller.js +0 -256
- package/dist/cjs/modules/file-upload/file-upload.controller.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.router.js +0 -80
- package/dist/cjs/modules/file-upload/file-upload.router.js.map +0 -1
- package/dist/cjs/modules/file-upload/file-upload.service.js +0 -343
- package/dist/cjs/modules/file-upload/file-upload.service.js.map +0 -1
- package/dist/cjs/modules/file-upload/utils/helpers/file-extensions.js +0 -134
- package/dist/cjs/modules/file-upload/utils/helpers/file-extensions.js.map +0 -1
- package/dist/cjs/modules/file-upload/utils/helpers/file-upload.helpers.js +0 -100
- package/dist/cjs/modules/file-upload/utils/helpers/file-upload.helpers.js.map +0 -1
- package/dist/cjs/modules/swagger/swagger.router.js +0 -65
- package/dist/cjs/modules/swagger/swagger.router.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/built-in-route-path-object-manager.js +0 -7
- package/dist/cjs/modules/swagger/utils/built-in-route-path-object-manager.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/class-validator-to-json-schema.js +0 -53
- package/dist/cjs/modules/swagger/utils/helpers/class-validator-to-json-schema.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/get-authentication-json-schema-paths.js +0 -473
- package/dist/cjs/modules/swagger/utils/helpers/get-authentication-json-schema-paths.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/get-file-upload-json-schema-paths.js +0 -491
- package/dist/cjs/modules/swagger/utils/helpers/get-file-upload-json-schema-paths.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/get-swagger-default-configs.js +0 -73
- package/dist/cjs/modules/swagger/utils/helpers/get-swagger-default-configs.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/get-system-json-schema-paths.js +0 -37
- package/dist/cjs/modules/swagger/utils/helpers/get-system-json-schema-paths.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-class-validator-json-schemas.js +0 -61
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-class-validator-json-schemas.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-prisma-json-schemas.js +0 -31
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-prisma-json-schemas.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-system-json-schemas.js +0 -49
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-system-json-schemas.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-zod-json-schemas.js +0 -39
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/generate-zod-json-schemas.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/prisma-models/generate-prisma-model-main-routes-paths.js +0 -468
- package/dist/cjs/modules/swagger/utils/helpers/json-schema-generators/prisma-models/generate-prisma-model-main-routes-paths.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/missing-json-schemas-generator.js +0 -260
- package/dist/cjs/modules/swagger/utils/helpers/missing-json-schemas-generator.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/openapi-schema-converter.js +0 -331
- package/dist/cjs/modules/swagger/utils/helpers/openapi-schema-converter.js.map +0 -1
- package/dist/cjs/modules/swagger/utils/helpers/swagger.router.helpers.js +0 -109
- package/dist/cjs/modules/swagger/utils/helpers/swagger.router.helpers.js.map +0 -1
- package/dist/cjs/package.json +0 -3
- package/dist/cjs/server.js +0 -60
- package/dist/cjs/server.js.map +0 -1
- package/dist/cjs/types/arkos-prisma-input.js +0 -3
- package/dist/cjs/types/arkos-prisma-input.js.map +0 -1
- package/dist/cjs/types/arkos.js +0 -3
- package/dist/cjs/types/arkos.js.map +0 -1
- package/dist/cjs/types/auth.js +0 -3
- package/dist/cjs/types/auth.js.map +0 -1
- package/dist/cjs/types/index.js +0 -3
- package/dist/cjs/types/index.js.map +0 -1
- package/dist/cjs/types/new-arkos-config.js +0 -3
- package/dist/cjs/types/new-arkos-config.js.map +0 -1
- package/dist/cjs/types/router-config.js +0 -3
- package/dist/cjs/types/router-config.js.map +0 -1
- package/dist/cjs/utils/arkos-env.js +0 -9
- package/dist/cjs/utils/arkos-env.js.map +0 -1
- package/dist/cjs/utils/arkos-router/arkos-router-openapi-manager.js +0 -126
- package/dist/cjs/utils/arkos-router/arkos-router-openapi-manager.js.map +0 -1
- package/dist/cjs/utils/arkos-router/index.js +0 -253
- package/dist/cjs/utils/arkos-router/index.js.map +0 -1
- package/dist/cjs/utils/arkos-router/route-config-registry.js +0 -16
- package/dist/cjs/utils/arkos-router/route-config-registry.js.map +0 -1
- package/dist/cjs/utils/arkos-router/route-config-validator.js +0 -56
- package/dist/cjs/utils/arkos-router/route-config-validator.js.map +0 -1
- package/dist/cjs/utils/arkos-router/types/body-parser-config.js +0 -3
- package/dist/cjs/utils/arkos-router/types/body-parser-config.js.map +0 -1
- package/dist/cjs/utils/arkos-router/types/index.js +0 -3
- package/dist/cjs/utils/arkos-router/types/index.js.map +0 -1
- package/dist/cjs/utils/arkos-router/types/openapi-config.js +0 -3
- package/dist/cjs/utils/arkos-router/types/openapi-config.js.map +0 -1
- package/dist/cjs/utils/arkos-router/types/upload-config.js +0 -3
- package/dist/cjs/utils/arkos-router/types/upload-config.js.map +0 -1
- package/dist/cjs/utils/arkos-router/utils/helpers/index.js +0 -163
- package/dist/cjs/utils/arkos-router/utils/helpers/index.js.map +0 -1
- package/dist/cjs/utils/arkos-router/utils/helpers/upload-manager.js +0 -283
- package/dist/cjs/utils/arkos-router/utils/helpers/upload-manager.js.map +0 -1
- package/dist/cjs/utils/bundler.js +0 -163
- package/dist/cjs/utils/bundler.js.map +0 -1
- package/dist/cjs/utils/cli/build.js +0 -200
- package/dist/cjs/utils/cli/build.js.map +0 -1
- package/dist/cjs/utils/cli/dev.js +0 -128
- package/dist/cjs/utils/cli/dev.js.map +0 -1
- package/dist/cjs/utils/cli/export-auth-action.js +0 -79
- package/dist/cjs/utils/cli/export-auth-action.js.map +0 -1
- package/dist/cjs/utils/cli/generate.js +0 -229
- package/dist/cjs/utils/cli/generate.js.map +0 -1
- package/dist/cjs/utils/cli/index.js +0 -191
- package/dist/cjs/utils/cli/index.js.map +0 -1
- package/dist/cjs/utils/cli/prisma-generate.js +0 -112
- package/dist/cjs/utils/cli/prisma-generate.js.map +0 -1
- package/dist/cjs/utils/cli/start.js +0 -72
- package/dist/cjs/utils/cli/start.js.map +0 -1
- package/dist/cjs/utils/cli/utils/cli.helpers.js +0 -24
- package/dist/cjs/utils/cli/utils/cli.helpers.js.map +0 -1
- package/dist/cjs/utils/cli/utils/runtime-cli-commander.js +0 -114
- package/dist/cjs/utils/cli/utils/runtime-cli-commander.js.map +0 -1
- package/dist/cjs/utils/cli/utils/smart-fs-watcher.js +0 -73
- package/dist/cjs/utils/cli/utils/smart-fs-watcher.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js +0 -550
- package/dist/cjs/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-controller-template.js +0 -52
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-controller-template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-multiple-components.js +0 -139
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-multiple-components.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/policy-template.js +0 -53
- package/dist/cjs/utils/cli/utils/template-generator/templates/policy-template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/route-hook.template.js +0 -39
- package/dist/cjs/utils/cli/utils/template-generator/templates/route-hook.template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/router-template.js +0 -19
- package/dist/cjs/utils/cli/utils/template-generator/templates/router-template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/service-hook.template.js +0 -32
- package/dist/cjs/utils/cli/utils/template-generator/templates/service-hook.template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/service-template.js +0 -50
- package/dist/cjs/utils/cli/utils/template-generator/templates/service-template.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/zod-schema-generator.js +0 -351
- package/dist/cjs/utils/cli/utils/template-generator/templates/zod-schema-generator.js.map +0 -1
- package/dist/cjs/utils/cli/utils/template-generators.js +0 -52
- package/dist/cjs/utils/cli/utils/template-generators.js.map +0 -1
- package/dist/cjs/utils/cli/utils/watermark-stamper.js +0 -26
- package/dist/cjs/utils/cli/utils/watermark-stamper.js.map +0 -1
- package/dist/cjs/utils/define-config.js +0 -46
- package/dist/cjs/utils/define-config.js.map +0 -1
- package/dist/cjs/utils/dotenv.helpers.js +0 -52
- package/dist/cjs/utils/dotenv.helpers.js.map +0 -1
- package/dist/cjs/utils/dynamic-loader.js +0 -22
- package/dist/cjs/utils/dynamic-loader.js.map +0 -1
- package/dist/cjs/utils/expand-env.js +0 -72
- package/dist/cjs/utils/expand-env.js.map +0 -1
- package/dist/cjs/utils/features/api.features.js +0 -201
- package/dist/cjs/utils/features/api.features.js.map +0 -1
- package/dist/cjs/utils/features/port-and-host-allocator.js +0 -129
- package/dist/cjs/utils/features/port-and-host-allocator.js.map +0 -1
- package/dist/cjs/utils/helpers/api.features.helpers.js +0 -327
- package/dist/cjs/utils/helpers/api.features.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/arkos-config.helpers.js +0 -86
- package/dist/cjs/utils/helpers/arkos-config.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/change-case.helpers.js +0 -177
- package/dist/cjs/utils/helpers/change-case.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/deepmerge.helper.js +0 -115
- package/dist/cjs/utils/helpers/deepmerge.helper.js.map +0 -1
- package/dist/cjs/utils/helpers/exit-error.js +0 -12
- package/dist/cjs/utils/helpers/exit-error.js.map +0 -1
- package/dist/cjs/utils/helpers/fs.helpers.js +0 -60
- package/dist/cjs/utils/helpers/fs.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/global.helpers.js +0 -105
- package/dist/cjs/utils/helpers/global.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/prisma.helpers.js +0 -53
- package/dist/cjs/utils/helpers/prisma.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/query-parser.helpers.js +0 -69
- package/dist/cjs/utils/helpers/query-parser.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/routers.helpers.js +0 -36
- package/dist/cjs/utils/helpers/routers.helpers.js.map +0 -1
- package/dist/cjs/utils/helpers/text.helpers.js +0 -28
- package/dist/cjs/utils/helpers/text.helpers.js.map +0 -1
- package/dist/cjs/utils/initialize-app.js +0 -55
- package/dist/cjs/utils/initialize-app.js.map +0 -1
- package/dist/cjs/utils/prisma/prisma-json-schema-generator.js +0 -437
- package/dist/cjs/utils/prisma/prisma-json-schema-generator.js.map +0 -1
- package/dist/cjs/utils/prisma/prisma-schema-parser.js +0 -360
- package/dist/cjs/utils/prisma/prisma-schema-parser.js.map +0 -1
- package/dist/cjs/utils/prisma/types.js +0 -3
- package/dist/cjs/utils/prisma/types.js.map +0 -1
- package/dist/cjs/utils/remove-dir.js +0 -14
- package/dist/cjs/utils/remove-dir.js.map +0 -1
- package/dist/cjs/utils/setup-app.js +0 -119
- package/dist/cjs/utils/setup-app.js.map +0 -1
- package/dist/cjs/utils/sheu.js +0 -131
- package/dist/cjs/utils/sheu.js.map +0 -1
- package/dist/cjs/utils/validate-dto.js +0 -19
- package/dist/cjs/utils/validate-dto.js.map +0 -1
- package/dist/cjs/utils/validate-schema.js +0 -75
- package/dist/cjs/utils/validate-schema.js.map +0 -1
- package/dist/esm/components/arkos-loadable-translator/index.js +0 -138
- package/dist/esm/components/arkos-loadable-translator/index.js.map +0 -1
- package/dist/esm/components/arkos-service-hook/index.js +0 -32
- package/dist/esm/components/arkos-service-hook/index.js.map +0 -1
- package/dist/esm/components/arkos-service-hook/reader.js +0 -24
- package/dist/esm/components/arkos-service-hook/reader.js.map +0 -1
- package/dist/esm/components/arkos-service-hook/types.js +0 -2
- package/dist/esm/components/arkos-service-hook/types.js.map +0 -1
- package/dist/esm/modules/base/utils/helpers/base.router.helpers.js +0 -10
- package/dist/esm/modules/base/utils/helpers/base.router.helpers.js.map +0 -1
- package/dist/esm/modules/base/utils/service-hooks-manager.js +0 -17
- package/dist/esm/modules/base/utils/service-hooks-manager.js.map +0 -1
- package/dist/esm/modules/swagger/utils/built-in-route-path-object-manager.js +0 -5
- package/dist/esm/modules/swagger/utils/built-in-route-path-object-manager.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/get-authentication-json-schema-paths.js +0 -469
- package/dist/esm/modules/swagger/utils/helpers/get-authentication-json-schema-paths.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/get-file-upload-json-schema-paths.js +0 -485
- package/dist/esm/modules/swagger/utils/helpers/get-file-upload-json-schema-paths.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/get-system-json-schema-paths.js +0 -34
- package/dist/esm/modules/swagger/utils/helpers/get-system-json-schema-paths.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-class-validator-json-schemas.js +0 -55
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-class-validator-json-schemas.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-prisma-json-schemas.js +0 -25
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-prisma-json-schemas.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-system-json-schemas.js +0 -46
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-system-json-schemas.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-zod-json-schemas.js +0 -33
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/generate-zod-json-schemas.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/prisma-models/generate-prisma-model-main-routes-paths.js +0 -462
- package/dist/esm/modules/swagger/utils/helpers/json-schema-generators/prisma-models/generate-prisma-model-main-routes-paths.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/missing-json-schemas-generator.js +0 -255
- package/dist/esm/modules/swagger/utils/helpers/missing-json-schemas-generator.js.map +0 -1
- package/dist/esm/modules/swagger/utils/helpers/swagger.router.helpers.js +0 -98
- package/dist/esm/modules/swagger/utils/helpers/swagger.router.helpers.js.map +0 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/route-hook.template.js +0 -36
- package/dist/esm/utils/cli/utils/template-generator/templates/route-hook.template.js.map +0 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/service-hook.template.js +0 -29
- package/dist/esm/utils/cli/utils/template-generator/templates/service-hook.template.js.map +0 -1
- package/dist/types/components/arkos-loadable-translator/index.d.ts +0 -53
- package/dist/types/components/arkos-service-hook/index.d.ts +0 -41
- package/dist/types/components/arkos-service-hook/reader.d.ts +0 -35
- package/dist/types/components/arkos-service-hook/types.d.ts +0 -240
- package/dist/types/modules/base/utils/helpers/base.router.helpers.d.ts +0 -3
- package/dist/types/modules/base/utils/service-hooks-manager.d.ts +0 -10
- package/dist/types/modules/swagger/utils/built-in-route-path-object-manager.d.ts +0 -4
- package/dist/types/modules/swagger/utils/helpers/get-authentication-json-schema-paths.d.ts +0 -5
- package/dist/types/modules/swagger/utils/helpers/get-file-upload-json-schema-paths.d.ts +0 -3
- package/dist/types/modules/swagger/utils/helpers/get-system-json-schema-paths.d.ts +0 -2
- package/dist/types/modules/swagger/utils/helpers/json-schema-generators/generate-class-validator-json-schemas.d.ts +0 -1
- package/dist/types/modules/swagger/utils/helpers/json-schema-generators/generate-prisma-json-schemas.d.ts +0 -1
- package/dist/types/modules/swagger/utils/helpers/json-schema-generators/generate-system-json-schemas.d.ts +0 -4
- package/dist/types/modules/swagger/utils/helpers/json-schema-generators/generate-zod-json-schemas.d.ts +0 -1
- package/dist/types/modules/swagger/utils/helpers/json-schema-generators/prisma-models/generate-prisma-model-main-routes-paths.d.ts +0 -2
- package/dist/types/modules/swagger/utils/helpers/missing-json-schemas-generator.d.ts +0 -76
- package/dist/types/modules/swagger/utils/helpers/swagger.router.helpers.d.ts +0 -19
- package/dist/types/utils/cli/utils/template-generator/templates/route-hook.template.d.ts +0 -2
- package/dist/types/utils/cli/utils/template-generator/templates/service-hook.template.d.ts +0 -2
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import AppError from "../../../error-handler/utils/app-error.js";
|
|
5
|
+
import ArkosRouter from "../../../../utils/arkos-router/index.js";
|
|
6
|
+
import { extractPathParams } from "../../../../utils/arkos-router/utils/helpers/index.js";
|
|
7
|
+
import { getArkosConfig } from "../../../../server.js";
|
|
8
|
+
import deepmerge from "../../../../utils/helpers/deepmerge.helper.js";
|
|
9
|
+
import { assertSafeUploadPath, isRealPathInside, isSafeUploadParam, normalizeUploadDir, normalizeUploadUrlPath, resolveUploadPath, } from "./upload-path.helper.js";
|
|
10
|
+
import { uploadServingRegistry, } from "./upload-serving.registry.js";
|
|
11
|
+
const DEFAULT_STATIC_OPTIONS = {
|
|
12
|
+
maxAge: "1y",
|
|
13
|
+
etag: true,
|
|
14
|
+
lastModified: true,
|
|
15
|
+
dotfiles: "ignore",
|
|
16
|
+
fallthrough: false,
|
|
17
|
+
index: false,
|
|
18
|
+
cacheControl: true,
|
|
19
|
+
};
|
|
20
|
+
function buildStaticOptions(overrides) {
|
|
21
|
+
const config = getArkosConfig();
|
|
22
|
+
return deepmerge(deepmerge(DEFAULT_STATIC_OPTIONS, config.fileUpload?.expressStatic || {}), overrides || {});
|
|
23
|
+
}
|
|
24
|
+
function substituteParams(template, values) {
|
|
25
|
+
return template
|
|
26
|
+
.split("/")
|
|
27
|
+
.map((segment) => segment.startsWith(":") ? values[segment.slice(1)] : segment)
|
|
28
|
+
.join("/");
|
|
29
|
+
}
|
|
30
|
+
function stripMountSegments(url, segmentCount) {
|
|
31
|
+
const queryIndex = url.indexOf("?");
|
|
32
|
+
const rawPath = queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
33
|
+
const query = queryIndex === -1 ? "" : url.slice(queryIndex);
|
|
34
|
+
const parts = rawPath.split("/");
|
|
35
|
+
const start = rawPath.startsWith("/") ? segmentCount + 1 : segmentCount;
|
|
36
|
+
const remainder = parts.slice(start).join("/");
|
|
37
|
+
return `/${remainder}${query}`;
|
|
38
|
+
}
|
|
39
|
+
function isSafeServedPath(value) {
|
|
40
|
+
if (!value || value.includes("\\") || value.includes("\0"))
|
|
41
|
+
return false;
|
|
42
|
+
return value
|
|
43
|
+
.split("/")
|
|
44
|
+
.every((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
45
|
+
}
|
|
46
|
+
function notFound() {
|
|
47
|
+
return new AppError("File not found", 404, "FileNotFound");
|
|
48
|
+
}
|
|
49
|
+
function getLocals(req) {
|
|
50
|
+
return req.res?.locals || {};
|
|
51
|
+
}
|
|
52
|
+
function openApiConfig(dir) {
|
|
53
|
+
return {
|
|
54
|
+
tags: ["File Upload"],
|
|
55
|
+
summary: "Retrieve uploaded file",
|
|
56
|
+
description: `Serves files from the "${dir}" upload directory.`,
|
|
57
|
+
responses: {
|
|
58
|
+
"200": {
|
|
59
|
+
description: "File retrieved successfully",
|
|
60
|
+
content: {
|
|
61
|
+
"application/octet-stream": {
|
|
62
|
+
schema: { type: "string", format: "binary" },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
"404": {
|
|
67
|
+
description: "File not found",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function serveUploadDir(dir, options = {}) {
|
|
73
|
+
const normalizedDir = normalizeUploadDir(dir);
|
|
74
|
+
assertSafeUploadPath(normalizedDir, {
|
|
75
|
+
allowParams: true,
|
|
76
|
+
label: "upload directory",
|
|
77
|
+
});
|
|
78
|
+
const mountPath = normalizeUploadUrlPath(options.urlPath ?? `/${normalizedDir}`);
|
|
79
|
+
if (mountPath === "/")
|
|
80
|
+
throw new Error(`Invalid upload URL path "/" for upload directory "${normalizedDir}": it must contain at least one segment.`);
|
|
81
|
+
assertSafeUploadPath(mountPath.replace(/^\//, ""), {
|
|
82
|
+
allowParams: true,
|
|
83
|
+
label: "upload URL path",
|
|
84
|
+
});
|
|
85
|
+
if (options.prepare !== undefined && typeof options.prepare !== "function")
|
|
86
|
+
throw new Error(`Invalid prepare function for upload directory "${normalizedDir}": expected a function.`);
|
|
87
|
+
const dirParams = extractPathParams(`/${normalizedDir}`);
|
|
88
|
+
const pathParams = extractPathParams(mountPath);
|
|
89
|
+
if (dirParams.length > 0 && !options.prepare)
|
|
90
|
+
throw new Error(`Dynamic upload directory "${normalizedDir}" requires a prepare function.`);
|
|
91
|
+
const recursive = options.recursive === true;
|
|
92
|
+
const dynamic = dirParams.length > 0;
|
|
93
|
+
const mountSegments = mountPath.split("/").filter(Boolean).length;
|
|
94
|
+
const registration = {
|
|
95
|
+
dir: normalizedDir,
|
|
96
|
+
urlPath: mountPath,
|
|
97
|
+
dirParams,
|
|
98
|
+
pathParams,
|
|
99
|
+
recursive,
|
|
100
|
+
dynamic,
|
|
101
|
+
hasPrepare: !!options.prepare,
|
|
102
|
+
};
|
|
103
|
+
uploadServingRegistry.registerServe(registration);
|
|
104
|
+
const router = ArkosRouter();
|
|
105
|
+
let cachedStatic;
|
|
106
|
+
const resolveDirectory = async (req, _res, next) => {
|
|
107
|
+
try {
|
|
108
|
+
const config = getArkosConfig();
|
|
109
|
+
const baseUploadDir = config.fileUpload?.baseUploadDir || "uploads";
|
|
110
|
+
const basePath = path.resolve(process.cwd(), baseUploadDir);
|
|
111
|
+
const prepared = options.prepare
|
|
112
|
+
? await options.prepare(req, getLocals(req))
|
|
113
|
+
: undefined;
|
|
114
|
+
const values = prepared?.dirParams ?? {};
|
|
115
|
+
for (const param of dirParams) {
|
|
116
|
+
const value = values[param];
|
|
117
|
+
if (value === undefined)
|
|
118
|
+
throw new Error(`Missing required upload directory param ":${param}" for "${normalizedDir}" on "${req.method} ${req.originalUrl}".`);
|
|
119
|
+
if (!isSafeUploadParam(value))
|
|
120
|
+
return next(notFound());
|
|
121
|
+
}
|
|
122
|
+
const resolvedDir = substituteParams(normalizedDir, values);
|
|
123
|
+
const rootPath = resolveUploadPath(basePath, resolvedDir, {
|
|
124
|
+
strictSegments: true,
|
|
125
|
+
});
|
|
126
|
+
if (!rootPath)
|
|
127
|
+
return next(notFound());
|
|
128
|
+
if (!(await isRealPathInside(basePath, rootPath)))
|
|
129
|
+
return next(notFound());
|
|
130
|
+
let stats;
|
|
131
|
+
try {
|
|
132
|
+
stats = await fs.promises.stat(rootPath);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return next(notFound());
|
|
136
|
+
}
|
|
137
|
+
req.__arkos = {
|
|
138
|
+
...req.__arkos,
|
|
139
|
+
uploadDir: resolvedDir,
|
|
140
|
+
uploadPath: rootPath,
|
|
141
|
+
uploadKind: stats.isFile()
|
|
142
|
+
? "file"
|
|
143
|
+
: stats.isDirectory()
|
|
144
|
+
? "directory"
|
|
145
|
+
: undefined,
|
|
146
|
+
};
|
|
147
|
+
if (!req.__arkos.uploadKind)
|
|
148
|
+
return next(notFound());
|
|
149
|
+
next();
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
next(error);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const serveExactFile = (req, res, next) => {
|
|
156
|
+
const rootPath = req.__arkos?.uploadPath;
|
|
157
|
+
if (req.__arkos?.uploadKind !== "file" || !rootPath)
|
|
158
|
+
return next(notFound());
|
|
159
|
+
req.url = `/${encodeURIComponent(path.basename(rootPath))}${req.url.includes("?") ? req.url.slice(req.url.indexOf("?")) : ""}`;
|
|
160
|
+
const staticHandler = express.static(path.dirname(rootPath), buildStaticOptions(options.expressStatic));
|
|
161
|
+
staticHandler(req, res, next);
|
|
162
|
+
};
|
|
163
|
+
const serveFolder = (req, res, next) => {
|
|
164
|
+
const rootPath = req.__arkos?.uploadPath;
|
|
165
|
+
if (req.__arkos?.uploadKind !== "directory" || !rootPath)
|
|
166
|
+
return next(notFound());
|
|
167
|
+
if (!recursive) {
|
|
168
|
+
const fileName = req.params.fileName;
|
|
169
|
+
if (typeof fileName !== "string" ||
|
|
170
|
+
fileName.includes("/") ||
|
|
171
|
+
!isSafeServedPath(fileName))
|
|
172
|
+
return next(notFound());
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const filePath = req.params[0];
|
|
176
|
+
if (!filePath || !isSafeServedPath(filePath))
|
|
177
|
+
return next(notFound());
|
|
178
|
+
}
|
|
179
|
+
req.url = stripMountSegments(req.url, mountSegments);
|
|
180
|
+
if (req.url.split("?")[0] === "/")
|
|
181
|
+
return next(notFound());
|
|
182
|
+
if (!dynamic)
|
|
183
|
+
cachedStatic ??= express.static(rootPath, buildStaticOptions(options.expressStatic));
|
|
184
|
+
const staticHandler = cachedStatic ??
|
|
185
|
+
express.static(rootPath, buildStaticOptions(options.expressStatic));
|
|
186
|
+
staticHandler(req, res, next);
|
|
187
|
+
};
|
|
188
|
+
const handleStaticError = (err, req, _res, next) => {
|
|
189
|
+
if (err?.code === "ENOENT" ||
|
|
190
|
+
err?.status === 403 ||
|
|
191
|
+
err?.statusCode === 403)
|
|
192
|
+
return next(new AppError(`File ${req.path} was not found`, 404, "FileNotFound", { filepath: req.path }));
|
|
193
|
+
next(err);
|
|
194
|
+
};
|
|
195
|
+
const openapi = openApiConfig(normalizedDir);
|
|
196
|
+
router.get({
|
|
197
|
+
path: mountPath,
|
|
198
|
+
experimental: { openapi },
|
|
199
|
+
}, resolveDirectory, serveExactFile, handleStaticError);
|
|
200
|
+
router.get({
|
|
201
|
+
path: `${mountPath}${recursive ? "/*" : "/:fileName"}`,
|
|
202
|
+
experimental: { openapi },
|
|
203
|
+
}, resolveDirectory, serveFolder, handleStaticError);
|
|
204
|
+
return router;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=serve-upload-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-upload-dir.js","sourceRoot":"","sources":["../../../../../../src/modules/file-upload/utils/helpers/serve-upload-dir.ts"],"names":[],"mappings":"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","sourcesContent":["import express from \"express\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport AppError from \"../../../error-handler/utils/app-error\";\nimport { ArkosRequest, ArkosRequestHandler } from \"../../../../types\";\nimport type { UploadPrepare } from \"../../../../types/upload\";\nimport ArkosRouter from \"../../../../utils/arkos-router\";\nimport { IArkosRouter } from \"../../../../utils/arkos-router/types\";\nimport { extractPathParams } from \"../../../../utils/arkos-router/utils/helpers\";\nimport { getArkosConfig } from \"../../../../server\";\nimport deepmerge from \"../../../../utils/helpers/deepmerge.helper\";\nimport {\n assertSafeUploadPath,\n isRealPathInside,\n isSafeUploadParam,\n normalizeUploadDir,\n normalizeUploadUrlPath,\n resolveUploadPath,\n} from \"./upload-path.helper\";\nimport {\n uploadServingRegistry,\n UploadServeRegistration,\n} from \"./upload-serving.registry\";\n\nconst DEFAULT_STATIC_OPTIONS = {\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: false,\n index: false,\n cacheControl: true,\n};\n\nexport type ServeUploadDirOptions = {\n /**\n * Public URL folder, relative to the file upload `baseRoute`.\n *\n * @default `\"/\" + dir`\n */\n urlPath?: string;\n /**\n * Resolves the disk parameters for this folder. Required for every dynamic\n * folder (`:param` in `dir`). It may be async and may throw to deny the\n * request.\n */\n prepare?: UploadPrepare;\n /**\n * Options passed to `express.static`.\n */\n expressStatic?: Parameters<typeof express.static>[1];\n /**\n * Allow files in nested folders.\n *\n * @default false\n */\n recursive?: boolean;\n};\n\nfunction buildStaticOptions(\n overrides?: Parameters<typeof express.static>[1]\n) {\n const config = getArkosConfig();\n\n return deepmerge(\n deepmerge(DEFAULT_STATIC_OPTIONS, config.fileUpload?.expressStatic || {}),\n overrides || {}\n ) as Parameters<typeof express.static>[1];\n}\n\nfunction substituteParams(\n template: string,\n values: Record<string, string>\n): string {\n return template\n .split(\"/\")\n .map((segment) =>\n segment.startsWith(\":\") ? values[segment.slice(1)] : segment\n )\n .join(\"/\");\n}\n\nfunction stripMountSegments(url: string, segmentCount: number): string {\n const queryIndex = url.indexOf(\"?\");\n const rawPath = queryIndex === -1 ? url : url.slice(0, queryIndex);\n const query = queryIndex === -1 ? \"\" : url.slice(queryIndex);\n const parts = rawPath.split(\"/\");\n const start = rawPath.startsWith(\"/\") ? segmentCount + 1 : segmentCount;\n const remainder = parts.slice(start).join(\"/\");\n\n return `/${remainder}${query}`;\n}\n\nfunction isSafeServedPath(value: string): boolean {\n if (!value || value.includes(\"\\\\\") || value.includes(\"\\0\")) return false;\n\n return value\n .split(\"/\")\n .every(\n (segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\"\n );\n}\n\nfunction notFound() {\n return new AppError(\"File not found\", 404, \"FileNotFound\");\n}\n\nfunction getLocals(req: ArkosRequest): Record<string, any> {\n return req.res?.locals || {};\n}\n\nfunction openApiConfig(dir: string) {\n return {\n tags: [\"File Upload\"],\n summary: \"Retrieve uploaded file\",\n description: `Serves files from the \"${dir}\" upload directory.`,\n responses: {\n \"200\": {\n description: \"File retrieved successfully\",\n content: {\n \"application/octet-stream\": {\n schema: { type: \"string\", format: \"binary\" },\n },\n },\n },\n \"404\": {\n description: \"File not found\",\n },\n },\n };\n}\n\n/**\n * Serves a folder from the upload directory.\n *\n * Authentication belongs on the router mount:\n *\n * ```ts\n * fileUploadRouter.use(\n * { authentication: fileUploadPolicy.View },\n * arkos.serveUploadDir(\"/storage/acme\", { urlPath: \"/private/files\" })\n * );\n * ```\n *\n * When the resolved `dir` is a file, the route serves that file directly.\n * When it is a directory, the remainder of the request URL is served from it.\n */\nexport function serveUploadDir(\n dir: string,\n options: ServeUploadDirOptions = {}\n): IArkosRouter {\n const normalizedDir = normalizeUploadDir(dir);\n\n assertSafeUploadPath(normalizedDir, {\n allowParams: true,\n label: \"upload directory\",\n });\n\n const mountPath = normalizeUploadUrlPath(\n options.urlPath ?? `/${normalizedDir}`\n );\n\n if (mountPath === \"/\")\n throw new Error(\n `Invalid upload URL path \"/\" for upload directory \"${normalizedDir}\": it must contain at least one segment.`\n );\n\n assertSafeUploadPath(mountPath.replace(/^\\//, \"\"), {\n allowParams: true,\n label: \"upload URL path\",\n });\n\n if (options.prepare !== undefined && typeof options.prepare !== \"function\")\n throw new Error(\n `Invalid prepare function for upload directory \"${normalizedDir}\": expected a function.`\n );\n\n const dirParams = extractPathParams(`/${normalizedDir}`);\n const pathParams = extractPathParams(mountPath);\n\n if (dirParams.length > 0 && !options.prepare)\n throw new Error(\n `Dynamic upload directory \"${normalizedDir}\" requires a prepare function.`\n );\n\n const recursive = options.recursive === true;\n const dynamic = dirParams.length > 0;\n const mountSegments = mountPath.split(\"/\").filter(Boolean).length;\n\n const registration: UploadServeRegistration = {\n dir: normalizedDir,\n urlPath: mountPath,\n dirParams,\n pathParams,\n recursive,\n dynamic,\n hasPrepare: !!options.prepare,\n };\n\n uploadServingRegistry.registerServe(registration);\n\n const router = ArkosRouter();\n let cachedStatic: express.RequestHandler | undefined;\n\n const resolveDirectory: ArkosRequestHandler = async (req, _res, next) => {\n try {\n const config = getArkosConfig();\n const baseUploadDir = config.fileUpload?.baseUploadDir || \"uploads\";\n const basePath = path.resolve(process.cwd(), baseUploadDir);\n const prepared = options.prepare\n ? await options.prepare(req, getLocals(req))\n : undefined;\n const values = prepared?.dirParams ?? {};\n\n for (const param of dirParams) {\n const value = values[param];\n\n if (value === undefined)\n throw new Error(\n `Missing required upload directory param \":${param}\" for \"${normalizedDir}\" on \"${req.method} ${req.originalUrl}\".`\n );\n\n if (!isSafeUploadParam(value))\n return next(notFound());\n }\n\n const resolvedDir = substituteParams(normalizedDir, values);\n const rootPath = resolveUploadPath(basePath, resolvedDir, {\n strictSegments: true,\n });\n\n if (!rootPath) return next(notFound());\n\n if (!(await isRealPathInside(basePath, rootPath)))\n return next(notFound());\n\n let stats: fs.Stats;\n\n try {\n stats = await fs.promises.stat(rootPath);\n } catch {\n return next(notFound());\n }\n\n req.__arkos = {\n ...req.__arkos,\n uploadDir: resolvedDir,\n uploadPath: rootPath,\n uploadKind: stats.isFile()\n ? \"file\"\n : stats.isDirectory()\n ? \"directory\"\n : undefined,\n };\n\n if (!req.__arkos.uploadKind) return next(notFound());\n\n next();\n } catch (error) {\n next(error);\n }\n };\n\n const serveExactFile: ArkosRequestHandler = (req, res, next) => {\n const rootPath = req.__arkos?.uploadPath;\n\n if (req.__arkos?.uploadKind !== \"file\" || !rootPath)\n return next(notFound());\n\n req.url = `/${encodeURIComponent(path.basename(rootPath))}${\n req.url.includes(\"?\") ? req.url.slice(req.url.indexOf(\"?\")) : \"\"\n }`;\n\n const staticHandler = express.static(\n path.dirname(rootPath),\n buildStaticOptions(options.expressStatic)\n );\n\n staticHandler(req, res, next);\n };\n\n const serveFolder: ArkosRequestHandler = (req, res, next) => {\n const rootPath = req.__arkos?.uploadPath;\n\n if (req.__arkos?.uploadKind !== \"directory\" || !rootPath)\n return next(notFound());\n\n if (!recursive) {\n const fileName = (req.params as any).fileName;\n\n if (\n typeof fileName !== \"string\" ||\n fileName.includes(\"/\") ||\n !isSafeServedPath(fileName)\n )\n return next(notFound());\n } else {\n const filePath = (req.params as any)[0] as string | undefined;\n\n if (!filePath || !isSafeServedPath(filePath)) return next(notFound());\n }\n\n req.url = stripMountSegments(req.url, mountSegments);\n\n if (req.url.split(\"?\")[0] === \"/\") return next(notFound());\n\n if (!dynamic)\n cachedStatic ??= express.static(\n rootPath,\n buildStaticOptions(options.expressStatic)\n );\n\n const staticHandler =\n cachedStatic ??\n express.static(rootPath, buildStaticOptions(options.expressStatic));\n\n staticHandler(req, res, next);\n };\n\n const handleStaticError = (\n err: any,\n req: any,\n _res: any,\n next: (error?: any) => void\n ) => {\n if (\n err?.code === \"ENOENT\" ||\n err?.status === 403 ||\n err?.statusCode === 403\n )\n return next(\n new AppError(\n `File ${req.path} was not found`,\n 404,\n \"FileNotFound\",\n { filepath: req.path }\n )\n );\n\n next(err);\n };\n\n const openapi = openApiConfig(normalizedDir);\n\n router.get(\n {\n path: mountPath,\n experimental: { openapi },\n },\n resolveDirectory,\n serveExactFile,\n handleStaticError as any\n );\n\n router.get(\n {\n path: `${mountPath}${recursive ? \"/*\" : \"/:fileName\"}`,\n experimental: { openapi },\n },\n resolveDirectory,\n serveFolder,\n handleStaticError as any\n );\n\n return router;\n}\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export const DEFAULT_UPLOAD_DIRS = [
|
|
4
|
+
"images",
|
|
5
|
+
"videos",
|
|
6
|
+
"documents",
|
|
7
|
+
"files",
|
|
8
|
+
];
|
|
9
|
+
const SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
10
|
+
const PARAM_SEGMENT = /^:[A-Za-z_][A-Za-z0-9_]*$/;
|
|
11
|
+
const RESERVED_WINDOWS_NAMES = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;
|
|
12
|
+
export function isSafeUploadSegment(segment, allowParam = false) {
|
|
13
|
+
if (!segment)
|
|
14
|
+
return false;
|
|
15
|
+
if (allowParam && PARAM_SEGMENT.test(segment))
|
|
16
|
+
return true;
|
|
17
|
+
if (!SAFE_SEGMENT.test(segment))
|
|
18
|
+
return false;
|
|
19
|
+
if (segment === "." || segment === "..")
|
|
20
|
+
return false;
|
|
21
|
+
if (/[. ]$/.test(segment))
|
|
22
|
+
return false;
|
|
23
|
+
if (RESERVED_WINDOWS_NAMES.test(segment))
|
|
24
|
+
return false;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
export function assertSafeUploadPath(value, options = {}) {
|
|
28
|
+
const label = options.label || "upload path";
|
|
29
|
+
if (typeof value !== "string" || value.length === 0)
|
|
30
|
+
throw new Error(`Invalid ${label}: it must be a non-empty string.`);
|
|
31
|
+
if (path.isAbsolute(value))
|
|
32
|
+
throw new Error(`Invalid ${label} "${value}": absolute paths are not allowed.`);
|
|
33
|
+
if (value.includes("\\") || value.includes("\0"))
|
|
34
|
+
throw new Error(`Invalid ${label} "${value}": backslashes and null bytes are not allowed.`);
|
|
35
|
+
for (const segment of value.split("/")) {
|
|
36
|
+
if (!segment || segment === "." || segment === "..")
|
|
37
|
+
throw new Error(`Invalid ${label} "${value}": empty, "." and ".." segments are not allowed.`);
|
|
38
|
+
if (!isSafeUploadSegment(segment, options.allowParams))
|
|
39
|
+
throw new Error(`Invalid ${label} "${value}": segment "${segment}" is not allowed. Use letters, numbers, ".", "_" and "-".`);
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
export function normalizeUploadDir(dir) {
|
|
44
|
+
return dir.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
45
|
+
}
|
|
46
|
+
export function normalizeUploadUrlPath(urlPath) {
|
|
47
|
+
let result = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
|
|
48
|
+
if (result.length > 1)
|
|
49
|
+
result = result.replace(/\/+$/, "");
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
export function isSafeUploadParam(value) {
|
|
53
|
+
return (typeof value === "string" &&
|
|
54
|
+
value.length > 0 &&
|
|
55
|
+
value.length <= 128 &&
|
|
56
|
+
SAFE_SEGMENT.test(value) &&
|
|
57
|
+
value !== "." &&
|
|
58
|
+
value !== ".." &&
|
|
59
|
+
!/[. ]$/.test(value) &&
|
|
60
|
+
!RESERVED_WINDOWS_NAMES.test(value));
|
|
61
|
+
}
|
|
62
|
+
export function isPathInside(base, target) {
|
|
63
|
+
const relative = path.relative(base, target);
|
|
64
|
+
return (relative === "" ||
|
|
65
|
+
(!relative.startsWith(`..${path.sep}`) &&
|
|
66
|
+
relative !== ".." &&
|
|
67
|
+
!path.isAbsolute(relative)));
|
|
68
|
+
}
|
|
69
|
+
export function resolveUploadPath(root, relative, options = {}) {
|
|
70
|
+
if (typeof relative !== "string")
|
|
71
|
+
return null;
|
|
72
|
+
const cleaned = relative.replace(/^\/+/, "");
|
|
73
|
+
if (cleaned.includes("\0") || cleaned.includes("\\"))
|
|
74
|
+
return null;
|
|
75
|
+
if (cleaned === "")
|
|
76
|
+
return path.resolve(root);
|
|
77
|
+
for (const segment of cleaned.split("/")) {
|
|
78
|
+
if (!segment || segment === "." || segment === "..")
|
|
79
|
+
return null;
|
|
80
|
+
if (options.strictSegments && !isSafeUploadSegment(segment))
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const resolvedRoot = path.resolve(root);
|
|
84
|
+
const resolved = path.resolve(resolvedRoot, ...cleaned.split("/"));
|
|
85
|
+
if (!isPathInside(resolvedRoot, resolved))
|
|
86
|
+
return null;
|
|
87
|
+
return resolved;
|
|
88
|
+
}
|
|
89
|
+
export async function isRealPathInside(base, target) {
|
|
90
|
+
try {
|
|
91
|
+
const [realBase, realTarget] = await Promise.all([
|
|
92
|
+
fs.promises.realpath(base),
|
|
93
|
+
fs.promises.realpath(target),
|
|
94
|
+
]);
|
|
95
|
+
return isPathInside(realBase, realTarget);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error?.code === "ENOENT")
|
|
99
|
+
return true;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=upload-path.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-path.helper.js","sourceRoot":"","sources":["../../../../../../src/modules/file-upload/utils/helpers/upload-path.helper.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nexport const DEFAULT_UPLOAD_DIRS = [\n \"images\",\n \"videos\",\n \"documents\",\n \"files\",\n] as const;\n\nconst SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nconst PARAM_SEGMENT = /^:[A-Za-z_][A-Za-z0-9_]*$/;\nconst RESERVED_WINDOWS_NAMES = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;\n\nexport function isSafeUploadSegment(\n segment: string,\n allowParam = false\n): boolean {\n if (!segment) return false;\n if (allowParam && PARAM_SEGMENT.test(segment)) return true;\n if (!SAFE_SEGMENT.test(segment)) return false;\n if (segment === \".\" || segment === \"..\") return false;\n if (/[. ]$/.test(segment)) return false;\n if (RESERVED_WINDOWS_NAMES.test(segment)) return false;\n return true;\n}\n\nexport function assertSafeUploadPath(\n value: string,\n options: { allowParams?: boolean; label?: string } = {}\n) {\n const label = options.label || \"upload path\";\n\n if (typeof value !== \"string\" || value.length === 0)\n throw new Error(`Invalid ${label}: it must be a non-empty string.`);\n\n if (path.isAbsolute(value))\n throw new Error(\n `Invalid ${label} \"${value}\": absolute paths are not allowed.`\n );\n\n if (value.includes(\"\\\\\") || value.includes(\"\\0\"))\n throw new Error(\n `Invalid ${label} \"${value}\": backslashes and null bytes are not allowed.`\n );\n\n for (const segment of value.split(\"/\")) {\n if (!segment || segment === \".\" || segment === \"..\")\n throw new Error(\n `Invalid ${label} \"${value}\": empty, \".\" and \"..\" segments are not allowed.`\n );\n\n if (!isSafeUploadSegment(segment, options.allowParams))\n throw new Error(\n `Invalid ${label} \"${value}\": segment \"${segment}\" is not allowed. Use letters, numbers, \".\", \"_\" and \"-\".`\n );\n }\n\n return value;\n}\n\nexport function normalizeUploadDir(dir: string): string {\n return dir.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function normalizeUploadUrlPath(urlPath: string): string {\n let result = urlPath.startsWith(\"/\") ? urlPath : `/${urlPath}`;\n if (result.length > 1) result = result.replace(/\\/+$/, \"\");\n return result;\n}\n\nexport function isSafeUploadParam(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n value.length <= 128 &&\n SAFE_SEGMENT.test(value) &&\n value !== \".\" &&\n value !== \"..\" &&\n !/[. ]$/.test(value) &&\n !RESERVED_WINDOWS_NAMES.test(value)\n );\n}\n\nexport function isPathInside(base: string, target: string): boolean {\n const relative = path.relative(base, target);\n return (\n relative === \"\" ||\n (!relative.startsWith(`..${path.sep}`) &&\n relative !== \"..\" &&\n !path.isAbsolute(relative))\n );\n}\n\nexport function resolveUploadPath(\n root: string,\n relative: string,\n options: { strictSegments?: boolean } = {}\n): string | null {\n if (typeof relative !== \"string\") return null;\n\n const cleaned = relative.replace(/^\\/+/, \"\");\n if (cleaned.includes(\"\\0\") || cleaned.includes(\"\\\\\")) return null;\n if (cleaned === \"\") return path.resolve(root);\n\n for (const segment of cleaned.split(\"/\")) {\n if (!segment || segment === \".\" || segment === \"..\") return null;\n if (options.strictSegments && !isSafeUploadSegment(segment)) return null;\n }\n\n const resolvedRoot = path.resolve(root);\n const resolved = path.resolve(resolvedRoot, ...cleaned.split(\"/\"));\n\n if (!isPathInside(resolvedRoot, resolved)) return null;\n\n return resolved;\n}\n\nexport async function isRealPathInside(\n base: string,\n target: string\n): Promise<boolean> {\n try {\n const [realBase, realTarget] = await Promise.all([\n fs.promises.realpath(base),\n fs.promises.realpath(target),\n ]);\n\n return isPathInside(realBase, realTarget);\n } catch (error: any) {\n if (error?.code === \"ENOENT\") return true;\n return false;\n }\n}\n"]}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import sheu from "../../../../utils/sheu.js";
|
|
2
|
+
import { getArkosConfig } from "../../../../server.js";
|
|
3
|
+
import { extractPathParams } from "../../../../utils/arkos-router/utils/helpers/index.js";
|
|
4
|
+
import { DEFAULT_UPLOAD_DIRS, assertSafeUploadPath, normalizeUploadDir, normalizeUploadUrlPath, } from "./upload-path.helper.js";
|
|
5
|
+
import { uploadServingRegistry, } from "./upload-serving.registry.js";
|
|
6
|
+
function isExactUrlPath(urlPath) {
|
|
7
|
+
return !!urlPath && typeof urlPath === "object";
|
|
8
|
+
}
|
|
9
|
+
function normalizeBaseRoute(baseRoute) {
|
|
10
|
+
const withLeadingSlash = baseRoute.startsWith("/")
|
|
11
|
+
? baseRoute
|
|
12
|
+
: `/${baseRoute}`;
|
|
13
|
+
return withLeadingSlash.length > 1
|
|
14
|
+
? withLeadingSlash.replace(/\/+$/, "")
|
|
15
|
+
: withLeadingSlash;
|
|
16
|
+
}
|
|
17
|
+
function assertUrlPathIsRelativeToBaseRoute(urlPath, baseRoute, route) {
|
|
18
|
+
const normalizedBaseRoute = normalizeBaseRoute(baseRoute);
|
|
19
|
+
if (urlPath === normalizedBaseRoute ||
|
|
20
|
+
urlPath.startsWith(`${normalizedBaseRoute}/`))
|
|
21
|
+
throw new Error(`Invalid urlPath "${urlPath}" on route "${route}": it is relative to baseRoute and must not include "${normalizedBaseRoute}".`);
|
|
22
|
+
}
|
|
23
|
+
function substitutePath(pathTemplate, params) {
|
|
24
|
+
return pathTemplate
|
|
25
|
+
.split("/")
|
|
26
|
+
.map((segment) => segment.startsWith(":") ? params[segment.slice(1)] : segment)
|
|
27
|
+
.join("/");
|
|
28
|
+
}
|
|
29
|
+
function matchDirTemplates(serveDir, writeDir, recursive) {
|
|
30
|
+
const serveSegments = normalizeUploadDir(serveDir).split("/");
|
|
31
|
+
const writeSegments = normalizeUploadDir(writeDir).split("/");
|
|
32
|
+
if (serveSegments.length > writeSegments.length)
|
|
33
|
+
return null;
|
|
34
|
+
if (serveSegments.length < writeSegments.length && !recursive)
|
|
35
|
+
return null;
|
|
36
|
+
const params = {};
|
|
37
|
+
for (let index = 0; index < serveSegments.length; index++) {
|
|
38
|
+
const serveSegment = serveSegments[index];
|
|
39
|
+
const writeSegment = writeSegments[index];
|
|
40
|
+
if (serveSegment.startsWith(":")) {
|
|
41
|
+
if (writeSegment.startsWith(":")) {
|
|
42
|
+
if (serveSegment.slice(1) !== writeSegment.slice(1))
|
|
43
|
+
return null;
|
|
44
|
+
params[serveSegment.slice(1)] = serveSegment;
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
params[serveSegment.slice(1)] = writeSegment;
|
|
48
|
+
}
|
|
49
|
+
else if (serveSegment !== writeSegment)
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
params,
|
|
54
|
+
matched: serveSegments.length,
|
|
55
|
+
remaining: writeSegments.slice(serveSegments.length),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function validateWriteUrlPath(registration, baseRoute) {
|
|
59
|
+
const { urlPath, route, dir } = registration;
|
|
60
|
+
if (urlPath === undefined)
|
|
61
|
+
return;
|
|
62
|
+
if (!dir)
|
|
63
|
+
throw new Error(`Route "${route}" declares urlPath but does not declare uploadDir.`);
|
|
64
|
+
if (isExactUrlPath(urlPath)) {
|
|
65
|
+
const exact = urlPath.exact;
|
|
66
|
+
if (typeof exact !== "string" || !exact.startsWith("/"))
|
|
67
|
+
throw new Error(`Invalid exact urlPath on route "${route}": it must be a string starting with "/".`);
|
|
68
|
+
if (exact.length > 1 && exact.endsWith("/"))
|
|
69
|
+
throw new Error(`Invalid exact urlPath "${exact}" on route "${route}": it must not end with "/".`);
|
|
70
|
+
if (exact === "/")
|
|
71
|
+
throw new Error(`Invalid exact urlPath "/" on route "${route}": it must contain at least one segment.`);
|
|
72
|
+
assertSafeUploadPath(exact.replace(/^\//, ""), {
|
|
73
|
+
label: "exact upload urlPath",
|
|
74
|
+
});
|
|
75
|
+
assertUrlPathIsRelativeToBaseRoute(exact, baseRoute, route);
|
|
76
|
+
if (registration.type === "array")
|
|
77
|
+
throw new Error(`Exact urlPath "${exact}" on route "${route}" cannot be used with array uploads because every file would share the same URL.`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!urlPath.startsWith("/"))
|
|
81
|
+
throw new Error(`Invalid urlPath "${urlPath}" on route "${route}": it must start with "/".`);
|
|
82
|
+
if (urlPath.endsWith("/"))
|
|
83
|
+
throw new Error(`Invalid urlPath "${urlPath}" on route "${route}": it must not end with "/".`);
|
|
84
|
+
assertSafeUploadPath(urlPath.replace(/^\//, ""), {
|
|
85
|
+
allowParams: true,
|
|
86
|
+
label: "upload urlPath",
|
|
87
|
+
});
|
|
88
|
+
assertUrlPathIsRelativeToBaseRoute(urlPath, baseRoute, route);
|
|
89
|
+
}
|
|
90
|
+
function warnAboutUnusedUrlParams(dir, urlPath, route, suppress) {
|
|
91
|
+
if (suppress)
|
|
92
|
+
return;
|
|
93
|
+
const dirParams = extractPathParams(`/${dir}`);
|
|
94
|
+
const unused = extractPathParams(urlPath).filter((param) => !dirParams.includes(param));
|
|
95
|
+
if (unused.length > 0)
|
|
96
|
+
sheu.warn(`Upload urlPath "${urlPath}" on route "${route}" declares ${unused
|
|
97
|
+
.map((param) => `":${param}"`)
|
|
98
|
+
.join(", ")} but uploadDir "${dir}" does not use them.`, { timestamp: true });
|
|
99
|
+
}
|
|
100
|
+
export function validateUploadServingConfig() {
|
|
101
|
+
const config = getArkosConfig();
|
|
102
|
+
const serving = config.fileUpload?.serving || "all";
|
|
103
|
+
const findFileEnabled = uploadServingRegistry.isFindFileServingEnabled();
|
|
104
|
+
const baseRoute = config.fileUpload?.baseRoute || "/api/uploads";
|
|
105
|
+
const suppressUnusedUrlParams = config.warnings?.fileUpload?.suppressUnusedUrlParams === true;
|
|
106
|
+
const serveRegistrations = uploadServingRegistry.getServeRegistrations();
|
|
107
|
+
const writeRegistrations = uploadServingRegistry.getWriteRegistrations();
|
|
108
|
+
const seenServePaths = new Map();
|
|
109
|
+
const seenServeDirs = new Map();
|
|
110
|
+
const seenExactWritePaths = new Map();
|
|
111
|
+
const warnedRoutes = new Set();
|
|
112
|
+
for (const registration of serveRegistrations) {
|
|
113
|
+
const dir = normalizeUploadDir(registration.dir);
|
|
114
|
+
const publicPath = normalizeUploadUrlPath(registration.urlPath);
|
|
115
|
+
const firstDirSegment = dir.split("/")[0];
|
|
116
|
+
const firstPathSegment = publicPath.replace(/^\//, "").split("/")[0];
|
|
117
|
+
if (registration.dynamic && !registration.hasPrepare)
|
|
118
|
+
throw new Error(`Dynamic upload directory "${dir}" requires a prepare function.`);
|
|
119
|
+
if (registration.pathParams.length > 0 && !suppressUnusedUrlParams) {
|
|
120
|
+
const unused = registration.pathParams.filter((param) => !registration.dirParams.includes(param));
|
|
121
|
+
if (unused.length > 0)
|
|
122
|
+
sheu.warn(`Upload URL path "${publicPath}" declares ${unused
|
|
123
|
+
.map((param) => `":${param}"`)
|
|
124
|
+
.join(", ")} but the upload directory "${dir}" does not use them.`, { timestamp: true });
|
|
125
|
+
}
|
|
126
|
+
if (findFileEnabled &&
|
|
127
|
+
DEFAULT_UPLOAD_DIRS.includes(firstDirSegment))
|
|
128
|
+
throw new Error(`Cannot serve upload directory "${dir}" with arkos.serveUploadDir(): "${firstDirSegment}" is a built-in upload root and is always served while findFile is enabled.`);
|
|
129
|
+
if (findFileEnabled &&
|
|
130
|
+
DEFAULT_UPLOAD_DIRS.includes(firstPathSegment))
|
|
131
|
+
throw new Error(`Cannot register upload URL path "${publicPath}": "/${firstPathSegment}" is a built-in upload root and is always served while findFile is enabled.`);
|
|
132
|
+
if (seenServePaths.has(publicPath))
|
|
133
|
+
throw new Error(`Duplicate upload serving path "${publicPath}" registered with arkos.serveUploadDir().`);
|
|
134
|
+
seenServePaths.set(publicPath, dir);
|
|
135
|
+
if (seenServeDirs.has(dir))
|
|
136
|
+
throw new Error(seenServeDirs.get(dir) === publicPath
|
|
137
|
+
? `Duplicate arkos.serveUploadDir() registration for "${dir}".`
|
|
138
|
+
: `Upload directory "${dir}" is served at multiple paths: "${seenServeDirs.get(dir)}" and "${publicPath}".`);
|
|
139
|
+
seenServeDirs.set(dir, publicPath);
|
|
140
|
+
}
|
|
141
|
+
let warnedAboutAllMode = false;
|
|
142
|
+
for (const registration of writeRegistrations) {
|
|
143
|
+
const dir = registration.dir
|
|
144
|
+
? normalizeUploadDir(registration.dir)
|
|
145
|
+
: undefined;
|
|
146
|
+
validateWriteUrlPath(registration, baseRoute);
|
|
147
|
+
if (!dir)
|
|
148
|
+
continue;
|
|
149
|
+
assertSafeUploadPath(dir, { allowParams: true, label: "uploadDir" });
|
|
150
|
+
const dirParams = extractPathParams(`/${dir}`);
|
|
151
|
+
if (dirParams.length > 0 && !registration.hasPrepare)
|
|
152
|
+
throw new Error(`Dynamic upload directory "${dir}" on route "${registration.route}" requires a prepare function.`);
|
|
153
|
+
if (registration.urlPath !== undefined &&
|
|
154
|
+
!isExactUrlPath(registration.urlPath)) {
|
|
155
|
+
const warningKey = `${registration.route}:${dir}:${registration.urlPath}`;
|
|
156
|
+
if (!warnedRoutes.has(warningKey)) {
|
|
157
|
+
warnAboutUnusedUrlParams(dir, registration.urlPath, registration.route, suppressUnusedUrlParams);
|
|
158
|
+
warnedRoutes.add(warningKey);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (isExactUrlPath(registration.urlPath)) {
|
|
162
|
+
const exact = registration.urlPath.exact;
|
|
163
|
+
if (seenExactWritePaths.has(exact))
|
|
164
|
+
throw new Error(`Duplicate exact urlPath "${exact}" on route "${registration.route}"; it is already used on route "${seenExactWritePaths.get(exact)}".`);
|
|
165
|
+
seenExactWritePaths.set(exact, registration.route);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const firstDirSegment = dir.split("/")[0];
|
|
169
|
+
if (findFileEnabled &&
|
|
170
|
+
DEFAULT_UPLOAD_DIRS.includes(firstDirSegment))
|
|
171
|
+
continue;
|
|
172
|
+
if (serving === "all") {
|
|
173
|
+
if (!warnedAboutAllMode && serveRegistrations.length > 0) {
|
|
174
|
+
warningAboutAllMode();
|
|
175
|
+
warnedAboutAllMode = true;
|
|
176
|
+
}
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (registration.serve === false)
|
|
180
|
+
continue;
|
|
181
|
+
const writePublicPath = normalizeUploadUrlPath(registration.urlPath ?? `/${dir}`);
|
|
182
|
+
let bestMatch;
|
|
183
|
+
for (const serveRegistration of serveRegistrations) {
|
|
184
|
+
const match = matchDirTemplates(serveRegistration.dir, dir, serveRegistration.recursive);
|
|
185
|
+
if (!match)
|
|
186
|
+
continue;
|
|
187
|
+
if (!bestMatch || match.matched > bestMatch.match.matched) {
|
|
188
|
+
bestMatch = { registration: serveRegistration, match };
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (match.matched === bestMatch.match.matched &&
|
|
192
|
+
normalizeUploadUrlPath(serveRegistration.urlPath) !==
|
|
193
|
+
normalizeUploadUrlPath(bestMatch.registration.urlPath))
|
|
194
|
+
throw new Error(`Upload directory "${dir}" on route "${registration.route}" is ambiguously served by "${bestMatch.registration.urlPath}" and "${serveRegistration.urlPath}".`);
|
|
195
|
+
}
|
|
196
|
+
if (!bestMatch)
|
|
197
|
+
throw new Error(`Upload directory "${dir}" used by route "${registration.route}" is not served. Register it with arkos.serveUploadDir("${dir}"), register one of its parent folders with arkos.serveUploadDir(parent, { recursive: true }), or set "serve: false" in the route's uploads config.`);
|
|
198
|
+
const servedPublicPath = normalizeUploadUrlPath(`${substitutePath(bestMatch.registration.urlPath, bestMatch.match.params)}${bestMatch.match.remaining.length
|
|
199
|
+
? `/${bestMatch.match.remaining.join("/")}`
|
|
200
|
+
: ""}`);
|
|
201
|
+
if (servedPublicPath !== writePublicPath)
|
|
202
|
+
throw new Error(`Generated URL "${writePublicPath}" does not match served URL "${servedPublicPath}" for upload directory "${dir}".`);
|
|
203
|
+
}
|
|
204
|
+
if (serving === "all" &&
|
|
205
|
+
serveRegistrations.length > 0 &&
|
|
206
|
+
!warnedAboutAllMode)
|
|
207
|
+
warningAboutAllMode();
|
|
208
|
+
}
|
|
209
|
+
function warningAboutAllMode() {
|
|
210
|
+
sheu.warn(`fileUpload.serving is "all"; per-folder permissions registered via arkos.serveUploadDir() are not enforced.`, { timestamp: true });
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=upload-serving-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-serving-validation.js","sourceRoot":"","sources":["../../../../../../src/modules/file-upload/utils/helpers/upload-serving-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import sheu from \"../../../../utils/sheu\";\nimport { getArkosConfig } from \"../../../../server\";\nimport { extractPathParams } from \"../../../../utils/arkos-router/utils/helpers\";\nimport type { UploadUrlPath } from \"../../../../types/upload\";\nimport {\n DEFAULT_UPLOAD_DIRS,\n assertSafeUploadPath,\n normalizeUploadDir,\n normalizeUploadUrlPath,\n} from \"./upload-path.helper\";\nimport {\n uploadServingRegistry,\n UploadServeRegistration,\n UploadWriteRegistration,\n} from \"./upload-serving.registry\";\n\ntype TemplateMatch = {\n params: Record<string, string>;\n matched: number;\n remaining: string[];\n};\n\nfunction isExactUrlPath(\n urlPath: UploadUrlPath | undefined\n): urlPath is { exact: string } {\n return !!urlPath && typeof urlPath === \"object\";\n}\n\nfunction normalizeBaseRoute(baseRoute: string): string {\n const withLeadingSlash = baseRoute.startsWith(\"/\")\n ? baseRoute\n : `/${baseRoute}`;\n\n return withLeadingSlash.length > 1\n ? withLeadingSlash.replace(/\\/+$/, \"\")\n : withLeadingSlash;\n}\n\nfunction assertUrlPathIsRelativeToBaseRoute(\n urlPath: string,\n baseRoute: string,\n route: string\n) {\n const normalizedBaseRoute = normalizeBaseRoute(baseRoute);\n\n if (\n urlPath === normalizedBaseRoute ||\n urlPath.startsWith(`${normalizedBaseRoute}/`)\n )\n throw new Error(\n `Invalid urlPath \"${urlPath}\" on route \"${route}\": it is relative to baseRoute and must not include \"${normalizedBaseRoute}\".`\n );\n}\n\nfunction substitutePath(\n pathTemplate: string,\n params: Record<string, string>\n): string {\n return pathTemplate\n .split(\"/\")\n .map((segment) =>\n segment.startsWith(\":\") ? params[segment.slice(1)] : segment\n )\n .join(\"/\");\n}\n\nfunction matchDirTemplates(\n serveDir: string,\n writeDir: string,\n recursive: boolean\n): TemplateMatch | null {\n const serveSegments = normalizeUploadDir(serveDir).split(\"/\");\n const writeSegments = normalizeUploadDir(writeDir).split(\"/\");\n\n if (serveSegments.length > writeSegments.length) return null;\n if (serveSegments.length < writeSegments.length && !recursive) return null;\n\n const params: Record<string, string> = {};\n\n for (let index = 0; index < serveSegments.length; index++) {\n const serveSegment = serveSegments[index];\n const writeSegment = writeSegments[index];\n\n if (serveSegment.startsWith(\":\")) {\n if (writeSegment.startsWith(\":\")) {\n if (serveSegment.slice(1) !== writeSegment.slice(1)) return null;\n params[serveSegment.slice(1)] = serveSegment;\n } else params[serveSegment.slice(1)] = writeSegment;\n } else if (serveSegment !== writeSegment) return null;\n }\n\n return {\n params,\n matched: serveSegments.length,\n remaining: writeSegments.slice(serveSegments.length),\n };\n}\n\nfunction validateWriteUrlPath(\n registration: UploadWriteRegistration,\n baseRoute: string\n) {\n const { urlPath, route, dir } = registration;\n\n if (urlPath === undefined) return;\n\n if (!dir)\n throw new Error(\n `Route \"${route}\" declares urlPath but does not declare uploadDir.`\n );\n\n if (isExactUrlPath(urlPath)) {\n const exact = urlPath.exact;\n\n if (typeof exact !== \"string\" || !exact.startsWith(\"/\"))\n throw new Error(\n `Invalid exact urlPath on route \"${route}\": it must be a string starting with \"/\".`\n );\n\n if (exact.length > 1 && exact.endsWith(\"/\"))\n throw new Error(\n `Invalid exact urlPath \"${exact}\" on route \"${route}\": it must not end with \"/\".`\n );\n\n if (exact === \"/\")\n throw new Error(\n `Invalid exact urlPath \"/\" on route \"${route}\": it must contain at least one segment.`\n );\n\n assertSafeUploadPath(exact.replace(/^\\//, \"\"), {\n label: \"exact upload urlPath\",\n });\n\n assertUrlPathIsRelativeToBaseRoute(exact, baseRoute, route);\n\n if (registration.type === \"array\")\n throw new Error(\n `Exact urlPath \"${exact}\" on route \"${route}\" cannot be used with array uploads because every file would share the same URL.`\n );\n\n return;\n }\n\n if (!urlPath.startsWith(\"/\"))\n throw new Error(\n `Invalid urlPath \"${urlPath}\" on route \"${route}\": it must start with \"/\".`\n );\n\n if (urlPath.endsWith(\"/\"))\n throw new Error(\n `Invalid urlPath \"${urlPath}\" on route \"${route}\": it must not end with \"/\".`\n );\n\n assertSafeUploadPath(urlPath.replace(/^\\//, \"\"), {\n allowParams: true,\n label: \"upload urlPath\",\n });\n\n assertUrlPathIsRelativeToBaseRoute(urlPath, baseRoute, route);\n}\n\nfunction warnAboutUnusedUrlParams(\n dir: string,\n urlPath: string,\n route: string,\n suppress: boolean\n) {\n if (suppress) return;\n\n const dirParams = extractPathParams(`/${dir}`);\n const unused = extractPathParams(urlPath).filter(\n (param) => !dirParams.includes(param)\n );\n\n if (unused.length > 0)\n sheu.warn(\n `Upload urlPath \"${urlPath}\" on route \"${route}\" declares ${unused\n .map((param) => `\":${param}\"`)\n .join(\", \")} but uploadDir \"${dir}\" does not use them.`,\n { timestamp: true }\n );\n}\n\n/**\n * Validates the upload serving registrations collected while building the\n * routers. Must run once, after every router has been constructed.\n */\nexport function validateUploadServingConfig() {\n const config = getArkosConfig();\n const serving = config.fileUpload?.serving || \"all\";\n const findFileEnabled = uploadServingRegistry.isFindFileServingEnabled();\n const baseRoute = config.fileUpload?.baseRoute || \"/api/uploads\";\n const suppressUnusedUrlParams =\n config.warnings?.fileUpload?.suppressUnusedUrlParams === true;\n const serveRegistrations = uploadServingRegistry.getServeRegistrations();\n const writeRegistrations = uploadServingRegistry.getWriteRegistrations();\n\n const seenServePaths = new Map<string, string>();\n const seenServeDirs = new Map<string, string>();\n const seenExactWritePaths = new Map<string, string>();\n const warnedRoutes = new Set<string>();\n\n for (const registration of serveRegistrations) {\n const dir = normalizeUploadDir(registration.dir);\n const publicPath = normalizeUploadUrlPath(registration.urlPath);\n const firstDirSegment = dir.split(\"/\")[0];\n const firstPathSegment = publicPath.replace(/^\\//, \"\").split(\"/\")[0];\n\n if (registration.dynamic && !registration.hasPrepare)\n throw new Error(\n `Dynamic upload directory \"${dir}\" requires a prepare function.`\n );\n\n if (registration.pathParams.length > 0 && !suppressUnusedUrlParams) {\n const unused = registration.pathParams.filter(\n (param) => !registration.dirParams.includes(param)\n );\n\n if (unused.length > 0)\n sheu.warn(\n `Upload URL path \"${publicPath}\" declares ${unused\n .map((param) => `\":${param}\"`)\n .join(\", \")} but the upload directory \"${dir}\" does not use them.`,\n { timestamp: true }\n );\n }\n\n if (\n findFileEnabled &&\n (DEFAULT_UPLOAD_DIRS as readonly string[]).includes(firstDirSegment)\n )\n throw new Error(\n `Cannot serve upload directory \"${dir}\" with arkos.serveUploadDir(): \"${firstDirSegment}\" is a built-in upload root and is always served while findFile is enabled.`\n );\n\n if (\n findFileEnabled &&\n (DEFAULT_UPLOAD_DIRS as readonly string[]).includes(firstPathSegment)\n )\n throw new Error(\n `Cannot register upload URL path \"${publicPath}\": \"/${firstPathSegment}\" is a built-in upload root and is always served while findFile is enabled.`\n );\n\n if (seenServePaths.has(publicPath))\n throw new Error(\n `Duplicate upload serving path \"${publicPath}\" registered with arkos.serveUploadDir().`\n );\n\n seenServePaths.set(publicPath, dir);\n\n if (seenServeDirs.has(dir))\n throw new Error(\n seenServeDirs.get(dir) === publicPath\n ? `Duplicate arkos.serveUploadDir() registration for \"${dir}\".`\n : `Upload directory \"${dir}\" is served at multiple paths: \"${seenServeDirs.get(\n dir\n )}\" and \"${publicPath}\".`\n );\n\n seenServeDirs.set(dir, publicPath);\n }\n\n let warnedAboutAllMode = false;\n\n for (const registration of writeRegistrations) {\n const dir = registration.dir\n ? normalizeUploadDir(registration.dir)\n : undefined;\n\n validateWriteUrlPath(registration, baseRoute);\n\n if (!dir) continue;\n\n assertSafeUploadPath(dir, { allowParams: true, label: \"uploadDir\" });\n\n const dirParams = extractPathParams(`/${dir}`);\n\n if (dirParams.length > 0 && !registration.hasPrepare)\n throw new Error(\n `Dynamic upload directory \"${dir}\" on route \"${registration.route}\" requires a prepare function.`\n );\n\n if (\n registration.urlPath !== undefined &&\n !isExactUrlPath(registration.urlPath)\n ) {\n const warningKey = `${registration.route}:${dir}:${registration.urlPath}`;\n\n if (!warnedRoutes.has(warningKey)) {\n warnAboutUnusedUrlParams(\n dir,\n registration.urlPath,\n registration.route,\n suppressUnusedUrlParams\n );\n warnedRoutes.add(warningKey);\n }\n }\n\n if (isExactUrlPath(registration.urlPath)) {\n const exact = registration.urlPath.exact;\n\n if (seenExactWritePaths.has(exact))\n throw new Error(\n `Duplicate exact urlPath \"${exact}\" on route \"${registration.route}\"; it is already used on route \"${seenExactWritePaths.get(\n exact\n )}\".`\n );\n\n seenExactWritePaths.set(exact, registration.route);\n continue;\n }\n\n const firstDirSegment = dir.split(\"/\")[0];\n\n if (\n findFileEnabled &&\n (DEFAULT_UPLOAD_DIRS as readonly string[]).includes(firstDirSegment)\n )\n continue;\n\n if (serving === \"all\") {\n if (!warnedAboutAllMode && serveRegistrations.length > 0) {\n warningAboutAllMode();\n warnedAboutAllMode = true;\n }\n continue;\n }\n\n if (registration.serve === false) continue;\n\n const writePublicPath = normalizeUploadUrlPath(\n registration.urlPath ?? `/${dir}`\n );\n\n let bestMatch:\n | { registration: UploadServeRegistration; match: TemplateMatch }\n | undefined;\n\n for (const serveRegistration of serveRegistrations) {\n const match = matchDirTemplates(\n serveRegistration.dir,\n dir,\n serveRegistration.recursive\n );\n\n if (!match) continue;\n\n if (!bestMatch || match.matched > bestMatch.match.matched) {\n bestMatch = { registration: serveRegistration, match };\n continue;\n }\n\n if (\n match.matched === bestMatch.match.matched &&\n normalizeUploadUrlPath(serveRegistration.urlPath) !==\n normalizeUploadUrlPath(bestMatch.registration.urlPath)\n )\n throw new Error(\n `Upload directory \"${dir}\" on route \"${registration.route}\" is ambiguously served by \"${bestMatch.registration.urlPath}\" and \"${serveRegistration.urlPath}\".`\n );\n }\n\n if (!bestMatch)\n throw new Error(\n `Upload directory \"${dir}\" used by route \"${registration.route}\" is not served. Register it with arkos.serveUploadDir(\"${dir}\"), register one of its parent folders with arkos.serveUploadDir(parent, { recursive: true }), or set \"serve: false\" in the route's uploads config.`\n );\n\n const servedPublicPath = normalizeUploadUrlPath(\n `${substitutePath(bestMatch.registration.urlPath, bestMatch.match.params)}${\n bestMatch.match.remaining.length\n ? `/${bestMatch.match.remaining.join(\"/\")}`\n : \"\"\n }`\n );\n\n if (servedPublicPath !== writePublicPath)\n throw new Error(\n `Generated URL \"${writePublicPath}\" does not match served URL \"${servedPublicPath}\" for upload directory \"${dir}\".`\n );\n }\n\n if (\n serving === \"all\" &&\n serveRegistrations.length > 0 &&\n !warnedAboutAllMode\n )\n warningAboutAllMode();\n}\n\nfunction warningAboutAllMode() {\n sheu.warn(\n `fileUpload.serving is \"all\"; per-folder permissions registered via arkos.serveUploadDir() are not enforced.`,\n { timestamp: true }\n );\n}\n"]}
|