cabloy 5.1.101 → 5.1.103

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.
Files changed (128) hide show
  1. package/.cabloy-version +1 -1
  2. package/CHANGELOG.md +36 -0
  3. package/CLAUDE.local.md +4 -0
  4. package/cabloy-docs/.vitepress/config.mjs +3 -0
  5. package/cabloy-docs/backend/file-guide.md +148 -0
  6. package/cabloy-docs/backend/image-guide.md +40 -40
  7. package/cabloy-docs/backend/jwt-guide.md +21 -0
  8. package/cabloy-docs/frontend/file-guide.md +147 -0
  9. package/cabloy-docs/frontend/image-guide.md +18 -9
  10. package/cabloy-docs/frontend/model-state-guide.md +12 -0
  11. package/cabloy-docs/frontend/use-state-data-best-practices.md +54 -0
  12. package/cabloy-docs/fullstack/file-workflow.md +135 -0
  13. package/cabloy-docs/fullstack/image-workflow.md +12 -3
  14. package/package.json +1 -1
  15. package/scripts/upgrade.ts +26 -10
  16. package/vona/packages-vona/vona/package.json +1 -1
  17. package/vona/src/suite/a-training/modules/training-record/src/.metadata/index.ts +30 -4
  18. package/vona/src/suite/a-training/modules/training-record/src/bean/fileScene.dossierFile.ts +1 -1
  19. package/vona/src/suite/a-training/modules/training-record/src/bean/imageScene.sceneImage.ts +1 -0
  20. package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectResItem.tsx +8 -6
  21. package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +8 -6
  22. package/vona/src/suite/a-training/modules/training-record/src/index.ts +0 -1
  23. package/vona/src/suite/a-training/modules/training-record/src/lib/index.ts +0 -1
  24. package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +10 -12
  25. package/vona/src/suite/a-training/modules/training-student/src/bean/imageScene.studentImage.ts +1 -0
  26. package/vona/src/suite/a-training/modules/training-student/src/dto/detailRecordBase.tsx +9 -10
  27. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +2 -2
  28. package/vona/src/suite-vendor/a-file/modules/a-file/package.json +3 -2
  29. package/vona/src/suite-vendor/a-file/modules/a-file/src/.metadata/index.ts +155 -35
  30. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.file.ts +283 -54
  31. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/bean.fileUploadPolicy.ts +46 -63
  32. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.index.ts +12 -0
  33. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.redlock.ts +1 -1
  34. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/meta.version.ts +3 -0
  35. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/schedule.fileDraftPrune.ts +29 -0
  36. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/serializerTransform.resolveView.ts +45 -0
  37. package/vona/src/suite-vendor/a-file/modules/a-file/src/bean/serializerTransform.resolveViews.ts +45 -0
  38. package/vona/src/suite-vendor/a-file/modules/a-file/src/config/config.ts +6 -0
  39. package/vona/src/suite-vendor/a-file/modules/a-file/src/controller/file.ts +64 -56
  40. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadFinalizeRequest.ts +13 -0
  41. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadFinalizeResponse.ts +10 -0
  42. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadRequest.ts +0 -3
  43. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDirectUploadResponse.ts +2 -14
  44. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileDownloadRequest.ts +3 -0
  45. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadPolicyResponse.ts +3 -0
  46. package/vona/src/suite-vendor/a-file/modules/a-file/src/dto/fileUploadResponse.ts +0 -25
  47. package/vona/src/{suite/a-training/modules/training-record/src/dto/recordDossierFileView.ts → suite-vendor/a-file/modules/a-file/src/dto/fileView.ts} +3 -15
  48. package/vona/src/suite-vendor/a-file/modules/a-file/src/entity/file.ts +10 -0
  49. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/fileUploadUrl.ts +329 -0
  50. package/vona/src/suite-vendor/a-file/modules/a-file/src/lib/index.ts +1 -0
  51. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/file.ts +51 -10
  52. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileProvider.ts +8 -3
  53. package/vona/src/suite-vendor/a-file/modules/a-file/src/types/fileScene.ts +1 -1
  54. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/package.json +1 -1
  55. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/bean/fileProvider.cloudflare.ts +12 -4
  56. package/vona/src/suite-vendor/a-file/modules/file-cloudflare/src/service/fileCloudflare.ts +52 -18
  57. package/vona/src/suite-vendor/a-file/modules/file-native/package.json +1 -1
  58. package/vona/src/suite-vendor/a-file/modules/file-native/src/bean/fileProvider.native.ts +5 -5
  59. package/vona/src/suite-vendor/a-file/modules/file-native/src/service/fileNative.ts +7 -8
  60. package/vona/src/suite-vendor/a-file/package.json +4 -4
  61. package/vona/src/suite-vendor/a-image/modules/a-image/package.json +1 -1
  62. package/vona/src/suite-vendor/a-image/modules/a-image/src/.metadata/index.ts +16 -19
  63. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.image.ts +99 -74
  64. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/bean.imageUploadPolicy.ts +28 -68
  65. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/meta.version.ts +1 -1
  66. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/serializerTransform.resolveView.ts +3 -0
  67. package/vona/src/suite-vendor/a-image/modules/a-image/src/bean/serializerTransform.resolveViews.ts +3 -0
  68. package/vona/src/suite-vendor/a-image/modules/a-image/src/config/config.ts +4 -0
  69. package/vona/src/suite-vendor/a-image/modules/a-image/src/controller/image.ts +78 -34
  70. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDeliveryRequest.ts +3 -0
  71. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadRequest.ts +0 -3
  72. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageDirectUploadResponse.ts +1 -27
  73. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadPolicyResponse.ts +6 -0
  74. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadResponse.ts +2 -36
  75. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadUrlRequest.ts +0 -3
  76. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageView.ts +4 -27
  77. package/vona/src/suite-vendor/a-image/modules/a-image/src/entity/image.ts +1 -1
  78. package/vona/src/suite-vendor/a-image/modules/a-image/src/types/image.ts +36 -29
  79. package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageProvider.ts +4 -4
  80. package/vona/src/suite-vendor/a-image/modules/a-image/src/types/imageScene.ts +1 -0
  81. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/package.json +1 -1
  82. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/bean/imageProvider.cloudflare.ts +8 -11
  83. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/lib/cloudflareImageUrl.ts +4 -16
  84. package/vona/src/suite-vendor/a-image/modules/image-cloudflare/src/service/imageCloudflare.ts +17 -16
  85. package/vona/src/suite-vendor/a-image/modules/image-native/package.json +2 -6
  86. package/vona/src/suite-vendor/a-image/modules/image-native/src/.metadata/index.ts +0 -37
  87. package/vona/src/suite-vendor/a-image/modules/image-native/src/bean/imageProvider.native.ts +13 -36
  88. package/vona/src/suite-vendor/a-image/modules/image-native/src/service/imageNative.ts +100 -113
  89. package/vona/src/suite-vendor/a-image/package.json +1 -1
  90. package/vona/src/suite-vendor/a-vona/modules/a-jwt/package.json +1 -1
  91. package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/config/config.ts +3 -1
  92. package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/service/jwtClient.ts +9 -4
  93. package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +1 -1
  94. package/vona/src/suite-vendor/a-vona/modules/a-upload/src/bean/interceptor.upload.ts +113 -64
  95. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  96. package/zova/packages-zova/zova/package.json +2 -2
  97. package/zova/src/suite/a-home/modules/home-api/src/api/openapi/schemas.ts +50 -12
  98. package/zova/src/suite/a-home/modules/home-api/src/api/openapi/types.ts +610 -114
  99. package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +44 -1
  100. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +50 -12
  101. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +610 -114
  102. package/zova/src/suite/cabloy-basic/modules/basic-file/src/.metadata/index.ts +16 -12
  103. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/file.ts +25 -25
  104. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/schemas.ts +18 -24
  105. package/zova/src/suite/cabloy-basic/modules/basic-file/src/api/openapi/types.ts +228 -291
  106. package/zova/src/suite/cabloy-basic/modules/basic-file/src/apiSchema/file.ts +5 -5
  107. package/zova/src/suite/cabloy-basic/modules/basic-file/src/bean/tableCell.file.tsx +23 -5
  108. package/zova/src/suite/cabloy-basic/modules/basic-file/src/component/formFieldFile/controller.tsx +72 -43
  109. package/zova/src/suite/cabloy-basic/modules/basic-file/src/lib/file.ts +22 -4
  110. package/zova/src/suite/cabloy-basic/modules/basic-image/src/.metadata/index.ts +16 -42
  111. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/image.ts +5 -25
  112. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/schemas.ts +10 -24
  113. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/openapi/types.ts +216 -333
  114. package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/image.ts +0 -5
  115. package/zova/src/suite/cabloy-basic/modules/basic-image/src/bean/tableCell.image.tsx +38 -12
  116. package/zova/src/suite/cabloy-basic/modules/basic-image/src/component/formFieldImage/controller.tsx +79 -32
  117. package/zova/src/suite/cabloy-basic/modules/basic-image/src/lib/preview.ts +22 -4
  118. package/zova/src/suite/cabloy-basic/modules/basic-image/src/types/image.ts +3 -4
  119. package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
  120. package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/utils.ts +29 -1
  121. package/zova/src/suite-vendor/a-zova/modules/a-model/src/types/query.ts +2 -2
  122. package/zova/src/suite-vendor/a-zova/package.json +2 -2
  123. package/vona/src/suite/a-training/modules/training-record/src/lib/resolveDossierFiles.ts +0 -34
  124. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadTokenRequest.ts +0 -24
  125. package/vona/src/suite-vendor/a-image/modules/a-image/src/dto/imageUploadTokenResponse.ts +0 -16
  126. package/vona/src/suite-vendor/a-image/modules/image-native/src/controller/image.ts +0 -57
  127. package/zova/src/suite/cabloy-basic/modules/basic-image/src/api/imageNativeImage.ts +0 -31
  128. package/zova/src/suite/cabloy-basic/modules/basic-image/src/apiSchema/imageNativeImage.ts +0 -13
