cabloy 5.1.97 → 5.1.99
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/.cabloy-version +1 -1
- package/.claude/hooks/contract-loop-gate.ts +151 -44
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +2 -0
- package/cabloy-docs/.vitepress/config.mjs +11 -0
- package/cabloy-docs/backend/controller-aop-guide.md +0 -1
- package/cabloy-docs/backend/image-guide.md +544 -0
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +1 -1
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +1 -1
- package/cabloy-docs/frontend/image-guide.md +512 -0
- package/cabloy-docs/frontend/introduction.md +2 -0
- package/cabloy-docs/frontend/ioc-and-beans.md +34 -3
- package/cabloy-docs/frontend/model-architecture.md +2 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +3 -1
- package/cabloy-docs/frontend/model-state-guide.md +5 -1
- package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +10 -8
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +2 -2
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +1 -1
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +2 -2
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +4 -4
- package/cabloy-docs/frontend/server-data.md +2 -0
- package/cabloy-docs/frontend/state-architecture-for-vue-developers.md +218 -0
- package/cabloy-docs/frontend/system-startup-guide.md +2 -0
- package/cabloy-docs/frontend/use-state-data-best-practices.md +384 -0
- package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +11 -10
- package/cabloy-docs/fullstack/image-workflow.md +403 -0
- package/cabloy-docs/fullstack/introduction.md +1 -0
- package/package.json +1 -1
- package/scripts/upgrade.ts +2 -0
- package/vona/package.original.json +0 -1
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/bean/beanBase.ts +9 -9
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +424 -47
- package/vona/src/suite/a-training/modules/training-record/src/bean/fileScene.dossierFile.ts +22 -0
- package/vona/src/suite/a-training/modules/training-record/src/bean/meta.version.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordDossierFileView.ts +47 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +13 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +13 -0
- package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +16 -5
- package/vona/src/suite/a-training/modules/training-record/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-record/src/lib/index.ts +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/lib/resolveDossierFiles.ts +34 -0
- package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +209 -123
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx +18 -1
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +0 -2
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +4 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +4 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +3 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/service/ssrHandler.ts +11 -2
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +6 -0
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- package/vona/src/suite-vendor/a-file/modules/a-file/cli/fileProvider/boilerplate/{{sceneName}}.{{beanName}}.ts_ +23 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/cli/fileScene/boilerplate/{{sceneName}}.{{beanName}}.ts_ +5 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/package.json +68 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/index.ts +425 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/locales.ts +18 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.file.ts +322 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileProvider.ts +62 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileUploadPolicy.ts +224 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.redlock.ts +11 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.version.ts +38 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/config/config.ts +16 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/controller/file.ts +175 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadRequest.ts +33 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadResponse.ts +41 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDownloadRequest.ts +12 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyRequest.ts +15 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyResponse.ts +30 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadResponse.ts +59 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadTokenRequest.ts +24 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadTokenResponse.ts +16 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadUrlRequest.ts +33 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/entity/file.ts +55 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/entity/fileProvider.ts +24 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/index.ts +4 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileProvider.ts +7 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileScene.ts +7 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileUploadValidation.ts +15 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/index.ts +3 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/model/file.ts +10 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/model/fileProvider.ts +10 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/types/file.ts +144 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileProvider.ts +111 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileScene.ts +53 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/src/types/index.ts +3 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-file/modules/a-file/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/package.json +53 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/.metadata/index.ts +104 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/bean/fileProvider.cloudflare.ts +123 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/index.ts +1 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/service/fileCloudflare.ts +245 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-file/modules/file-cloudflare/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/package.json +50 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/.metadata/index.ts +111 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/bean/fileProvider.native.ts +125 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/config/config.ts +7 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/index.ts +1 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/src/service/fileNative.ts +125 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-file/modules/file-native/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-file/package.json +14 -0
- package/vona/src/suite-vendor/a-file/tsconfig.base.json +4 -0
- package/vona/src/suite-vendor/a-file/tsconfig.json +16 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/package.json +4 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/index.ts +61 -3
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.image.ts +336 -152
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageProvider.ts +21 -14
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageUploadPolicy.ts +86 -11
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.index.ts +12 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.redlock.ts +1 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.version.ts +3 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/schedule.imageDraftPrune.ts +29 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/config/config.ts +3 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/controller/image.ts +32 -54
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadFinalizeRequest.ts +13 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadFinalizeResponse.ts +10 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadResponse.ts +10 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyRequest.ts +15 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyResponse.ts +27 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadResponse.ts +10 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageView.ts +10 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/entity/image.ts +10 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/imageUploadValidation.ts +15 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/index.ts +1 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/image.ts +18 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageProvider.ts +28 -2
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/package.json +1 -1
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/bean/imageProvider.cloudflare.ts +13 -1
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/service/imageCloudflare.ts +26 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/package.json +6 -2
- package/vona/src/suite-vendor/a-image/modules/image-native/src/.metadata/index.ts +37 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/bean/imageProvider.native.ts +21 -1
- package/vona/src/suite-vendor/a-image/modules/image-native/src/controller/image.ts +57 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/service/imageNative.ts +142 -34
- package/vona/src/suite-vendor/a-image/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/types/entity.ts +2 -4
- package/vona/src/suite-vendor/a-vona/modules/a-ormutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormutils/src/lib/columns.ts +7 -3
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/.metadata/index.ts +24 -9
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +87 -73
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionActionByRoles.ts +27 -0
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permissionUser.ts +20 -0
- package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-startup/src/service/startup.ts +4 -3
- package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-upload/src/bean/interceptor.upload.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/.metadata/index.ts +0 -13
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/lib/passport.ts +0 -7
- package/vona/src/suite-vendor/a-vona/modules/a-version/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-version/src/bean/meta.version.ts +2 -24
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +1 -1
- package/zova/packages-zova/zova-core/src/bean/beanBase.ts +9 -13
- package/zova/pnpm-lock.yaml +418 -411
- package/zova/src/suite/a-demo/modules/demo-basic/src/page/toolOne/controller.tsx +2 -2
- package/zova/src/suite/a-demo/modules/demo-todo/src/page/todo/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +2 -2
- package/zova/src/suite/a-home/modules/home-login/src/page/login/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx +5 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockTable/controller.tsx +20 -15
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/service/detail.tsx +6 -1
- package/zova/src/suite/cabloy-basic/modules/basic-file/cli/openapi.config.ts +9 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/package.json +58 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/component/formFieldFile.ts +31 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/index.ts +222 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/this.ts +2 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/file.ts +121 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/schemas.ts +306 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/types.ts +5718 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/apiSchema/file.ts +40 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/bean/tableCell.file.tsx +187 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/component/formFieldFile/controller.tsx +534 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/en-us.ts +15 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/config/locale/zh-cn.ts +15 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/index.ts +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/file.ts +74 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/model/file.ts +23 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/file.ts +12 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/src/types/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.build.json +13 -0
- package/zova/src/suite/cabloy-basic/modules/basic-file/tsconfig.json +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/index.ts +61 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/image.ts +38 -1
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/imageNativeImage.ts +31 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/schemas.ts +52 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/types.ts +614 -1
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/image.ts +10 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/imageNativeImage.ts +13 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/component/formFieldImage/controller.tsx +126 -62
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/model/image.ts +23 -0
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +44 -4
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +17 -12
- package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-resource/src/component/formFieldResourcePicker/controller.tsx +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/controller.tsx +7 -2
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +34 -33
- package/zova/src/suite/cabloy-basic/package.json +1 -0
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +5 -3
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/entry/controller.tsx +2 -2
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsx +2 -2
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/utils.ts +17 -17
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +8 -3
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/summerCache.permission.ts +0 -17
- package/vona/src/suite-vendor/a-vona/modules/a-user/src/bean/guard.userName.ts +0 -35
|
@@ -39,6 +39,8 @@ export type IImageNamedVariants = Partial<Record<TypeImageVariantName, IImageTra
|
|
|
39
39
|
|
|
40
40
|
export type TypeImageDeliveryExpiry = Date | string | number;
|
|
41
41
|
|
|
42
|
+
export type TypeImageStatus = 'draft' | 'ready' | 'expired';
|
|
43
|
+
|
|
42
44
|
export interface IImageDeliveryOptions {
|
|
43
45
|
signed?: boolean;
|
|
44
46
|
expiresIn?: number;
|
|
@@ -142,6 +144,9 @@ export interface IImageResource<
|
|
|
142
144
|
provider: keyof IImageProviderRecord;
|
|
143
145
|
clientName: string;
|
|
144
146
|
imageScene?: keyof IImageSceneRecord | string;
|
|
147
|
+
status?: TypeImageStatus;
|
|
148
|
+
draftExpiresAt?: Date;
|
|
149
|
+
finalizedAt?: Date;
|
|
145
150
|
uploadedAt?: Date;
|
|
146
151
|
}
|
|
147
152
|
|
|
@@ -153,6 +158,11 @@ export interface IImageDirectUploadResult<
|
|
|
153
158
|
draft?: boolean;
|
|
154
159
|
}
|
|
155
160
|
|
|
161
|
+
export interface IImageFinalizeDirectUploadResult<
|
|
162
|
+
TMeta extends TypeImageMeta = TypeImageMeta,
|
|
163
|
+
TRaw = unknown,
|
|
164
|
+
> extends IImageResource<TMeta, TRaw> {}
|
|
165
|
+
|
|
156
166
|
export interface IImageView {
|
|
157
167
|
id: TableIdentity;
|
|
158
168
|
url: string;
|
|
@@ -162,6 +172,9 @@ export interface IImageView {
|
|
|
162
172
|
provider: keyof IImageProviderRecord;
|
|
163
173
|
clientName: string;
|
|
164
174
|
imageScene?: keyof IImageSceneRecord | string;
|
|
175
|
+
status?: TypeImageStatus;
|
|
176
|
+
draftExpiresAt?: Date;
|
|
177
|
+
finalizedAt?: Date;
|
|
165
178
|
uploadedAt?: Date;
|
|
166
179
|
variants?: IImageNamedVariants;
|
|
167
180
|
signed?: boolean;
|
|
@@ -194,6 +207,11 @@ export interface IImageUploadTokenPayload<
|
|
|
194
207
|
kind: 'imageUpload';
|
|
195
208
|
}
|
|
196
209
|
|
|
210
|
+
export interface IImageDirectUploadTokenPayload {
|
|
211
|
+
kind: 'imageDirectUpload';
|
|
212
|
+
resourceId: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
197
215
|
export interface IImageDeliveryTokenPayload {
|
|
198
216
|
kind: 'imageDelivery';
|
|
199
217
|
imageId: TableIdentity;
|
|
@@ -37,16 +37,37 @@ export type TypeImageProviderClientOptions<T> =
|
|
|
37
37
|
T extends IDecoratorImageProviderOptions<any, infer O> ? O : never;
|
|
38
38
|
|
|
39
39
|
export type TypeImageProviderClientName<T> =
|
|
40
|
-
T extends IDecoratorImageProviderOptions<infer R, any> ? keyof R : never;
|
|
40
|
+
T extends IDecoratorImageProviderOptions<infer R, any> ? keyof R & string : never;
|
|
41
41
|
|
|
42
42
|
export interface IDecoratorImageProviderOptions<
|
|
43
43
|
R extends IImageProviderClientRecord = IImageProviderClientRecord,
|
|
44
44
|
T extends IImageProviderClientOptions = IImageProviderClientOptions,
|
|
45
45
|
> extends TypeOnionOptionsEnableSimple {
|
|
46
46
|
base?: T;
|
|
47
|
-
clients?: { [K in keyof R]?: T };
|
|
47
|
+
clients?: { [K in keyof R]?: R[K] extends undefined ? T : R[K] };
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
export type TypeImageProviderOptionsByName<N extends keyof IImageProviderRecord> =
|
|
51
|
+
IImageProviderRecord[N];
|
|
52
|
+
|
|
53
|
+
export type TypeImageProviderClientOptionsByName<N extends keyof IImageProviderRecord> =
|
|
54
|
+
TypeImageProviderOptionsByName<N> extends IDecoratorImageProviderOptions<any, any>
|
|
55
|
+
? TypeImageProviderClientOptions<TypeImageProviderOptionsByName<N>>
|
|
56
|
+
: never;
|
|
57
|
+
|
|
58
|
+
export type TypeImageProviderClientNameByName<N extends keyof IImageProviderRecord> =
|
|
59
|
+
TypeImageProviderOptionsByName<N> extends IDecoratorImageProviderOptions<any, any>
|
|
60
|
+
? TypeImageProviderClientName<TypeImageProviderOptionsByName<N>>
|
|
61
|
+
: never;
|
|
62
|
+
|
|
63
|
+
export type TypeImageProviderExecuteByName<N extends keyof IImageProviderRecord> =
|
|
64
|
+
TypeImageProviderOptionsByName<N> extends IDecoratorImageProviderOptions<any, any>
|
|
65
|
+
? IImageProviderExecute<
|
|
66
|
+
TypeImageProviderClientOptionsByName<N>,
|
|
67
|
+
TypeImageProviderOptionsByName<N>
|
|
68
|
+
>
|
|
69
|
+
: never;
|
|
70
|
+
|
|
50
71
|
// Provider-internal resolved variant names include both declaration-merged named variants
|
|
51
72
|
// and the internal `custom` sentinel used for ad hoc transform requests.
|
|
52
73
|
export type TypeImageProviderResolvedVariantName = TypeImageVariantName | 'custom';
|
|
@@ -71,6 +92,11 @@ export interface IImageProviderExecute<
|
|
|
71
92
|
clientOptions: T,
|
|
72
93
|
options: O,
|
|
73
94
|
): Promise<IImageProviderDirectUploadResource>;
|
|
95
|
+
finalizeDirectUpload?(
|
|
96
|
+
image: EntityImage,
|
|
97
|
+
clientOptions: T,
|
|
98
|
+
options: O,
|
|
99
|
+
): Promise<IImageProviderResource | undefined>;
|
|
74
100
|
get(
|
|
75
101
|
image: EntityImage,
|
|
76
102
|
clientOptions: T,
|
package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/bean/imageProvider.cloudflare.ts
CHANGED
|
@@ -43,7 +43,11 @@ export interface IImageProviderOptionsCloudflare extends IDecoratorImageProvider
|
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
45
|
})
|
|
46
|
-
export class ImageProviderCloudflare
|
|
46
|
+
export class ImageProviderCloudflare
|
|
47
|
+
extends BeanBase
|
|
48
|
+
implements
|
|
49
|
+
IImageProviderExecute<IImageProviderCloudflareClientOptions, IImageProviderOptionsCloudflare>
|
|
50
|
+
{
|
|
47
51
|
async upload(
|
|
48
52
|
input: IImageUploadInput,
|
|
49
53
|
clientOptions: IImageProviderCloudflareClientOptions,
|
|
@@ -68,6 +72,14 @@ export class ImageProviderCloudflare extends BeanBase implements IImageProviderE
|
|
|
68
72
|
return await this.scope.service.imageCloudflare.createDirectUpload(input, clientOptions);
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
async finalizeDirectUpload(
|
|
76
|
+
image: EntityImage,
|
|
77
|
+
clientOptions: IImageProviderCloudflareClientOptions,
|
|
78
|
+
_options: IImageProviderOptionsCloudflare,
|
|
79
|
+
) {
|
|
80
|
+
return await this.scope.service.imageCloudflare.finalizeDirectUpload(image, clientOptions);
|
|
81
|
+
}
|
|
82
|
+
|
|
71
83
|
async get(
|
|
72
84
|
image: EntityImage,
|
|
73
85
|
clientOptions: IImageProviderCloudflareClientOptions,
|
package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/service/imageCloudflare.ts
CHANGED
|
@@ -38,6 +38,12 @@ interface ICloudflareImageResult {
|
|
|
38
38
|
draft?: boolean;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
interface ICloudflareImageDetailsResult extends ICloudflareImageResult {
|
|
42
|
+
meta?: {
|
|
43
|
+
filename?: string;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
interface ICloudflareClientOptionsNormalized extends IImageProviderCloudflareClientOptions {
|
|
42
48
|
accountId: string;
|
|
43
49
|
apiToken: string;
|
|
@@ -130,6 +136,26 @@ export class ServiceImageCloudflare extends BeanBase {
|
|
|
130
136
|
};
|
|
131
137
|
}
|
|
132
138
|
|
|
139
|
+
async finalizeDirectUpload(
|
|
140
|
+
image: Pick<EntityImage, 'resourceId' | 'filename' | 'meta' | 'requireSignedURLs'>,
|
|
141
|
+
options: IImageProviderCloudflareClientOptions,
|
|
142
|
+
): Promise<IImageProviderResource | undefined> {
|
|
143
|
+
const normalized = this._normalizeClientOptions(options);
|
|
144
|
+
const result = await this._request<ICloudflareImageDetailsResult>(
|
|
145
|
+
normalized,
|
|
146
|
+
`/images/v1/${encodeURIComponent(image.resourceId)}`,
|
|
147
|
+
{
|
|
148
|
+
method: 'GET',
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
if (result.draft) return undefined;
|
|
152
|
+
return this._mapImageResource(result, normalized, {
|
|
153
|
+
filename: result.filename ?? result.meta?.filename ?? image.filename,
|
|
154
|
+
meta: image.meta,
|
|
155
|
+
requireSignedURLs: image.requireSignedURLs,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
async remove(
|
|
134
160
|
image: Pick<EntityImage, 'resourceId'>,
|
|
135
161
|
options: IImageProviderCloudflareClientOptions,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-module-image-native",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Vona Module"
|
|
@@ -46,7 +46,11 @@
|
|
|
46
46
|
"title": "image-native",
|
|
47
47
|
"vonaModule": {
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"a-
|
|
49
|
+
"a-core": "5.0.0",
|
|
50
|
+
"a-image": "5.0.0",
|
|
51
|
+
"a-upload": "5.0.0",
|
|
52
|
+
"a-user": "5.0.0",
|
|
53
|
+
"a-web": "5.0.0"
|
|
50
54
|
},
|
|
51
55
|
"globalDependencies": {
|
|
52
56
|
"sharp": true
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// eslint-disable
|
|
2
|
+
import type { TypeControllerOptionsActions } from 'vona-module-a-openapi';
|
|
2
3
|
/** service: begin */
|
|
3
4
|
export * from '../service/imageNative.ts';
|
|
4
5
|
|
|
@@ -72,6 +73,42 @@ export interface IModuleImageProvider {
|
|
|
72
73
|
'native': ImageProviderNative;
|
|
73
74
|
}
|
|
74
75
|
/** imageProvider: end */
|
|
76
|
+
/** controller: begin */
|
|
77
|
+
export * from '../controller/image.ts';
|
|
78
|
+
import type { IControllerOptionsImage } from '../controller/image.ts';
|
|
79
|
+
import 'vona-module-a-web';
|
|
80
|
+
declare module 'vona-module-a-web' {
|
|
81
|
+
export interface IControllerRecord {
|
|
82
|
+
'image-native:image': IControllerOptionsImage;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
declare module 'vona-module-image-native' {
|
|
86
|
+
export interface ControllerImage {
|
|
87
|
+
/** @internal */
|
|
88
|
+
get scope(): ScopeModuleImageNative;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ControllerImage {
|
|
92
|
+
get $beanFullName(): 'image-native.controller.image';
|
|
93
|
+
get $onionName(): 'image-native:image';
|
|
94
|
+
get $onionOptions(): IControllerOptionsImage;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** controller: end */
|
|
98
|
+
/** controller: begin */
|
|
99
|
+
// @ts-ignore ignore
|
|
100
|
+
import type { ControllerImage } from '../controller/image.ts';
|
|
101
|
+
declare module 'vona-module-image-native' {
|
|
102
|
+
export interface IControllerOptionsImage {
|
|
103
|
+
actions?: TypeControllerOptionsActions<ControllerImage>;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
declare module 'vona-module-a-web' {
|
|
107
|
+
export interface IApiPathPostRecord {
|
|
108
|
+
'/image-native/direct-upload/:resourceId': undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** controller: end */
|
|
75
112
|
/** config: begin */
|
|
76
113
|
export * from '../config/config.ts';
|
|
77
114
|
import type { config } from '../config/config.ts';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
IDecoratorImageProviderOptions,
|
|
3
3
|
IImageDeliveryOptions,
|
|
4
|
+
IImageDirectUploadInput,
|
|
4
5
|
IImageDownloadResult,
|
|
5
6
|
IImageProviderClientOptions,
|
|
6
7
|
IImageProviderClientRecord,
|
|
@@ -34,7 +35,10 @@ export interface IImageProviderOptionsNative extends IDecoratorImageProviderOpti
|
|
|
34
35
|
signedDeliveryKind: 'proxy',
|
|
35
36
|
},
|
|
36
37
|
})
|
|
37
|
-
export class ImageProviderNative
|
|
38
|
+
export class ImageProviderNative
|
|
39
|
+
extends BeanBase
|
|
40
|
+
implements IImageProviderExecute<IImageProviderNativeClientOptions, IImageProviderOptionsNative>
|
|
41
|
+
{
|
|
38
42
|
async upload(
|
|
39
43
|
input: IImageUploadInput,
|
|
40
44
|
clientOptions: IImageProviderNativeClientOptions,
|
|
@@ -49,6 +53,22 @@ export class ImageProviderNative extends BeanBase implements IImageProviderExecu
|
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
async createDirectUpload(
|
|
57
|
+
input: IImageDirectUploadInput,
|
|
58
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
59
|
+
_options: IImageProviderOptionsNative,
|
|
60
|
+
) {
|
|
61
|
+
return await this.scope.service.imageNative.createDirectUpload(input, clientOptions);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async finalizeDirectUpload(
|
|
65
|
+
image: EntityImage,
|
|
66
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
67
|
+
_options: IImageProviderOptionsNative,
|
|
68
|
+
) {
|
|
69
|
+
return await this.scope.service.imageNative.finalizeDirectUpload(image, clientOptions);
|
|
70
|
+
}
|
|
71
|
+
|
|
52
72
|
async get(
|
|
53
73
|
image: EntityImage,
|
|
54
74
|
clientOptions: IImageProviderNativeClientOptions,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { IUploadFile } from 'vona-module-a-upload';
|
|
2
|
+
import type { IDecoratorControllerOptions } from 'vona-module-a-web';
|
|
3
|
+
|
|
4
|
+
import fse from 'fs-extra';
|
|
5
|
+
import { BeanBase } from 'vona';
|
|
6
|
+
import { Core } from 'vona-module-a-core';
|
|
7
|
+
import { Passport } from 'vona-module-a-user';
|
|
8
|
+
import { Arg, Controller, Web } from 'vona-module-a-web';
|
|
9
|
+
|
|
10
|
+
export interface IControllerOptionsImage extends IDecoratorControllerOptions {}
|
|
11
|
+
|
|
12
|
+
@Controller<IControllerOptionsImage>({ path: 'image-native' })
|
|
13
|
+
export class ControllerImage extends BeanBase {
|
|
14
|
+
@Web.post('direct-upload/:resourceId')
|
|
15
|
+
@Passport.public()
|
|
16
|
+
@Core.fileUpload()
|
|
17
|
+
async directUpload(
|
|
18
|
+
@Arg.param('resourceId') resourceId: string,
|
|
19
|
+
@Arg.query('token') token: string,
|
|
20
|
+
@Arg.file('image') file: IUploadFile,
|
|
21
|
+
) {
|
|
22
|
+
const payload = await this.bean.imageUploadPolicy.verifyDirectUploadToken(
|
|
23
|
+
token,
|
|
24
|
+
this.ctx.route.routePathRaw,
|
|
25
|
+
);
|
|
26
|
+
if (payload.resourceId !== resourceId) {
|
|
27
|
+
return this.app.throw(401);
|
|
28
|
+
}
|
|
29
|
+
const modelImage = this.app.bean._getBean<any>('a-image.model.image' as never);
|
|
30
|
+
const image = await modelImage.get({
|
|
31
|
+
providerName: 'image-native:native',
|
|
32
|
+
resourceId,
|
|
33
|
+
});
|
|
34
|
+
if (!image || image.status !== 'draft') {
|
|
35
|
+
return this.app.throw(403, `image is not draft: ${resourceId}`);
|
|
36
|
+
}
|
|
37
|
+
if (!image.imageScene) {
|
|
38
|
+
throw new Error(`image scene missing: ${resourceId}`);
|
|
39
|
+
}
|
|
40
|
+
const stat = await fse.stat(file.file);
|
|
41
|
+
const policy = await this.bean.imageUploadPolicy.resolveUploadPolicy({
|
|
42
|
+
imageScene: image.imageScene as never,
|
|
43
|
+
size: Number(stat.size),
|
|
44
|
+
mimeType: file.info.mimeType,
|
|
45
|
+
});
|
|
46
|
+
await this.bean.imageUploadPolicy.validateUploadFile(
|
|
47
|
+
{
|
|
48
|
+
file: file.file,
|
|
49
|
+
filename: file.info.filename,
|
|
50
|
+
mimeType: file.info.mimeType,
|
|
51
|
+
},
|
|
52
|
+
policy,
|
|
53
|
+
);
|
|
54
|
+
await this.scope.service.imageNative.uploadDirectFile(image, file);
|
|
55
|
+
return { ok: true };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -2,13 +2,15 @@ import type { SharpConstructor } from 'sharp';
|
|
|
2
2
|
import type {
|
|
3
3
|
EntityImage,
|
|
4
4
|
IImageDeliveryOptions,
|
|
5
|
-
|
|
5
|
+
IImageDirectUploadInput,
|
|
6
|
+
IImageProviderDirectUploadResource,
|
|
6
7
|
IImageProviderResolvedVariant,
|
|
7
8
|
IImageProviderResource,
|
|
8
9
|
IImageTransformOptions,
|
|
9
10
|
IImageUploadInput,
|
|
10
11
|
IImageVariantRequest,
|
|
11
12
|
} from 'vona-module-a-image';
|
|
13
|
+
import type { IUploadFile } from 'vona-module-a-upload';
|
|
12
14
|
|
|
13
15
|
import fse from 'fs-extra';
|
|
14
16
|
import { createHash } from 'node:crypto';
|
|
@@ -24,6 +26,20 @@ type IImageNativeStoredImage = Pick<
|
|
|
24
26
|
'resourceId' | 'filename' | 'storagePath' | 'variants'
|
|
25
27
|
>;
|
|
26
28
|
|
|
29
|
+
type IImageNativeDraftImage = Pick<
|
|
30
|
+
EntityImage,
|
|
31
|
+
| 'resourceId'
|
|
32
|
+
| 'filename'
|
|
33
|
+
| 'contentType'
|
|
34
|
+
| 'meta'
|
|
35
|
+
| 'imageScene'
|
|
36
|
+
| 'requireSignedURLs'
|
|
37
|
+
| 'storagePath'
|
|
38
|
+
| 'deliveryBaseUrl'
|
|
39
|
+
| 'variants'
|
|
40
|
+
| 'clientName'
|
|
41
|
+
>;
|
|
42
|
+
|
|
27
43
|
@Service()
|
|
28
44
|
export class ServiceImageNative extends BeanBase {
|
|
29
45
|
private _sharpInstance: SharpConstructor;
|
|
@@ -39,39 +55,90 @@ export class ServiceImageNative extends BeanBase {
|
|
|
39
55
|
input: IImageUploadInput,
|
|
40
56
|
options: IImageProviderNativeClientOptions,
|
|
41
57
|
): Promise<IImageProviderResource> {
|
|
42
|
-
const publicPath = await this.app.util.getPublicPathPhysical(
|
|
43
|
-
path.join('image-native', options.subdir ?? 'default'),
|
|
44
|
-
true,
|
|
45
|
-
);
|
|
46
58
|
const resourceId = uuidv4();
|
|
47
|
-
const
|
|
48
|
-
const targetName = `${resourceId}${ext}`;
|
|
49
|
-
const targetPath = path.join(publicPath, targetName);
|
|
59
|
+
const targetPath = await this._getFinalPath(resourceId, input.filename, options, input.file);
|
|
50
60
|
await fse.copy(input.file, targetPath);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
options,
|
|
61
|
+
return await this._buildStoredResource(targetPath, {
|
|
62
|
+
resourceId,
|
|
63
|
+
filename: input.filename,
|
|
64
|
+
contentType: input.contentType,
|
|
65
|
+
meta: input.meta,
|
|
66
|
+
requireSignedURLs: input.requireSignedURLs ?? options.requireSignedURLs,
|
|
67
|
+
variants: options.variants ?? this.scope.config.imageNative.variants,
|
|
68
|
+
deliveryBaseUrl: options.deliveryBaseUrl,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async createDirectUpload(
|
|
73
|
+
input: IImageDirectUploadInput,
|
|
74
|
+
options: IImageProviderNativeClientOptions,
|
|
75
|
+
): Promise<IImageProviderDirectUploadResource> {
|
|
76
|
+
const resourceId = this._sanitizeResourceId(input.customId) ?? uuidv4();
|
|
77
|
+
const storagePath = await this._getFinalPath(resourceId, input.filename, options);
|
|
78
|
+
const routePath = this.scope.util.combineApiPath(
|
|
79
|
+
`image-native/direct-upload/${encodeURIComponent(resourceId)}`,
|
|
80
|
+
false,
|
|
81
|
+
true,
|
|
58
82
|
);
|
|
83
|
+
const tokenPath = this.scope.util.combineApiPath(
|
|
84
|
+
'image-native/direct-upload/:resourceId',
|
|
85
|
+
false,
|
|
86
|
+
true,
|
|
87
|
+
);
|
|
88
|
+
const tokenPayload = await this.bean.imageUploadPolicy.createDirectUploadToken({
|
|
89
|
+
resourceId,
|
|
90
|
+
path: tokenPath,
|
|
91
|
+
});
|
|
92
|
+
const uploadUrl = new URL(this.app.util.getAbsoluteUrlByApiPath(routePath));
|
|
93
|
+
uploadUrl.searchParams.set('token', tokenPayload.token);
|
|
59
94
|
return {
|
|
60
95
|
resourceId,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
storagePath: targetPath,
|
|
65
|
-
deliveryBaseUrl: options.deliveryBaseUrl,
|
|
96
|
+
filename: input.filename,
|
|
97
|
+
contentType: input.contentType,
|
|
98
|
+
meta: input.meta,
|
|
66
99
|
requireSignedURLs: input.requireSignedURLs ?? options.requireSignedURLs,
|
|
67
|
-
variants,
|
|
100
|
+
variants: options.variants ?? this.scope.config.imageNative.variants,
|
|
101
|
+
deliveryBaseUrl: options.deliveryBaseUrl,
|
|
102
|
+
storagePath,
|
|
103
|
+
uploadUrl: uploadUrl.toString(),
|
|
104
|
+
draft: true,
|
|
68
105
|
};
|
|
69
106
|
}
|
|
70
107
|
|
|
108
|
+
async uploadDirectFile(image: IImageNativeDraftImage, file: IUploadFile) {
|
|
109
|
+
const draftPath = this._getDraftPath(image.storagePath, image.resourceId);
|
|
110
|
+
await fse.ensureDir(path.dirname(draftPath));
|
|
111
|
+
await fse.move(file.file, draftPath, { overwrite: true });
|
|
112
|
+
return draftPath;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async finalizeDirectUpload(
|
|
116
|
+
image: IImageNativeDraftImage,
|
|
117
|
+
options: IImageProviderNativeClientOptions,
|
|
118
|
+
): Promise<IImageProviderResource | undefined> {
|
|
119
|
+
const storagePath =
|
|
120
|
+
image.storagePath ?? (await this._getFinalPath(image.resourceId, image.filename, options));
|
|
121
|
+
const draftPath = this._getDraftPath(storagePath, image.resourceId);
|
|
122
|
+
if (!(await fse.pathExists(draftPath))) return undefined;
|
|
123
|
+
await fse.ensureDir(path.dirname(storagePath));
|
|
124
|
+
await fse.move(draftPath, storagePath, { overwrite: true });
|
|
125
|
+
return await this._buildStoredResource(storagePath, {
|
|
126
|
+
resourceId: image.resourceId,
|
|
127
|
+
filename: image.filename,
|
|
128
|
+
contentType: image.contentType,
|
|
129
|
+
meta: image.meta,
|
|
130
|
+
requireSignedURLs: image.requireSignedURLs ?? options.requireSignedURLs,
|
|
131
|
+
variants: image.variants ?? options.variants ?? this.scope.config.imageNative.variants,
|
|
132
|
+
deliveryBaseUrl: image.deliveryBaseUrl ?? options.deliveryBaseUrl,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
71
136
|
async remove(image: IImageNativeStoredImage) {
|
|
72
137
|
if (!image.storagePath) return;
|
|
73
138
|
const dir = path.dirname(image.storagePath);
|
|
74
139
|
if (!(await fse.pathExists(dir))) return;
|
|
140
|
+
const draftPath = this._getDraftPath(image.storagePath, image.resourceId);
|
|
141
|
+
await fse.remove(draftPath);
|
|
75
142
|
const entries = await fse.readdir(dir);
|
|
76
143
|
await Promise.all(
|
|
77
144
|
entries
|
|
@@ -100,22 +167,57 @@ export class ServiceImageNative extends BeanBase {
|
|
|
100
167
|
return await this._buildUrl(targetPath, options.deliveryBaseUrl);
|
|
101
168
|
}
|
|
102
169
|
|
|
103
|
-
private async
|
|
104
|
-
|
|
170
|
+
private async _buildStoredResource(
|
|
171
|
+
targetPath: string,
|
|
172
|
+
data: {
|
|
173
|
+
resourceId: string;
|
|
174
|
+
filename?: string;
|
|
175
|
+
contentType?: string;
|
|
176
|
+
meta?: Record<string, unknown>;
|
|
177
|
+
requireSignedURLs?: boolean;
|
|
178
|
+
variants?: EntityImage['variants'];
|
|
179
|
+
deliveryBaseUrl?: string;
|
|
180
|
+
},
|
|
181
|
+
): Promise<IImageProviderResource> {
|
|
182
|
+
const sharp = await this.getSharp();
|
|
183
|
+
const metadata = await sharp(targetPath).metadata();
|
|
184
|
+
const stat = await fse.stat(targetPath);
|
|
185
|
+
return {
|
|
186
|
+
resourceId: data.resourceId,
|
|
187
|
+
filename: data.filename,
|
|
188
|
+
contentType: data.contentType,
|
|
189
|
+
size: Number(stat.size),
|
|
190
|
+
width: metadata.width,
|
|
191
|
+
height: metadata.height,
|
|
192
|
+
requireSignedURLs: data.requireSignedURLs,
|
|
193
|
+
variants: data.variants,
|
|
194
|
+
meta: data.meta,
|
|
195
|
+
storagePath: targetPath,
|
|
196
|
+
deliveryBaseUrl: data.deliveryBaseUrl,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async _getFinalPath(
|
|
201
|
+
resourceId: string,
|
|
202
|
+
filename: string | undefined,
|
|
105
203
|
options: IImageProviderNativeClientOptions,
|
|
204
|
+
filePath?: string,
|
|
106
205
|
) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
206
|
+
const publicPath = await this.app.util.getPublicPathPhysical(
|
|
207
|
+
path.join('image-native', options.subdir ?? 'default'),
|
|
208
|
+
true,
|
|
209
|
+
);
|
|
210
|
+
const ext = this._getOriginalExt(filename, filePath ?? resourceId);
|
|
211
|
+
return path.join(publicPath, `${resourceId}${ext}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _getDraftPath(storagePath: string | undefined, resourceId: string) {
|
|
215
|
+
if (!storagePath) {
|
|
216
|
+
throw new Error(`Image storage path missing: ${resourceId}`);
|
|
116
217
|
}
|
|
117
|
-
|
|
118
|
-
|
|
218
|
+
const dir = path.dirname(storagePath);
|
|
219
|
+
const ext = path.extname(storagePath) || '.bin';
|
|
220
|
+
return path.join(dir, `${resourceId}__draft${ext}`);
|
|
119
221
|
}
|
|
120
222
|
|
|
121
223
|
private async _ensureVariantFile(
|
|
@@ -266,6 +368,12 @@ export class ServiceImageNative extends BeanBase {
|
|
|
266
368
|
return JSON.stringify(value);
|
|
267
369
|
}
|
|
268
370
|
|
|
371
|
+
private _sanitizeResourceId(resourceId: string | undefined) {
|
|
372
|
+
if (!resourceId) return undefined;
|
|
373
|
+
const sanitized = resourceId.replace(/[^\w.-]/g, '-');
|
|
374
|
+
return sanitized || undefined;
|
|
375
|
+
}
|
|
376
|
+
|
|
269
377
|
private _sanitizeVariantName(variantName: string) {
|
|
270
378
|
return variantName.replace(/[^\w.-]/g, '-');
|
|
271
379
|
}
|
|
@@ -11,7 +11,5 @@ export type TypeEntityMeta<T, N = string> = Required<{
|
|
|
11
11
|
export const SymbolKeyFieldsMore = Symbol('$fieldsMore');
|
|
12
12
|
export type TypeSymbolKeyFieldsMore = typeof SymbolKeyFieldsMore;
|
|
13
13
|
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
16
|
-
keyof TypeEntityStudentMetaSimple<T>
|
|
17
|
-
>;
|
|
14
|
+
export type TypeEntityMetaFields<T> = Omit<T, '$table' | '$comment' | '$default'>;
|
|
15
|
+
export type TypeEntityMetaFieldKeys<T> = PickString<keyof TypeEntityMetaFields<T>>;
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
IDecoratorEntityOptions,
|
|
5
5
|
ITableRecord,
|
|
6
6
|
TypeEntityMeta,
|
|
7
|
-
|
|
7
|
+
TypeEntityMetaFieldKeys,
|
|
8
8
|
} from 'vona-module-a-orm';
|
|
9
9
|
|
|
10
10
|
import { isClass } from '@cabloy/utils';
|
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
getTargetDecoratorRules,
|
|
16
16
|
} from 'vona-module-a-openapiutils';
|
|
17
17
|
|
|
18
|
+
export type TypeEntityMetaCompositeFieldKeys<T> =
|
|
19
|
+
`${TypeEntityMetaFieldKeys<T>}+${TypeEntityMetaFieldKeys<T>}`;
|
|
20
|
+
|
|
18
21
|
export function $column<T>(key: keyof T): keyof T {
|
|
19
22
|
return key;
|
|
20
23
|
}
|
|
@@ -53,8 +56,9 @@ export function $columnsAll<T, TableName extends boolean, Meta extends boolean>(
|
|
|
53
56
|
export function $tableColumns<K extends keyof ITableRecord>(
|
|
54
57
|
tableName: K,
|
|
55
58
|
key?:
|
|
56
|
-
|
|
|
57
|
-
|
|
|
59
|
+
| TypeEntityMetaFieldKeys<ITableRecord[K]>
|
|
60
|
+
| TypeEntityMetaCompositeFieldKeys<ITableRecord[K]>
|
|
61
|
+
| TypeEntityMetaFieldKeys<ITableRecord[K]>[]
|
|
58
62
|
| undefined,
|
|
59
63
|
) {
|
|
60
64
|
return { [tableName]: key };
|