cabloy 5.1.95 → 5.1.97
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 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +4 -1
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +6 -3
- package/.github/workflows/vona-test-crud.yml +2 -0
- package/.github/workflows/vona-test-mysql.yml +2 -0
- package/.github/workflows/vona-test-pg.yml +2 -0
- package/.github/workflows/vona-test-sqlite3.yml +2 -0
- package/CHANGELOG.md +38 -0
- package/CLAUDE.md +1 -0
- package/cabloy-docs/ai/playbook-backend-module.md +6 -3
- package/cabloy-docs/fullstack/framework-performance.md +3 -3
- package/cabloy-docs/fullstack/quickstart.md +1 -1
- package/package.json +1 -1
- package/scripts/release.ts +27 -1
- package/vona/docker-compose-original/docker-compose-dockerfile-app +4 -0
- package/vona/docker-compose-original/docker-compose.original.yml +0 -1
- package/vona/env/.env +0 -1
- package/vona/env/.env.prod +0 -1
- package/vona/env/.env.prod.docker +0 -7
- package/vona/package.original.json +3 -3
- package/vona/packages-cli/cabloy-cli/package.json +2 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +2 -2
- package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.build.ts +70 -2
- package/vona/packages-utils/babel-plugin-vona-bean-module/package.json +2 -2
- package/vona/packages-utils/module-glob/package.json +2 -2
- package/vona/packages-utils/module-info-pro/package.json +2 -2
- package/vona/packages-utils/utils/package.json +2 -2
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +2 -2
- package/vona/packages-vona/vona-core/src/lib/addon/addon.ts +77 -0
- package/vona/packages-vona/vona-core/src/lib/addon/index.ts +3 -0
- package/vona/packages-vona/vona-core/src/lib/addon/sharp.ts +46 -0
- package/vona/packages-vona/vona-core/src/lib/addon/sqlite3.ts +23 -0
- package/vona/packages-vona/vona-core/src/lib/index.ts +1 -0
- package/vona/packages-vona/vona-core/src/lib/utils/index.ts +0 -1
- package/vona/packages-vona/vona-core/src/lib/utils/util.ts +5 -0
- package/vona/packages-vona/vona-mock/package.json +2 -2
- package/vona/pnpm-lock.yaml +441 -62
- package/vona/pnpm-workspace.yaml +1 -1
- package/vona/src/backend/cli.ts +2 -5
- package/vona/src/backend/config/config/config.ts +0 -4
- package/vona/src/suite/a-demo/modules/demo-basic/src/bean/ssrMenu.admin.ts +1 -1
- package/vona/src/suite/a-training/modules/training-record/src/.metadata/index.ts +26 -0
- package/vona/src/suite/a-training/modules/training-record/src/bean/imageScene.sceneImage.ts +11 -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/recordSelectResItem.tsx +12 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +12 -0
- package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +26 -1
- package/vona/src/suite/a-training/modules/training-record/src/index.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +27 -1
- package/vona/src/suite/a-training/modules/training-student/src/bean/imageScene.studentImage.ts +10 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +1 -0
- 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 +16 -2
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +1 -1
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +12 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +1 -1
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +13 -1
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +26 -1
- package/vona/src/suite/a-training/modules/training-student/src/index.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +1 -0
- package/vona/src/suite-vendor/a-auth/modules/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-auth/modules/a-auth/src/bean/bean.authProvider.ts +2 -5
- package/vona/src/suite-vendor/a-auth/package.json +1 -1
- package/vona/src/suite-vendor/a-image/modules/a-image/cli/imageProvider/boilerplate/{{sceneName}}.{{beanName}}.ts_ +23 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/cli/imageScene/boilerplate/{{sceneName}}.{{beanName}}.ts_ +5 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/package.json +68 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/index.ts +482 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/locales.ts +18 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.image.ts +443 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageProvider.ts +55 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageUploadPolicy.ts +174 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.redlock.ts +11 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.version.ts +40 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/serializerTransform.resolveView.ts +44 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/serializerTransform.resolveViews.ts +44 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/config/config.ts +17 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/controller/image.ts +165 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDeliveryRequest.ts +20 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadRequest.ts +36 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadResponse.ts +38 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageTransformOptions.tsx +42 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadResponse.ts +62 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadTokenRequest.ts +24 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadTokenResponse.ts +16 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadUrlRequest.ts +33 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageView.ts +46 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/entity/image.ts +58 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/entity/imageProvider.ts +24 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/index.ts +4 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/imageProvider.ts +9 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/imageScene.ts +7 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/imageVariant.ts +46 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/lib/index.ts +3 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/model/image.ts +10 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/model/imageProvider.ts +10 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/image.ts +208 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageProvider.ts +110 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageScene.ts +52 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/src/types/index.ts +3 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-image/modules/a-image/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/package.json +49 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/.metadata/index.ts +89 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/bean/imageProvider.cloudflare.ts +155 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/index.ts +1 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/lib/cloudflareImageUrl.ts +112 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/service/imageCloudflare.ts +273 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-image/modules/image-cloudflare/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/package.json +63 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/.metadata/index.ts +114 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/bean/imageProvider.native.ts +131 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/config/config.ts +11 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/index.ts +1 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/monkey.ts +33 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/src/service/imageNative.ts +291 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-image/modules/image-native/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-image/package.json +14 -0
- package/vona/src/suite-vendor/a-image/tsconfig.base.json +4 -0
- package/vona/src/suite-vendor/a-image/tsconfig.json +16 -0
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/service/jwtClient.ts +5 -0
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/types/jwt.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/schema/makeSchemaLikes.ts +6 -3
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/utils.ts +13 -7
- 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/database.ts +0 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +9 -1
- 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 +39 -7
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-cli/cli/package.json +3 -3
- package/zova/packages-cli/cli-set-front/package.json +9 -9
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +20 -10
- package/zova/packages-utils/babel-plugin-zova-bean-module/package.json +2 -2
- package/zova/packages-utils/babel-plugin-zova-bean-use/package.json +2 -2
- package/zova/packages-utils/babel-plugin-zova-behavior/package.json +2 -2
- package/zova/packages-utils/babel-plugin-zova-component/package.json +2 -2
- package/zova/packages-utils/zova-jsx/package.json +3 -3
- package/zova/packages-utils/zova-vite/package.json +7 -7
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +3 -3
- package/zova/pnpm-lock.yaml +126 -74
- package/zova/src/suite/a-home/modules/home-api/src/api/captcha.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/api/home.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/api/homeBaseMenu.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/api/homeBasePermission.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/api/homeUserPassport.ts +22 -20
- package/zova/src/suite/a-home/modules/home-api/src/api/openapi/schemas.ts +163 -53
- package/zova/src/suite/a-home/modules/home-api/src/api/openapi/types.ts +2060 -675
- package/zova/src/suite/a-home/modules/home-api/src/api/testSsrToolOne.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/captcha.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/home.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/homeBaseMenu.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/homeBasePermission.ts +3 -1
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/homeUserPassport.ts +13 -11
- package/zova/src/suite/a-home/modules/home-api/src/apiSchema/testSsrToolOne.ts +3 -1
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +54 -16
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +468 -8
- package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +3 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionUpdate.tsx +1 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/actionCreate/controller.tsx +1 -1
- package/zova/src/suite/cabloy-basic/modules/basic-details/src/service/detail.tsx +53 -1
- package/zova/src/suite/cabloy-basic/modules/basic-image/cli/openapi.config.ts +9 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/package.json +60 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/component/formFieldImage.ts +31 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/index.ts +191 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/this.ts +2 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/image.ts +104 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/schemas.ts +262 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/types.ts +5159 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/image.ts +35 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/bean/tableCell.image.tsx +200 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/component/formFieldImage/controller.tsx +781 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/config/locale/en-us.ts +18 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/config/locale/zh-cn.ts +18 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/index.ts +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/lib/index.ts +2 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/lib/preview.ts +105 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/lib/previewDialog.tsx +190 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/types/image.ts +5 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/src/types/index.ts +1 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/tsconfig.build.json +13 -0
- package/zova/src/suite/cabloy-basic/modules/basic-image/tsconfig.json +5 -0
- package/zova/src/suite/cabloy-basic/package.json +1 -0
- 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/types/image.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/index.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +5 -5
- package/zova/src/suite-vendor/a-zova/package.json +3 -3
- package/vona/packages-vona/vona-core/src/lib/utils/sqlite3.ts +0 -50
- /package/vona/patches/{zova-core@5.1.75.patch → zova-core@5.1.76.patch} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vona-module-image-native",
|
|
3
|
+
"version": "5.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Vona Module"
|
|
7
|
+
],
|
|
8
|
+
"author": "",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": [
|
|
17
|
+
"./src/index.ts",
|
|
18
|
+
"./dist/index.d.ts"
|
|
19
|
+
],
|
|
20
|
+
"import": "./src/index.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"clean": "rimraf dist tsconfig.build.tsbuildinfo",
|
|
27
|
+
"tsc:publish": "npm run clean && node ../../../../../packages-cli/cli/src/bin/vona.ts :bin:buildModule --sourcemap && tsc -p tsconfig.build.json",
|
|
28
|
+
"prepublishOnly": "npm run tsc:publish",
|
|
29
|
+
"prepack": "clean-package",
|
|
30
|
+
"postpack": "clean-package restore"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"sharp": "^0.35.2"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"clean-package": "^2.2.0",
|
|
37
|
+
"rimraf": "^6.1.3"
|
|
38
|
+
},
|
|
39
|
+
"clean-package": {
|
|
40
|
+
"indent": 2,
|
|
41
|
+
"remove": [
|
|
42
|
+
"clean-package",
|
|
43
|
+
"exports.\\..import"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"title": "image-native",
|
|
47
|
+
"vonaModule": {
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"a-image": "5.0.0"
|
|
50
|
+
},
|
|
51
|
+
"globalDependencies": {
|
|
52
|
+
"sharp": true
|
|
53
|
+
},
|
|
54
|
+
"bundle": {
|
|
55
|
+
"externals": [
|
|
56
|
+
"sharp"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"capabilities": {
|
|
60
|
+
"monkey": true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// eslint-disable
|
|
2
|
+
/** service: begin */
|
|
3
|
+
export * from '../service/imageNative.ts';
|
|
4
|
+
|
|
5
|
+
import 'vona-module-a-bean';
|
|
6
|
+
declare module 'vona-module-a-bean' {
|
|
7
|
+
|
|
8
|
+
export interface IServiceRecord {
|
|
9
|
+
'image-native:imageNative': never;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
declare module 'vona-module-image-native' {
|
|
15
|
+
|
|
16
|
+
export interface ServiceImageNative {
|
|
17
|
+
/** @internal */
|
|
18
|
+
get scope(): ScopeModuleImageNative;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ServiceImageNative {
|
|
22
|
+
get $beanFullName(): 'image-native.service.imageNative';
|
|
23
|
+
get $onionName(): 'image-native:imageNative';
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** service: end */
|
|
28
|
+
/** service: begin */
|
|
29
|
+
import type { ServiceImageNative } from '../service/imageNative.ts';
|
|
30
|
+
export interface IModuleService {
|
|
31
|
+
'imageNative': ServiceImageNative;
|
|
32
|
+
}
|
|
33
|
+
/** service: end */
|
|
34
|
+
/** service: begin */
|
|
35
|
+
|
|
36
|
+
import 'vona';
|
|
37
|
+
declare module 'vona' {
|
|
38
|
+
export interface IBeanRecordGeneral {
|
|
39
|
+
'image-native.service.imageNative': ServiceImageNative;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** service: end */
|
|
43
|
+
/** imageProvider: begin */
|
|
44
|
+
export * from '../bean/imageProvider.native.ts';
|
|
45
|
+
import type { IImageProviderOptionsNative } from '../bean/imageProvider.native.ts';
|
|
46
|
+
import 'vona-module-a-image';
|
|
47
|
+
declare module 'vona-module-a-image' {
|
|
48
|
+
|
|
49
|
+
export interface IImageProviderRecord {
|
|
50
|
+
'image-native:native': IImageProviderOptionsNative;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
declare module 'vona-module-image-native' {
|
|
56
|
+
|
|
57
|
+
export interface ImageProviderNative {
|
|
58
|
+
/** @internal */
|
|
59
|
+
get scope(): ScopeModuleImageNative;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ImageProviderNative {
|
|
63
|
+
get $beanFullName(): 'image-native.imageProvider.native';
|
|
64
|
+
get $onionName(): 'image-native:native';
|
|
65
|
+
get $onionOptions(): IImageProviderOptionsNative;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** imageProvider: end */
|
|
69
|
+
/** imageProvider: begin */
|
|
70
|
+
import type { ImageProviderNative } from '../bean/imageProvider.native.ts';
|
|
71
|
+
export interface IModuleImageProvider {
|
|
72
|
+
'native': ImageProviderNative;
|
|
73
|
+
}
|
|
74
|
+
/** imageProvider: end */
|
|
75
|
+
/** config: begin */
|
|
76
|
+
export * from '../config/config.ts';
|
|
77
|
+
import type { config } from '../config/config.ts';
|
|
78
|
+
/** config: end */
|
|
79
|
+
/** monkey: begin */
|
|
80
|
+
export * from '../monkey.ts';
|
|
81
|
+
/** monkey: end */
|
|
82
|
+
/** scope: begin */
|
|
83
|
+
import { BeanScopeBase, type BeanScopeUtil, type TypeModuleConfig } from 'vona';
|
|
84
|
+
import { Scope } from 'vona-module-a-bean';
|
|
85
|
+
|
|
86
|
+
@Scope()
|
|
87
|
+
export class ScopeModuleImageNative extends BeanScopeBase {}
|
|
88
|
+
|
|
89
|
+
export interface ScopeModuleImageNative {
|
|
90
|
+
util: BeanScopeUtil;
|
|
91
|
+
config: TypeModuleConfig<typeof config>;
|
|
92
|
+
service: IModuleService;
|
|
93
|
+
imageProvider: IModuleImageProvider;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
import 'vona';
|
|
97
|
+
declare module 'vona' {
|
|
98
|
+
export interface IBeanScopeRecord {
|
|
99
|
+
'image-native': ScopeModuleImageNative;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface IBeanScopeContainer {
|
|
103
|
+
imageNative: ScopeModuleImageNative;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface IBeanScopeConfig {
|
|
107
|
+
'image-native': ReturnType<typeof config>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
/** scope: end */
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDecoratorImageProviderOptions,
|
|
3
|
+
IImageDeliveryOptions,
|
|
4
|
+
IImageDownloadResult,
|
|
5
|
+
IImageProviderClientOptions,
|
|
6
|
+
IImageProviderClientRecord,
|
|
7
|
+
IImageProviderExecute,
|
|
8
|
+
IImageProviderResource,
|
|
9
|
+
IImageUploadInput,
|
|
10
|
+
IImageVariantRequest,
|
|
11
|
+
} from 'vona-module-a-image';
|
|
12
|
+
import type { EntityImage } from 'vona-module-a-image';
|
|
13
|
+
|
|
14
|
+
import fse from 'fs-extra';
|
|
15
|
+
import { BeanBase } from 'vona';
|
|
16
|
+
import { ImageProvider } from 'vona-module-a-image';
|
|
17
|
+
|
|
18
|
+
export interface IImageProviderNativeClientRecord extends IImageProviderClientRecord {}
|
|
19
|
+
|
|
20
|
+
export interface IImageProviderNativeClientOptions extends IImageProviderClientOptions {
|
|
21
|
+
subdir?: string;
|
|
22
|
+
signingKey?: string;
|
|
23
|
+
tokenName?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IImageProviderOptionsNative extends IDecoratorImageProviderOptions<
|
|
27
|
+
IImageProviderNativeClientRecord,
|
|
28
|
+
IImageProviderNativeClientOptions
|
|
29
|
+
> {}
|
|
30
|
+
|
|
31
|
+
@ImageProvider<IImageProviderOptionsNative>({
|
|
32
|
+
base: {
|
|
33
|
+
subdir: 'default',
|
|
34
|
+
signedDeliveryKind: 'proxy',
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
export class ImageProviderNative extends BeanBase implements IImageProviderExecute {
|
|
38
|
+
async upload(
|
|
39
|
+
input: IImageUploadInput,
|
|
40
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
41
|
+
_options: IImageProviderOptionsNative,
|
|
42
|
+
): Promise<IImageProviderResource> {
|
|
43
|
+
const resource = await this.scope.service.imageNative.upload(input, clientOptions);
|
|
44
|
+
return {
|
|
45
|
+
...resource,
|
|
46
|
+
filename: input.filename,
|
|
47
|
+
contentType: input.contentType,
|
|
48
|
+
meta: input.meta,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async get(
|
|
53
|
+
image: EntityImage,
|
|
54
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
55
|
+
_options: IImageProviderOptionsNative,
|
|
56
|
+
) {
|
|
57
|
+
return {
|
|
58
|
+
resourceId: image.resourceId,
|
|
59
|
+
filename: image.filename,
|
|
60
|
+
contentType: image.contentType,
|
|
61
|
+
size: image.size,
|
|
62
|
+
width: image.width,
|
|
63
|
+
height: image.height,
|
|
64
|
+
requireSignedURLs: image.requireSignedURLs,
|
|
65
|
+
variants: image.variants,
|
|
66
|
+
meta: image.meta,
|
|
67
|
+
storagePath: image.storagePath,
|
|
68
|
+
deliveryBaseUrl: image.deliveryBaseUrl ?? clientOptions.deliveryBaseUrl,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async delete(
|
|
73
|
+
image: EntityImage,
|
|
74
|
+
_clientOptions: IImageProviderClientOptions,
|
|
75
|
+
_options: IImageProviderOptionsNative,
|
|
76
|
+
) {
|
|
77
|
+
await this.scope.service.imageNative.remove(image);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async getVariantUrl(
|
|
81
|
+
image: EntityImage,
|
|
82
|
+
request: IImageVariantRequest,
|
|
83
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
84
|
+
_options: IImageProviderOptionsNative,
|
|
85
|
+
deliveryOptions?: IImageDeliveryOptions,
|
|
86
|
+
) {
|
|
87
|
+
return await this.scope.service.imageNative.getVariantUrl(
|
|
88
|
+
image,
|
|
89
|
+
request,
|
|
90
|
+
{
|
|
91
|
+
...clientOptions,
|
|
92
|
+
subdir: clientOptions.subdir ?? 'default',
|
|
93
|
+
deliveryBaseUrl: image.deliveryBaseUrl ?? clientOptions.deliveryBaseUrl,
|
|
94
|
+
},
|
|
95
|
+
deliveryOptions,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async download(
|
|
100
|
+
image: EntityImage,
|
|
101
|
+
request: IImageVariantRequest,
|
|
102
|
+
clientOptions: IImageProviderNativeClientOptions,
|
|
103
|
+
options: IImageProviderOptionsNative,
|
|
104
|
+
deliveryOptions?: IImageDeliveryOptions,
|
|
105
|
+
): Promise<IImageDownloadResult> {
|
|
106
|
+
if (
|
|
107
|
+
(deliveryOptions?.responseMode ?? 'auto') !== 'url' &&
|
|
108
|
+
!deliveryOptions?.signed &&
|
|
109
|
+
request.variantName === 'original' &&
|
|
110
|
+
!request.transformOptions
|
|
111
|
+
) {
|
|
112
|
+
const buffer = image.storagePath ? await fse.readFile(image.storagePath) : undefined;
|
|
113
|
+
if (buffer) {
|
|
114
|
+
return {
|
|
115
|
+
kind: 'buffer',
|
|
116
|
+
buffer,
|
|
117
|
+
filename: image.filename,
|
|
118
|
+
contentType: image.contentType,
|
|
119
|
+
signed: false,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
kind: 'url',
|
|
125
|
+
url: await this.getVariantUrl(image, request, clientOptions, options, deliveryOptions),
|
|
126
|
+
filename: image.filename,
|
|
127
|
+
contentType: image.contentType,
|
|
128
|
+
signed: !!deliveryOptions?.signed,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './.metadata/index.ts';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IMonkeyAppStart } from 'vona';
|
|
2
|
+
|
|
3
|
+
import fse from 'fs-extra';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { BeanSimple, cast, getPlatformArch, resolveAddon } from 'vona';
|
|
6
|
+
|
|
7
|
+
const __Version = '8.18.3';
|
|
8
|
+
|
|
9
|
+
const __MapTargetNames = {
|
|
10
|
+
'linux-arm64': `libvips-cpp.so.${__Version}`,
|
|
11
|
+
'linux-x64': `libvips-cpp.so.${__Version}`,
|
|
12
|
+
'darwin-arm64': `libvips-cpp.${__Version}.dylib`,
|
|
13
|
+
'darwin-x64': `libvips-cpp.${__Version}.dylib`,
|
|
14
|
+
'win32-x64': 'libvips-42.dll',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class Monkey extends BeanSimple implements IMonkeyAppStart {
|
|
18
|
+
async appStart() {
|
|
19
|
+
cast(this.app).__prepareSharpLibvips = () => {
|
|
20
|
+
const platformArch = getPlatformArch();
|
|
21
|
+
const addonFileSrc = resolveAddon('sharpLibvips');
|
|
22
|
+
const addonDirDest = path.join(
|
|
23
|
+
import.meta.dirname,
|
|
24
|
+
`node_modules/@img/sharp-libvips-${platformArch}/lib`,
|
|
25
|
+
);
|
|
26
|
+
const addonFileDest = path.join(addonDirDest, __MapTargetNames[platformArch]);
|
|
27
|
+
if (!fse.existsSync(addonFileDest)) {
|
|
28
|
+
fse.ensureDirSync(addonDirDest);
|
|
29
|
+
fse.copyFileSync(addonFileSrc, addonFileDest);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type { SharpConstructor } from 'sharp';
|
|
2
|
+
import type {
|
|
3
|
+
EntityImage,
|
|
4
|
+
IImageDeliveryOptions,
|
|
5
|
+
IImageNamedVariants,
|
|
6
|
+
IImageProviderResolvedVariant,
|
|
7
|
+
IImageProviderResource,
|
|
8
|
+
IImageTransformOptions,
|
|
9
|
+
IImageUploadInput,
|
|
10
|
+
IImageVariantRequest,
|
|
11
|
+
} from 'vona-module-a-image';
|
|
12
|
+
|
|
13
|
+
import fse from 'fs-extra';
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { BeanBase, uuidv4 } from 'vona';
|
|
17
|
+
import { Service } from 'vona-module-a-bean';
|
|
18
|
+
import { resolveImageVariantRequestToTransform } from 'vona-module-a-image';
|
|
19
|
+
|
|
20
|
+
import type { IImageProviderNativeClientOptions } from '../bean/imageProvider.native.ts';
|
|
21
|
+
|
|
22
|
+
type IImageNativeStoredImage = Pick<
|
|
23
|
+
EntityImage,
|
|
24
|
+
'resourceId' | 'filename' | 'storagePath' | 'variants'
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
@Service()
|
|
28
|
+
export class ServiceImageNative extends BeanBase {
|
|
29
|
+
private _sharpInstance: SharpConstructor;
|
|
30
|
+
|
|
31
|
+
private async getSharp() {
|
|
32
|
+
if (!this._sharpInstance) {
|
|
33
|
+
this._sharpInstance = (await import('sharp')).default;
|
|
34
|
+
}
|
|
35
|
+
return this._sharpInstance;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async upload(
|
|
39
|
+
input: IImageUploadInput,
|
|
40
|
+
options: IImageProviderNativeClientOptions,
|
|
41
|
+
): Promise<IImageProviderResource> {
|
|
42
|
+
const publicPath = await this.app.util.getPublicPathPhysical(
|
|
43
|
+
path.join('image-native', options.subdir ?? 'default'),
|
|
44
|
+
true,
|
|
45
|
+
);
|
|
46
|
+
const resourceId = uuidv4();
|
|
47
|
+
const ext = this._getOriginalExt(input.filename, input.file);
|
|
48
|
+
const targetName = `${resourceId}${ext}`;
|
|
49
|
+
const targetPath = path.join(publicPath, targetName);
|
|
50
|
+
await fse.copy(input.file, targetPath);
|
|
51
|
+
const sharp = await this.getSharp();
|
|
52
|
+
const metadata = await sharp(targetPath).metadata();
|
|
53
|
+
const stat = await fse.stat(targetPath);
|
|
54
|
+
const variants = options.variants ?? this.scope.config.imageNative.variants;
|
|
55
|
+
await this._generateNamedVariants(
|
|
56
|
+
{ resourceId, filename: input.filename, storagePath: targetPath, variants },
|
|
57
|
+
options,
|
|
58
|
+
);
|
|
59
|
+
return {
|
|
60
|
+
resourceId,
|
|
61
|
+
size: Number(stat.size),
|
|
62
|
+
width: metadata.width,
|
|
63
|
+
height: metadata.height,
|
|
64
|
+
storagePath: targetPath,
|
|
65
|
+
deliveryBaseUrl: options.deliveryBaseUrl,
|
|
66
|
+
requireSignedURLs: input.requireSignedURLs ?? options.requireSignedURLs,
|
|
67
|
+
variants,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async remove(image: IImageNativeStoredImage) {
|
|
72
|
+
if (!image.storagePath) return;
|
|
73
|
+
const dir = path.dirname(image.storagePath);
|
|
74
|
+
if (!(await fse.pathExists(dir))) return;
|
|
75
|
+
const entries = await fse.readdir(dir);
|
|
76
|
+
await Promise.all(
|
|
77
|
+
entries
|
|
78
|
+
.filter(
|
|
79
|
+
name =>
|
|
80
|
+
name === path.basename(image.storagePath!) || name.startsWith(`${image.resourceId}__`),
|
|
81
|
+
)
|
|
82
|
+
.map(name => fse.remove(path.join(dir, name))),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getVariantUrl(
|
|
87
|
+
image: IImageNativeStoredImage,
|
|
88
|
+
request: IImageVariantRequest,
|
|
89
|
+
options: IImageProviderNativeClientOptions,
|
|
90
|
+
_deliveryOptions?: IImageDeliveryOptions,
|
|
91
|
+
) {
|
|
92
|
+
const resolved = resolveImageVariantRequestToTransform(request, 'original', image.variants);
|
|
93
|
+
if (
|
|
94
|
+
resolved.variantName === 'original' &&
|
|
95
|
+
this._isOriginalTransform(resolved.transformOptions)
|
|
96
|
+
) {
|
|
97
|
+
return await this._getOriginalUrl(image, options);
|
|
98
|
+
}
|
|
99
|
+
const targetPath = await this._ensureVariantFile(image, resolved);
|
|
100
|
+
return await this._buildUrl(targetPath, options.deliveryBaseUrl);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private async _generateNamedVariants(
|
|
104
|
+
image: IImageNativeStoredImage,
|
|
105
|
+
options: IImageProviderNativeClientOptions,
|
|
106
|
+
) {
|
|
107
|
+
const variantNames = Object.keys(image.variants ?? {}) as Array<
|
|
108
|
+
keyof NonNullable<IImageNamedVariants>
|
|
109
|
+
>;
|
|
110
|
+
for (const variantName of variantNames) {
|
|
111
|
+
if (variantName === 'original') continue;
|
|
112
|
+
await this._ensureVariantFile(
|
|
113
|
+
image,
|
|
114
|
+
resolveImageVariantRequestToTransform({ variantName }, 'original', image.variants),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (!image.variants?.original) return;
|
|
118
|
+
await this.getVariantUrl(image, { variantName: 'original' }, options);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private async _ensureVariantFile(
|
|
122
|
+
image: IImageNativeStoredImage,
|
|
123
|
+
resolved: IImageProviderResolvedVariant,
|
|
124
|
+
) {
|
|
125
|
+
if (!image.storagePath) {
|
|
126
|
+
throw new Error(`Image storage path missing: ${image.resourceId}`);
|
|
127
|
+
}
|
|
128
|
+
const targetPath = await this._getVariantAbsolutePath(image, resolved);
|
|
129
|
+
if (!(await fse.pathExists(targetPath))) {
|
|
130
|
+
await this._writeTransformedFile(image.storagePath, targetPath, resolved.transformOptions);
|
|
131
|
+
}
|
|
132
|
+
return targetPath;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async _writeTransformedFile(
|
|
136
|
+
sourcePath: string,
|
|
137
|
+
targetPath: string,
|
|
138
|
+
transformOptions: IImageTransformOptions,
|
|
139
|
+
) {
|
|
140
|
+
await fse.ensureDir(path.dirname(targetPath));
|
|
141
|
+
if (this._isOriginalTransform(transformOptions)) {
|
|
142
|
+
await fse.copy(sourcePath, targetPath, { overwrite: true });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const sharp = await this.getSharp();
|
|
146
|
+
let pipeline = sharp(sourcePath, { failOn: 'none' });
|
|
147
|
+
const width =
|
|
148
|
+
transformOptions.width && transformOptions.dpr
|
|
149
|
+
? Math.round(transformOptions.width * transformOptions.dpr)
|
|
150
|
+
: transformOptions.width;
|
|
151
|
+
const height =
|
|
152
|
+
transformOptions.height && transformOptions.dpr
|
|
153
|
+
? Math.round(transformOptions.height * transformOptions.dpr)
|
|
154
|
+
: transformOptions.height;
|
|
155
|
+
if (
|
|
156
|
+
width ||
|
|
157
|
+
height ||
|
|
158
|
+
transformOptions.fit ||
|
|
159
|
+
transformOptions.gravity ||
|
|
160
|
+
transformOptions.background
|
|
161
|
+
) {
|
|
162
|
+
pipeline = pipeline.resize({
|
|
163
|
+
width,
|
|
164
|
+
height,
|
|
165
|
+
fit: this._mapFit(transformOptions.fit),
|
|
166
|
+
position: this._mapGravity(transformOptions.gravity),
|
|
167
|
+
background: transformOptions.background,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (transformOptions.rotate !== undefined) {
|
|
171
|
+
pipeline = pipeline.rotate(transformOptions.rotate);
|
|
172
|
+
}
|
|
173
|
+
if (transformOptions.sharpen !== undefined) {
|
|
174
|
+
pipeline = pipeline.sharpen({ sigma: transformOptions.sharpen });
|
|
175
|
+
}
|
|
176
|
+
const format = this._normalizeFormat(transformOptions.format);
|
|
177
|
+
if (format === 'jpeg') {
|
|
178
|
+
pipeline = pipeline.jpeg({ quality: transformOptions.quality });
|
|
179
|
+
} else if (format === 'png') {
|
|
180
|
+
pipeline = pipeline.png({ quality: transformOptions.quality });
|
|
181
|
+
} else if (format === 'webp') {
|
|
182
|
+
pipeline = pipeline.webp({ quality: transformOptions.quality });
|
|
183
|
+
} else if (format === 'avif') {
|
|
184
|
+
pipeline = pipeline.avif({ quality: transformOptions.quality });
|
|
185
|
+
}
|
|
186
|
+
await pipeline.toFile(targetPath);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private async _getOriginalUrl(
|
|
190
|
+
image: IImageNativeStoredImage,
|
|
191
|
+
options: IImageProviderNativeClientOptions,
|
|
192
|
+
) {
|
|
193
|
+
if (!image.storagePath) {
|
|
194
|
+
throw new Error(`Image storage path missing: ${image.resourceId}`);
|
|
195
|
+
}
|
|
196
|
+
return await this._buildUrl(image.storagePath, options.deliveryBaseUrl);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async _buildUrl(targetPath: string, deliveryBaseUrl?: string) {
|
|
200
|
+
const variantPath = await this._getVariantStaticPath(targetPath);
|
|
201
|
+
if (deliveryBaseUrl) {
|
|
202
|
+
return `${deliveryBaseUrl.replace(/\/$/, '')}/${variantPath}`;
|
|
203
|
+
}
|
|
204
|
+
return this.app.util.combineStaticPath(`/${variantPath}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private async _getVariantStaticPath(targetPath: string) {
|
|
208
|
+
const publicRoot = await this.app.util.getPublicPathPhysical(undefined, true);
|
|
209
|
+
const relativePath = path.relative(publicRoot, targetPath).split(path.sep).join(path.posix.sep);
|
|
210
|
+
return path.posix.join('public', this.ctx.instance.id.toString(), relativePath);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private async _getVariantAbsolutePath(
|
|
214
|
+
image: IImageNativeStoredImage,
|
|
215
|
+
resolved: IImageProviderResolvedVariant,
|
|
216
|
+
) {
|
|
217
|
+
if (!image.storagePath) throw new Error(`Image storage path missing: ${image.resourceId}`);
|
|
218
|
+
const dir = path.dirname(image.storagePath);
|
|
219
|
+
const ext = this._getVariantExt(image.filename, image.storagePath, resolved.transformOptions);
|
|
220
|
+
if (resolved.variantName !== 'custom') {
|
|
221
|
+
const variantName = this._sanitizeVariantName(resolved.variantName);
|
|
222
|
+
return path.join(dir, `${image.resourceId}__${variantName}${ext}`);
|
|
223
|
+
}
|
|
224
|
+
const cacheKey = this._buildTransformCacheKey(resolved.transformOptions);
|
|
225
|
+
return path.join(dir, `${image.resourceId}__t_${cacheKey}${ext}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private _getVariantExt(
|
|
229
|
+
filename: string | undefined,
|
|
230
|
+
storagePath: string | undefined,
|
|
231
|
+
transformOptions: IImageTransformOptions,
|
|
232
|
+
) {
|
|
233
|
+
const format = this._normalizeFormat(transformOptions.format);
|
|
234
|
+
if (format) {
|
|
235
|
+
return format === 'jpeg' ? '.jpg' : `.${format}`;
|
|
236
|
+
}
|
|
237
|
+
return path.extname(filename ?? '') || path.extname(storagePath ?? '') || '.bin';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private _getOriginalExt(filename: string | undefined, filePath: string) {
|
|
241
|
+
return path.extname(filename ?? '') || path.extname(filePath) || '.bin';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private _normalizeFormat(format: IImageTransformOptions['format']) {
|
|
245
|
+
if (!format || format === 'auto') return undefined;
|
|
246
|
+
return format === 'jpeg' ? 'jpeg' : format;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private _buildTransformCacheKey(transformOptions: IImageTransformOptions) {
|
|
250
|
+
const stable = this._stableStringify(transformOptions);
|
|
251
|
+
return createHash('sha1').update(stable).digest('hex').slice(0, 12);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private _stableStringify(value: unknown): string {
|
|
255
|
+
if (Array.isArray(value)) {
|
|
256
|
+
return `[${value.map(item => this._stableStringify(item)).join(',')}]`;
|
|
257
|
+
}
|
|
258
|
+
if (value && typeof value === 'object') {
|
|
259
|
+
const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>
|
|
260
|
+
a.localeCompare(b),
|
|
261
|
+
);
|
|
262
|
+
return `{${entries
|
|
263
|
+
.map(([key, item]) => `${JSON.stringify(key)}:${this._stableStringify(item)}`)
|
|
264
|
+
.join(',')}}`;
|
|
265
|
+
}
|
|
266
|
+
return JSON.stringify(value);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private _sanitizeVariantName(variantName: string) {
|
|
270
|
+
return variantName.replace(/[^\w.-]/g, '-');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private _isOriginalTransform(transformOptions: IImageTransformOptions) {
|
|
274
|
+
return Object.keys(transformOptions).length === 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private _mapFit(fit: IImageTransformOptions['fit']) {
|
|
278
|
+
if (fit === 'scale-down') return 'inside' as const;
|
|
279
|
+
if (fit === 'contain' || fit === 'pad') return 'contain' as const;
|
|
280
|
+
if (fit === 'cover' || fit === 'crop') return 'cover' as const;
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private _mapGravity(gravity: IImageTransformOptions['gravity']) {
|
|
285
|
+
if (gravity === 'top') return 'north';
|
|
286
|
+
if (gravity === 'bottom') return 'south';
|
|
287
|
+
if (gravity === 'left') return 'west';
|
|
288
|
+
if (gravity === 'right') return 'east';
|
|
289
|
+
return 'centre';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vona-suite-a-image",
|
|
3
|
+
"version": "5.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"author": "",
|
|
6
|
+
"files": [],
|
|
7
|
+
"type": "module",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"vona-module-a-image": "workspace:^",
|
|
10
|
+
"vona-module-image-cloudflare": "workspace:^",
|
|
11
|
+
"vona-module-image-native": "workspace:^"
|
|
12
|
+
},
|
|
13
|
+
"title": "a-image"
|
|
14
|
+
}
|