@@ -28,7 +28,7 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate {
28
28
  table.integer(entityImage.size);
29
29
  table.integer(entityImage.width);
30
30
  table.integer(entityImage.height);
31
- table.boolean(entityImage.requireSignedURLs).defaultTo(false);
31
+ table.boolean(entityImage.public).defaultTo(true);
32
32
  table.json(entityImage.variants);
33
33
  table.json(entityImage.meta);
34
34
  table.text(entityImage.storagePath);
@@ -7,6 +7,7 @@ import { BeanBase } from 'vona';
7
7
  import { SerializerTransform } from 'vona-module-a-serialization';
8
8
 
9
9
  import type { DtoImageView } from '../dto/imageView.ts';
10
+ import type { IImageDeliveryOptions } from '../types/image.ts';
10
11
  import type { IImageSceneRecord } from '../types/imageScene.ts';
11
12
 
12
13
  export type TypeSerializerTransformResolveViewValue = unknown;
@@ -18,6 +19,7 @@ export type TypeSerializerTransformResolveViewResult = DtoImageView | undefined;
18
19
  export interface ISerializerTransformOptionsResolveView extends IDecoratorSerializerTransformOptions {
19
20
  fieldName: string;
20
21
  imageScene?: keyof IImageSceneRecord;
22
+ deliveryOptions?: IImageDeliveryOptions;
21
23
  }
22
24
 
23
25
  @SerializerTransform<ISerializerTransformOptionsResolveView>()
@@ -39,6 +41,7 @@ export class SerializerTransformResolveView
39
41
  data[options.fieldName],
40
42
  undefined,
41
43
  options.imageScene,
44
+ options.deliveryOptions,
42
45
  );
43
46
  }
44
47
  }
@@ -7,6 +7,7 @@ import { BeanBase } from 'vona';
7
7
  import { SerializerTransform } from 'vona-module-a-serialization';
8
8
 
9
9
  import type { DtoImageView } from '../dto/imageView.ts';
10
+ import type { IImageDeliveryOptions } from '../types/image.ts';
10
11
  import type { IImageSceneRecord } from '../types/imageScene.ts';
11
12
 
12
13
  export type TypeSerializerTransformResolveViewsValue = unknown;
@@ -18,6 +19,7 @@ export type TypeSerializerTransformResolveViewsResult = DtoImageView[] | undefin
18
19
  export interface ISerializerTransformOptionsResolveViews extends IDecoratorSerializerTransformOptions {
19
20
  fieldName: string;
20
21
  imageScene?: keyof IImageSceneRecord;
22
+ deliveryOptions?: IImageDeliveryOptions;
21
23
  }
22
24
 
23
25
  @SerializerTransform<ISerializerTransformOptionsResolveViews>()
@@ -39,6 +41,7 @@ export class SerializerTransformResolveViews
39
41
  data[options.fieldName],
40
42
  undefined,
41
43
  options.imageScene,
44
+ options.deliveryOptions,
42
45
  );
43
46
  }
44
47
  }
@@ -8,6 +8,7 @@ export function config(_app: VonaApplication) {
8
8
  defaultVariant: 'original',
9
9
  defaultProvider: 'image-native:native' as keyof IImageProviderRecord,
10
10
  defaultClientName: 'default',
11
+ public: true,
11
12
  upload: {
12
13
  maxSize: 2 * 1024 * 1024,
13
14
  mimeTypes: ['image/png', 'image/jpeg', 'image/webp'],
@@ -15,6 +16,9 @@ export function config(_app: VonaApplication) {
15
16
  directUpload: {
16
17
  draftExpiresIn: 30 * 60 * 1000,
17
18
  },
19
+ delivery: {
20
+ audienceExpiresIn: 8 * 60 * 60,
21
+ },
18
22
  },
19
23
  };
20
24
  }
@@ -1,11 +1,16 @@
1
1
  import type { IUploadFile } from 'vona-module-a-upload';
2
2
  import type { IDecoratorControllerOptions } from 'vona-module-a-web';
3
3
 
4
+ import fse from 'fs-extra';
4
5
  import { BeanBase } from 'vona';
5
6
  import { Core } from 'vona-module-a-core';
6
7
  import { Api, v } from 'vona-module-a-openapiutils';
7
8
  import { Passport } from 'vona-module-a-user';
8
9
  import { Arg, Controller, Web } from 'vona-module-a-web';
10
+ import z from 'zod';
11
+
12
+ import type { TypeImageVariantInput } from '../types/image.ts';
13
+ import type { IImageSceneRecord } from '../types/imageScene.ts';
9
14
 
10
15
  import { DtoImageDeliveryRequest } from '../dto/imageDeliveryRequest.ts';
11
16
  import { DtoImageDirectUploadFinalizeRequest } from '../dto/imageDirectUploadFinalizeRequest.ts';
@@ -15,8 +20,6 @@ import { DtoImageDirectUploadResponse } from '../dto/imageDirectUploadResponse.t
15
20
  import { DtoImageUploadPolicyRequest } from '../dto/imageUploadPolicyRequest.ts';
16
21
  import { DtoImageUploadPolicyResponse } from '../dto/imageUploadPolicyResponse.ts';
17
22
  import { DtoImageUploadResponse } from '../dto/imageUploadResponse.ts';
18
- import { DtoImageUploadTokenRequest } from '../dto/imageUploadTokenRequest.ts';
19
- import { DtoImageUploadTokenResponse } from '../dto/imageUploadTokenResponse.ts';
20
23
  import { DtoImageUploadUrlRequest } from '../dto/imageUploadUrlRequest.ts';
21
24
 
22
25
  export interface IControllerOptionsImage extends IDecoratorControllerOptions {}
@@ -29,40 +32,48 @@ export class ControllerImage extends BeanBase {
29
32
  return await this.bean.imageUploadPolicy.resolveSceneUploadPolicy(data);
30
33
  }
31
34
 
32
- @Web.post('upload-token')
33
- @Api.body(DtoImageUploadTokenResponse)
34
- async createUploadToken(@Arg.body() data: DtoImageUploadTokenRequest) {
35
- return await this.bean.imageUploadPolicy.createUploadToken(data);
36
- }
37
-
38
35
  @Web.post('upload')
39
- @Core.fileUpload()
36
+ @Core.fileUpload({
37
+ busboy: {
38
+ limits: {
39
+ fields: 1,
40
+ files: 1,
41
+ parts: 3,
42
+ },
43
+ },
44
+ })
40
45
  @Api.body(DtoImageUploadResponse)
41
46
  @Api.contentType('application/json')
42
- async upload(@Arg.field('token') token: string, @Arg.file('image') file: IUploadFile) {
43
- const payload = await this.bean.imageUploadPolicy.verifyUploadToken(
44
- token,
45
- this.ctx.route.routePathRaw,
46
- );
47
+ async upload(
48
+ @Arg.field('imageScene', v.required(), z.string()) imageScene: keyof IImageSceneRecord,
49
+ @Arg.file('image', v.required()) file: IUploadFile,
50
+ ) {
51
+ const stat = await fse.stat(file.file);
52
+ const policy = await this.bean.imageUploadPolicy.resolveUploadPolicy({
53
+ imageScene,
54
+ size: Number(stat.size),
55
+ mimeType: file.info.mimeType,
56
+ });
47
57
  await this.bean.imageUploadPolicy.validateUploadFile(
48
58
  {
49
59
  file: file.file,
50
60
  filename: file.info.filename,
51
61
  mimeType: file.info.mimeType,
52
62
  },
53
- payload,
63
+ policy,
54
64
  );
55
65
  const image = await this.bean.image.upload(
56
- payload.providerName,
66
+ policy.providerName,
57
67
  {
58
68
  file: file.file,
59
69
  filename: file.info.filename,
60
70
  contentType: file.info.mimeType,
71
+ public: policy.public,
61
72
  },
62
73
  {
63
- clientName: payload.clientName,
64
- meta: payload.meta,
65
- imageScene: payload.imageScene,
74
+ clientName: policy.clientName,
75
+ meta: policy.meta,
76
+ imageScene: policy.imageScene,
66
77
  },
67
78
  );
68
79
  return await this.bean.image.createImageActionResponse(image);
@@ -80,8 +91,8 @@ export class ControllerImage extends BeanBase {
80
91
  policy.providerName,
81
92
  {
82
93
  filename: data.filename,
83
- contentType: data.contentType,
84
- requireSignedURLs: data.requireSignedURLs,
94
+ contentType: data.contentType ?? data.mimeType,
95
+ public: policy.public,
85
96
  expiry: data.expiry,
86
97
  customId: data.customId,
87
98
  },
@@ -114,7 +125,7 @@ export class ControllerImage extends BeanBase {
114
125
  url: data.url,
115
126
  filename: data.filename,
116
127
  contentType: data.contentType,
117
- requireSignedURLs: data.requireSignedURLs,
128
+ public: policy.public,
118
129
  },
119
130
  {
120
131
  clientName: policy.clientName,
@@ -125,19 +136,52 @@ export class ControllerImage extends BeanBase {
125
136
  return await this.bean.image.createImageActionResponse(image);
126
137
  }
127
138
 
128
- @Web.get('delivery/:imageId')
139
+ @Web.get('delivery')
129
140
  @Passport.public()
130
- async delivery(
131
- @Arg.param('imageId', v.tableIdentity()) imageId: number,
132
- @Arg.query(v.object(DtoImageDeliveryRequest)) query: DtoImageDeliveryRequest,
133
- ) {
134
- const payload = await this.bean.imageUploadPolicy.verifyDeliveryToken(
135
- query.token,
136
- this.scope.util.combineApiPath(`image/delivery/${imageId}`, false, true),
137
- );
138
- if (String(payload.imageId) !== String(imageId)) {
139
- return this.app.throw(401);
141
+ async delivery(@Arg.query(v.object(DtoImageDeliveryRequest)) query: DtoImageDeliveryRequest) {
142
+ const { imageId } = query;
143
+ const image = await this.bean.image.get(imageId);
144
+ if (!image) return this.app.throw(404);
145
+ let request: TypeImageVariantInput = query.token
146
+ ? undefined
147
+ : {
148
+ variantName: query.variantName as any,
149
+ transformOptions: query.transformOptions as any,
150
+ };
151
+ if (query.token || !image.public) {
152
+ const payload = await this.bean.imageUploadPolicy.verifyDeliveryToken(
153
+ query.token,
154
+ this.scope.util.combineApiPath('image/delivery', false, true),
155
+ );
156
+ if (String(payload.imageId) !== String(imageId)) {
157
+ return this.app.throw(401);
158
+ }
159
+ if (payload.audienceUserId !== undefined) {
160
+ const auth = await this.bean.passport.checkAuthToken(
161
+ this.bean.jwt.extractAuthTokenFromAllWays(),
162
+ undefined,
163
+ { path: this.ctx.path },
164
+ );
165
+ if (!auth) return this.app.throw(401);
166
+ const user = auth.passport.user;
167
+ if (!user || user.anonymous) return this.app.throw(401);
168
+ if (String(user.id) !== String(payload.audienceUserId)) return this.app.throw(403);
169
+ }
170
+ request = payload.request;
171
+ }
172
+ const result = await this.bean.image.downloadForDelivery(imageId, request, {
173
+ protected: !image.public,
174
+ });
175
+ if (result.kind === 'url') {
176
+ if (!result.url) {
177
+ throw new Error(`image delivery url missing: ${imageId}`);
178
+ }
179
+ this.ctx.redirect(result.url);
180
+ return;
181
+ }
182
+ if (result.contentType) {
183
+ this.ctx.type = result.contentType;
140
184
  }
141
- this.ctx.redirect(payload.targetUrl);
185
+ this.ctx.body = result.buffer;
142
186
  }
143
187
  }
@@ -9,6 +9,9 @@ export interface IDtoOptionsImageDeliveryRequest extends IDecoratorDtoOptions {}
9
9
 
10
10
  @Dto<IDtoOptionsImageDeliveryRequest>()
11
11
  export class DtoImageDeliveryRequest {
12
+ @Api.field(v.tableIdentity())
13
+ imageId: number | string;
14
+
12
15
  @Api.field(v.optional())
13
16
  variantName?: string;
14
17
 
@@ -25,9 +25,6 @@ export class DtoImageDirectUploadRequest {
25
25
  @Api.field(v.optional())
26
26
  contentType?: string;
27
27
 
28
- @Api.field(v.optional())
29
- requireSignedURLs?: boolean;
30
-
31
28
  @Api.field(v.optional())
32
29
  expiry?: string;
33
30
 
@@ -3,11 +3,6 @@ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
3
 
4
4
  import { Api, v } from 'vona-module-a-openapiutils';
5
5
  import { Dto } from 'vona-module-a-web';
6
- import z from 'zod';
7
-
8
- import type { TypeImageStatus } from '../types/image.ts';
9
- import type { IImageProviderRecord } from '../types/imageProvider.ts';
10
- import type { IImageSceneRecord } from '../types/imageScene.ts';
11
6
 
12
7
  export interface IDtoOptionsImageDirectUploadResponse extends IDecoratorDtoOptions {}
13
8
 
@@ -16,33 +11,12 @@ export class DtoImageDirectUploadResponse {
16
11
  @Api.field(v.tableIdentity())
17
12
  id: TableIdentity;
18
13
 
19
- @Api.field(z.string())
20
- provider: keyof IImageProviderRecord;
21
-
22
- @Api.field()
23
- clientName: string;
24
-
25
- @Api.field()
26
- resourceId: string;
27
-
28
14
  @Api.field()
29
15
  uploadUrl: string;
30
16
 
31
- @Api.field(v.optional())
32
- draft?: boolean;
33
-
34
17
  @Api.field(v.optional())
35
18
  filename?: string;
36
19
 
37
20
  @Api.field(v.optional())
38
- requireSignedURLs?: boolean;
39
-
40
- @Api.field(v.optional(), z.string())
41
- status?: TypeImageStatus;
42
-
43
- @Api.field(v.optional())
44
- draftExpiresAt?: Date;
45
-
46
- @Api.field(v.optional(), z.string())
47
- imageScene?: keyof IImageSceneRecord;
21
+ public?: boolean;
48
22
  }
@@ -24,4 +24,10 @@ export class DtoImageUploadPolicyResponse {
24
24
 
25
25
  @Api.field(v.optional(), z.boolean())
26
26
  multiple?: boolean;
27
+
28
+ @Api.field(v.optional(), z.boolean())
29
+ public?: boolean;
30
+
31
+ @Api.field(v.optional(), z.boolean())
32
+ directUpload?: boolean;
27
33
  }
@@ -1,15 +1,8 @@
1
1
  import type { TableIdentity } from 'table-identity';
2
2
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
3
 
4
- import { $schema, Api, v } from 'vona-module-a-openapiutils';
4
+ import { Api, v } from 'vona-module-a-openapiutils';
5
5
  import { Dto } from 'vona-module-a-web';
6
- import z from 'zod';
7
-
8
- import type { IImageNamedVariants, TypeImageStatus } from '../types/image.ts';
9
- import type { IImageProviderRecord } from '../types/imageProvider.ts';
10
- import type { IImageSceneRecord } from '../types/imageScene.ts';
11
-
12
- import { DtoImageTransformOptions } from './imageTransformOptions.tsx';
13
6
 
14
7
  export interface IDtoOptionsImageUploadResponse extends IDecoratorDtoOptions {}
15
8
 
@@ -18,15 +11,6 @@ export class DtoImageUploadResponse {
18
11
  @Api.field(v.tableIdentity())
19
12
  id: TableIdentity;
20
13
 
21
- @Api.field(z.string())
22
- provider: keyof IImageProviderRecord;
23
-
24
- @Api.field()
25
- clientName: string;
26
-
27
- @Api.field()
28
- resourceId: string;
29
-
30
14
  @Api.field(v.optional())
31
15
  filename?: string;
32
16
 
@@ -43,25 +27,7 @@ export class DtoImageUploadResponse {
43
27
  height?: number;
44
28
 
45
29
  @Api.field(v.optional())
46
- requireSignedURLs?: boolean;
47
-
48
- @Api.field(v.optional(), z.record(z.string(), $schema(DtoImageTransformOptions)))
49
- variants?: IImageNamedVariants;
50
-
51
- @Api.field(v.optional(), z.string())
52
- imageScene?: keyof IImageSceneRecord;
53
-
54
- @Api.field(v.optional(), z.string())
55
- status?: TypeImageStatus;
56
-
57
- @Api.field(v.optional())
58
- draftExpiresAt?: Date;
59
-
60
- @Api.field(v.optional())
61
- finalizedAt?: Date;
62
-
63
- @Api.field(v.optional())
64
- uploadedAt?: Date;
30
+ public?: boolean;
65
31
 
66
32
  @Api.field(v.optional())
67
33
  url?: string;
@@ -27,7 +27,4 @@ export class DtoImageUploadUrlRequest {
27
27
 
28
28
  @Api.field(v.optional())
29
29
  contentType?: string;
30
-
31
- @Api.field(v.optional())
32
- requireSignedURLs?: boolean;
33
30
  }
@@ -1,15 +1,10 @@
1
1
  import type { TableIdentity } from 'table-identity';
2
2
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
3
 
4
- import { $schema, Api, v } from 'vona-module-a-openapiutils';
4
+ import { Api, v } from 'vona-module-a-openapiutils';
5
5
  import { Dto } from 'vona-module-a-web';
6
6
  import z from 'zod';
7
7
 
8
- import type { IImageNamedVariants, TypeImageStatus } from '../types/image.ts';
9
- import type { IImageSceneRecord } from '../types/imageScene.ts';
10
-
11
- import { DtoImageTransformOptions } from './imageTransformOptions.tsx';
12
-
13
8
  export interface IDtoOptionsImageView extends IDecoratorDtoOptions {}
14
9
 
15
10
  @Dto<IDtoOptionsImageView>()
@@ -29,27 +24,9 @@ export class DtoImageView {
29
24
  @Api.field(v.optional())
30
25
  height?: number;
31
26
 
32
- @Api.field(z.string())
33
- provider: string;
34
-
35
- @Api.field(z.string())
36
- clientName: string;
37
-
38
- @Api.field(v.optional())
39
- imageScene?: keyof IImageSceneRecord | string;
40
-
41
- @Api.field(v.optional(), z.string())
42
- status?: TypeImageStatus;
43
-
44
- @Api.field(v.optional())
45
- draftExpiresAt?: Date;
46
-
47
- @Api.field(v.optional())
48
- finalizedAt?: Date;
49
-
50
27
  @Api.field(v.optional())
51
- uploadedAt?: Date;
28
+ public?: boolean;
52
29
 
53
- @Api.field(v.optional(), z.record(z.string(), $schema(DtoImageTransformOptions)))
54
- variants?: IImageNamedVariants;
30
+ @Api.field(v.default(true))
31
+ signed: boolean;
55
32
  }
@@ -39,7 +39,7 @@ export class EntityImage extends EntityBase {
39
39
  height?: number;
40
40
 
41
41
  @Api.field(v.optional())
42
- requireSignedURLs?: boolean;
42
+ public?: boolean;
43
43
 
44
44
  @Api.field(v.optional(), z.record(z.string(), $schema(DtoImageTransformOptions)))
45
45
  variants?: IImageNamedVariants;
@@ -37,14 +37,19 @@ export type TypeImageVariantName = keyof IImageVariantNameRecord;
37
37
 
38
38
  export type IImageNamedVariants = Partial<Record<TypeImageVariantName, IImageTransformOptions>>;
39
39
 
40
- export type TypeImageDeliveryExpiry = Date | string | number;
40
+ export type TypeImageDirectUploadExpiry = Date | string | number;
41
41
 
42
42
  export type TypeImageStatus = 'draft' | 'ready' | 'expired';
43
43
 
44
44
  export interface IImageDeliveryOptions {
45
- signed?: boolean;
46
45
  expiresIn?: number;
47
- expiresAt?: TypeImageDeliveryExpiry;
46
+ audience?: boolean;
47
+ responseMode?: 'auto' | 'buffer' | 'url';
48
+ }
49
+
50
+ export interface IImageProviderDeliveryOptions {
51
+ protected: boolean;
52
+ expiresIn?: number;
48
53
  responseMode?: 'auto' | 'buffer' | 'url';
49
54
  }
50
55
 
@@ -73,7 +78,7 @@ export interface IImageUploadInput<TMeta extends TypeImageMeta = TypeImageMeta>
73
78
  filename?: string;
74
79
  contentType?: string;
75
80
  size?: number;
76
- requireSignedURLs?: boolean;
81
+ public?: boolean;
77
82
  meta?: TMeta;
78
83
  }
79
84
 
@@ -81,16 +86,16 @@ export interface IImageUploadUrlInput<TMeta extends TypeImageMeta = TypeImageMet
81
86
  url: string;
82
87
  filename?: string;
83
88
  contentType?: string;
84
- requireSignedURLs?: boolean;
89
+ public?: boolean;
85
90
  meta?: TMeta;
86
91
  }
87
92
 
88
93
  export interface IImageDirectUploadInput<TMeta extends TypeImageMeta = TypeImageMeta> {
89
94
  filename?: string;
90
95
  contentType?: string;
91
- requireSignedURLs?: boolean;
96
+ public?: boolean;
92
97
  meta?: TMeta;
93
- expiry?: TypeImageDeliveryExpiry;
98
+ expiry?: TypeImageDirectUploadExpiry;
94
99
  customId?: string;
95
100
  }
96
101
 
@@ -98,6 +103,7 @@ export interface IImageUploadContextResolved<TMeta extends TypeImageMeta = TypeI
98
103
  imageScene: keyof IImageSceneRecord;
99
104
  providerName: keyof IImageProviderRecord;
100
105
  clientName: string;
106
+ public?: boolean;
101
107
  meta?: TMeta;
102
108
  }
103
109
 
@@ -120,7 +126,7 @@ export interface IImageProviderResource<
120
126
  size?: number;
121
127
  width?: number;
122
128
  height?: number;
123
- requireSignedURLs?: boolean;
129
+ public?: boolean;
124
130
  variants?: IImageNamedVariants;
125
131
  meta?: TMeta;
126
132
  storagePath?: string;
@@ -163,21 +169,33 @@ export interface IImageFinalizeDirectUploadResult<
163
169
  TRaw = unknown,
164
170
  > extends IImageResource<TMeta, TRaw> {}
165
171
 
172
+ export interface IImageActionResponse {
173
+ id: TableIdentity;
174
+ filename?: string;
175
+ contentType?: string;
176
+ size?: number;
177
+ width?: number;
178
+ height?: number;
179
+ public?: boolean;
180
+ url: string;
181
+ signed: boolean;
182
+ }
183
+
184
+ export interface IImageDirectUploadResponse {
185
+ id: TableIdentity;
186
+ uploadUrl: string;
187
+ filename?: string;
188
+ public?: boolean;
189
+ }
190
+
166
191
  export interface IImageView {
167
192
  id: TableIdentity;
168
193
  url: string;
169
194
  filename?: string;
170
195
  width?: number;
171
196
  height?: number;
172
- provider: keyof IImageProviderRecord;
173
- clientName: string;
174
- imageScene?: keyof IImageSceneRecord | string;
175
- status?: TypeImageStatus;
176
- draftExpiresAt?: Date;
177
- finalizedAt?: Date;
178
- uploadedAt?: Date;
179
- variants?: IImageNamedVariants;
180
- signed?: boolean;
197
+ public?: boolean;
198
+ signed: boolean;
181
199
  }
182
200
 
183
201
  export interface IImageUploadOptions<
@@ -201,22 +219,11 @@ export interface IImageUploadPolicyResolved<
201
219
  mimeType: string;
202
220
  }
203
221
 
204
- export interface IImageUploadTokenPayload<
205
- TMeta extends TypeImageMeta = TypeImageMeta,
206
- > extends IImageUploadPolicyResolved<TMeta> {
207
- kind: 'imageUpload';
208
- }
209
-
210
- export interface IImageDirectUploadTokenPayload {
211
- kind: 'imageDirectUpload';
212
- resourceId: string;
213
- }
214
-
215
222
  export interface IImageDeliveryTokenPayload {
216
223
  kind: 'imageDelivery';
217
224
  imageId: TableIdentity;
218
225
  request: IImageVariantRequest;
219
- targetUrl: string;
226
+ audienceUserId?: TableIdentity;
220
227
  }
221
228
 
222
229
  declare module 'vona' {
@@ -4,8 +4,8 @@ import type { ServiceOnion, TypeOnionOptionsEnableSimple } from 'vona-module-a-o
4
4
  import type { EntityImage } from '../entity/image.ts';
5
5
  import type { EntityImageProvider } from '../entity/imageProvider.ts';
6
6
  import type {
7
- IImageDeliveryOptions,
8
7
  IImageDirectUploadInput,
8
+ IImageProviderDeliveryOptions,
9
9
  IImageDownloadResult,
10
10
  IImageNamedVariants,
11
11
  IImageProviderDirectUploadResource,
@@ -29,7 +29,7 @@ export interface IImageProviderClientRecord {
29
29
  export interface IImageProviderClientOptions {
30
30
  deliveryBaseUrl?: string;
31
31
  variants?: IImageNamedVariants;
32
- requireSignedURLs?: boolean;
32
+ public?: boolean;
33
33
  signedDeliveryKind?: 'proxy' | 'provider';
34
34
  }
35
35
 
@@ -108,14 +108,14 @@ export interface IImageProviderExecute<
108
108
  request: IImageVariantRequest,
109
109
  clientOptions: T,
110
110
  options: O,
111
- deliveryOptions?: IImageDeliveryOptions,
111
+ deliveryOptions?: IImageProviderDeliveryOptions,
112
112
  ): Promise<string>;
113
113
  download?(
114
114
  image: EntityImage,
115
115
  request: IImageVariantRequest,
116
116
  clientOptions: T,
117
117
  options: O,
118
- deliveryOptions?: IImageDeliveryOptions,
118
+ deliveryOptions?: IImageProviderDeliveryOptions,
119
119
  ): Promise<IImageDownloadResult>;
120
120
  }
121
121
 
@@ -32,6 +32,7 @@ export type TypeImageSceneOptionsMetaResolver = (
32
32
  export interface IDecoratorImageSceneOptions {
33
33
  provider?: TypeDecoratorImageSceneOptionsProvider;
34
34
  upload?: IImageSceneOptionsUpload;
35
+ public?: boolean;
35
36
  meta?: Record<string, any> | TypeImageSceneOptionsMetaResolver;
36
37
  }
37
38
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-image-cloudflare",
3
- "version": "5.0.4",
3
+ "version": "5.0.5",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "Vona Module"