cabloy 5.1.239 → 5.1.241

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 (51) hide show
  1. package/.cabloy-version +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/package.json +1 -1
  4. package/repo-docs/backend/openapi-guide.md +18 -0
  5. package/repo-docs/backend/rate-limit-guide.md +54 -9
  6. package/repo-e2e/specs/home-user-account.spec.ts +53 -8
  7. package/vona/packages-vona/vona/package.json +1 -1
  8. package/vona/pnpm-lock.yaml +16 -141
  9. package/vona/src/suite/a-commerce/modules/commerce-siteadmin/src/dto/operatorContext.ts +4 -1
  10. package/vona/src/suite/a-commerce/modules/commerce-siteadmin/src/service/operator.ts +1 -0
  11. package/vona/src/suite/a-commerce/modules/commerce-siteadmin/test/operatorAccess.test.ts +1 -0
  12. package/vona/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +1 -0
  13. package/vona/src/suite/a-home/modules/home-user/src/controller/passport.ts +1 -0
  14. package/vona/src/suite/a-home/modules/home-user/src/dto/accountCurrent.ts +3 -0
  15. package/vona/src/suite/a-home/modules/home-user/src/dto/accountProfileUpdate.ts +9 -2
  16. package/vona/src/suite/a-home/modules/home-user/src/dto/passportUser.ts +3 -0
  17. package/vona/src/suite/a-home/modules/home-user/src/entity/user.ts +3 -0
  18. package/vona/src/suite/a-home/modules/home-user/src/service/account.ts +7 -3
  19. package/vona/src/suite/a-home/modules/home-user/src/service/userAdapter.ts +1 -0
  20. package/vona/src/suite/a-home/modules/home-user/test/account.test.ts +133 -8
  21. package/vona/src/suite/a-home/modules/home-user/test/accountOpenapi.test.ts +32 -5
  22. package/vona/src/suite/a-home/modules/home-user/test/passport.test.ts +159 -1
  23. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  24. package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
  25. package/vona/src/suite-vendor/a-vona/modules/a-hmr/package.json +1 -1
  26. package/vona/src/suite-vendor/a-vona/modules/a-hmr/src/service/hmr.ts +5 -12
  27. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  28. package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +54 -8
  29. package/vona/src/suite-vendor/a-vona/modules/a-permission/test/permission.test.ts +228 -16
  30. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/package.json +1 -1
  31. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/.metadata/index.ts +26 -0
  32. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/bean/middlewareSystem.aggregate.ts +58 -0
  33. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/service/rateLimit.ts +25 -5
  34. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/types/rateLimit.ts +5 -0
  35. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/test/aggregate.test.ts +247 -0
  36. package/vona/src/suite-vendor/a-vona/modules/a-user/package.json +1 -1
  37. package/vona/src/suite-vendor/a-vona/modules/a-user/src/types/user.ts +1 -0
  38. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  39. package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/api/openapi/schemas.ts +68 -52
  40. package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/api/openapi/types.ts +530 -344
  41. package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/page/dashboard/controller.tsx +7 -1
  42. package/zova/src/suite/a-home/modules/home-api/src/api/openapi/types.ts +6 -1
  43. package/zova/src/suite/a-home/modules/home-base/src/config/locale/en-us.ts +1 -0
  44. package/zova/src/suite/a-home/modules/home-base/src/config/locale/zh-cn.ts +1 -0
  45. package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.user.tsx +1 -1
  46. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.user.tsx +3 -1
  47. package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +4 -0
  48. package/zova/src/suite/a-home/modules/home-user/src/config/locale/en-us.ts +1 -0
  49. package/zova/src/suite/a-home/modules/home-user/src/config/locale/zh-cn.ts +1 -0
  50. package/zova/src/suite/a-home/modules/home-user/src/model/account.ts +2 -1
  51. package/zova/src/suite/a-home/modules/home-user/src/page/account/controller.tsx +17 -3
@@ -0,0 +1,247 @@
1
+ import type { IMiddlewareSystemOptionsAggregate, RateLimitMode } from 'vona-module-a-ratelimit';
2
+
3
+ import assert from 'node:assert/strict';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { once } from 'node:events';
6
+ import { createServer } from 'node:http';
7
+ import { describe, it } from 'node:test';
8
+ import { setTimeout } from 'node:timers/promises';
9
+ import { cast, compose } from 'vona';
10
+ import { app } from 'vona-mock';
11
+ import { MiddlewareSystemAggregate, ServiceRateLimit } from 'vona-module-a-ratelimit';
12
+
13
+ const exemptPath = '/api/test/vona/performAction/rateLimitExempt';
14
+ const limitedPath = '/api/test/vona/performAction/rateLimit';
15
+
16
+ type AdmitCommand = (key: string, windowMs: string) => Promise<[number, number]>;
17
+
18
+ function createService(command: AdmitCommand) {
19
+ const service = app.bean._newBean(ServiceRateLimit);
20
+ Object.defineProperty(service, 'bean', {
21
+ value: { redis: { get: () => ({ rateLimitAdmit: command }) } },
22
+ });
23
+ return service;
24
+ }
25
+
26
+ type Request = (path: string, options?: RequestInit) => Promise<Response>;
27
+
28
+ async function withGate(
29
+ mode: RateLimitMode,
30
+ limit: number,
31
+ command: AdmitCommand,
32
+ fn: (request: Request) => Promise<void>,
33
+ ) {
34
+ await app.bean.executor.mockCtx(async () => {
35
+ const middleware = app.bean._newBean(MiddlewareSystemAggregate);
36
+ Object.defineProperty(middleware, 'scope', {
37
+ value: { service: { rateLimit: createService(command) } },
38
+ });
39
+ const policyName = `test-aggregate-${randomUUID()}`;
40
+ // Keep admission and its listener local; never patch the shared application chain.
41
+ const chain = compose([
42
+ (_ctx, next) => middleware.execute({ rateLimit: { mode, limit } }, next),
43
+ ...app.middleware,
44
+ ]);
45
+ const server = createServer((req, res) => {
46
+ void app.bean.executor
47
+ .newCtx(
48
+ () => {
49
+ app.ctx.onionsDynamic = {
50
+ interceptor: { 'a-ratelimit:rateLimit': { rateLimit: { name: policyName } } },
51
+ };
52
+ return cast(app).handleRequest(app.ctx, chain);
53
+ },
54
+ { dbInfo: { level: 0 }, innerAccess: false, req, res },
55
+ )
56
+ .catch(error => res.destroy(error));
57
+ });
58
+ try {
59
+ server.listen(0, '127.0.0.1');
60
+ await once(server, 'listening');
61
+ const address = server.address();
62
+ assert.ok(address && typeof address !== 'string');
63
+ await fn((path, options) =>
64
+ fetch(`http://127.0.0.1:${address.port}${path}`, {
65
+ ...options,
66
+ headers: { accept: 'application/json', ...options?.headers },
67
+ signal: AbortSignal.timeout(10_000),
68
+ }),
69
+ );
70
+ } finally {
71
+ await new Promise<void>((resolve, reject) => {
72
+ server.close(error => (error ? reject(error) : resolve()));
73
+ server.closeAllConnections();
74
+ });
75
+ const redis = app.bean.redis.get('limiter');
76
+ const prefix = redis.options.keyPrefix ?? '';
77
+ const keys = await redis.keys(`${prefix}rate-limit:v1:*:${encodeURIComponent(policyName)}:*`);
78
+ if (keys.length) await redis.del(...keys.map(key => key.slice(prefix.length)));
79
+ }
80
+ });
81
+ }
82
+
83
+ function counter(): AdmitCommand {
84
+ let current = 0;
85
+ return async () => [++current, 1_000];
86
+ }
87
+
88
+ describe('aggregate.test.ts', { concurrency: false }, () => {
89
+ it('shares an atomic Redis budget across request contexts and expires its counter', async () => {
90
+ const key = `test:aggregate:${randomUUID()}`;
91
+ const redis = cast(app.bean.redis.get('limiter'));
92
+ const keys: string[] = [];
93
+ // Isolate this test's bucket without changing the production key dimensions or TTL.
94
+ const service = createService((actualKey, windowMs) => {
95
+ keys.push(actualKey);
96
+ return redis.rateLimitAdmit(key, windowMs);
97
+ });
98
+ try {
99
+ const results = await Promise.all(
100
+ [0, 1, 2, 3].map(index =>
101
+ app.bean.executor.mockCtx(async () => {
102
+ app.ctx.req.url = `/aggregate-${index}`;
103
+ return service.admitAggregate({
104
+ mode: 'enforce',
105
+ limit: 2,
106
+ });
107
+ }),
108
+ ),
109
+ );
110
+ assert.equal(results.filter(result => result.allowed).length, 2);
111
+ assert.ok(keys.every(actualKey => /^rate-limit:aggregate:v1:\d+$/.test(actualKey)));
112
+ assert.equal(await redis.get(key), '4');
113
+ const ttl = await redis.pttl(key);
114
+ assert.ok(ttl > 0 && ttl <= 1_000);
115
+ await setTimeout(ttl + 20);
116
+ assert.equal(await redis.get(key), null);
117
+ await app.bean.executor.mockCtx(async () => {
118
+ const result = await service.admitAggregate({
119
+ mode: 'enforce',
120
+ limit: 2,
121
+ });
122
+ assert.equal(result.allowed, true);
123
+ assert.equal(result.remaining, 1);
124
+ });
125
+ } finally {
126
+ await redis.del(key);
127
+ }
128
+ });
129
+
130
+ it('counts health, preflight, unknown paths and identity-exempt actions in one HTTP budget', async () => {
131
+ await withGate('enforce', 3, counter(), async request => {
132
+ const health = await request('/health/live');
133
+ assert.equal(health.status, 200);
134
+ await health.text();
135
+ const preflight = await request('/aggregate-unknown', {
136
+ method: 'OPTIONS',
137
+ headers: { 'origin': 'https://example.test', 'access-control-request-method': 'GET' },
138
+ });
139
+ assert.notEqual(preflight.status, 429);
140
+ await preflight.text();
141
+ const unknown = await request(`/aggregate-unknown-${randomUUID()}`);
142
+ assert.equal(unknown.status, 404);
143
+ await unknown.text();
144
+ const rejected = await request(exemptPath);
145
+ assert.equal(rejected.status, 429);
146
+ assert.equal(rejected.headers.get('retry-after'), '1');
147
+ assert.equal(rejected.headers.get('ratelimit-limit'), null);
148
+ assert.deepEqual(await rejected.json(), { code: 429, message: 'Too Many Requests' });
149
+ });
150
+ });
151
+
152
+ it('observes excess requests without rejecting or replacing identity headers', async () => {
153
+ await withGate('observe', 1, counter(), async request => {
154
+ for (let index = 0; index < 2; index++) {
155
+ const response = await request(exemptPath);
156
+ assert.equal(response.status, 200);
157
+ assert.equal(response.headers.get('ratelimit-limit'), null);
158
+ assert.equal(response.headers.get('retry-after'), null);
159
+ await response.text();
160
+ }
161
+ });
162
+ await withGate('enforce', 100, counter(), async request => {
163
+ for (let index = 0; index < 2; index++) {
164
+ const response = await request(limitedPath);
165
+ assert.equal(response.status, 200);
166
+ assert.equal(response.headers.get('ratelimit-limit'), '2');
167
+ await response.text();
168
+ }
169
+ const response = await request(limitedPath);
170
+ assert.equal(response.status, 429);
171
+ assert.equal(response.headers.get('ratelimit-limit'), '2');
172
+ await response.text();
173
+ });
174
+ });
175
+
176
+ it('fails open only in observe mode and preserves HTTP 503 for HTML callers', async () => {
177
+ const unavailable: AdmitCommand = async () => {
178
+ throw new Error('redis unavailable');
179
+ };
180
+ await withGate('observe', 1, unavailable, async request => {
181
+ const response = await request('/health/live');
182
+ assert.equal(response.status, 200);
183
+ await response.text();
184
+ });
185
+ await withGate('enforce', 1, unavailable, async request => {
186
+ const response = await request(exemptPath, { headers: { accept: 'text/html' } });
187
+ assert.equal(response.status, 503);
188
+ assert.match(response.headers.get('content-type')!, /application\/json/);
189
+ assert.equal(response.headers.get('retry-after'), null);
190
+ assert.deepEqual(await response.json(), { code: 503, message: 'Service Unavailable' });
191
+ });
192
+ });
193
+
194
+ it('keeps competing gates and the shared application listener independent', async () => {
195
+ await Promise.all([
196
+ withGate(
197
+ 'enforce',
198
+ 1,
199
+ async () => [2, 1_000],
200
+ async request => {
201
+ const response = await request('/health/live');
202
+ assert.equal(response.status, 429);
203
+ await response.text();
204
+ const address = app.server.address();
205
+ assert.ok(address && typeof address !== 'string');
206
+ const shared = await fetch(`http://127.0.0.1:${address.port}/health/live`, {
207
+ signal: AbortSignal.timeout(10_000),
208
+ });
209
+ assert.equal(shared.status, 200);
210
+ await shared.text();
211
+ },
212
+ ),
213
+ withGate(
214
+ 'enforce',
215
+ 1,
216
+ async () => [1, 1_000],
217
+ async request => {
218
+ const response = await request('/health/live');
219
+ assert.equal(response.status, 200);
220
+ await response.text();
221
+ },
222
+ ),
223
+ ]);
224
+ });
225
+
226
+ it('requires valid explicit configuration even in observe mode', async () => {
227
+ await app.bean.executor.mockCtx(async () => {
228
+ const middleware = app.bean._newBean(MiddlewareSystemAggregate);
229
+ let downstream = false;
230
+ const next = async () => {
231
+ downstream = true;
232
+ };
233
+ for (const options of [
234
+ {},
235
+ { rateLimit: { mode: 'observe', limit: 0 } },
236
+ { rateLimit: { mode: 'observe', limit: 1.5 } },
237
+ { rateLimit: { mode: 'invalid', limit: 1 } },
238
+ ]) {
239
+ await assert.rejects(
240
+ middleware.execute(options as IMiddlewareSystemOptionsAggregate, next),
241
+ /rate-limit aggregate/,
242
+ );
243
+ }
244
+ assert.equal(downstream, false);
245
+ });
246
+ });
247
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-module-a-user",
3
- "version": "5.1.25",
3
+ "version": "5.1.26",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "keywords": [
@@ -16,6 +16,7 @@ export interface IUserIdRecord {
16
16
  export interface IUser {
17
17
  id: TableIdentity;
18
18
  name: string;
19
+ displayName?: string;
19
20
  avatar?: string;
20
21
  email?: string;
21
22
  mobile?: string;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-suite-a-vona",
3
- "version": "5.1.109",
3
+ "version": "5.1.111",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "",
6
6
  "author": "",
@@ -6,6 +6,42 @@ export type ApiSchemaTestVonaDtoUserCreate = components['schemas']['test-vona.dt
6
6
  export type ApiSchemaTestVonaDtoUserCreatePartial = Partial<ApiSchemaTestVonaDtoUserCreate>;
7
7
  export type ApiSchemaTestVonaEntityProduct = components['schemas']['test-vona.entity.product'];
8
8
  export type ApiSchemaTestVonaEntityProductPartial = Partial<ApiSchemaTestVonaEntityProduct>;
9
+ export type ApiSchemaAImageDtoImageUploadPolicyResponse =
10
+ components['schemas']['a-image.dto.imageUploadPolicyResponse'];
11
+ export type ApiSchemaAImageDtoImageUploadPolicyResponsePartial =
12
+ Partial<ApiSchemaAImageDtoImageUploadPolicyResponse>;
13
+ export type ApiSchemaAImageDtoImageUploadPolicyRequest =
14
+ components['schemas']['a-image.dto.imageUploadPolicyRequest'];
15
+ export type ApiSchemaAImageDtoImageUploadPolicyRequestPartial =
16
+ Partial<ApiSchemaAImageDtoImageUploadPolicyRequest>;
17
+ export type ApiSchemaAImageDtoImageUploadResponse =
18
+ components['schemas']['a-image.dto.imageUploadResponse'];
19
+ export type ApiSchemaAImageDtoImageUploadResponsePartial =
20
+ Partial<ApiSchemaAImageDtoImageUploadResponse>;
21
+ export type ApiSchemaAImageDtoImageDirectUploadResponse =
22
+ components['schemas']['a-image.dto.imageDirectUploadResponse'];
23
+ export type ApiSchemaAImageDtoImageDirectUploadResponsePartial =
24
+ Partial<ApiSchemaAImageDtoImageDirectUploadResponse>;
25
+ export type ApiSchemaAImageDtoImageDirectUploadRequest =
26
+ components['schemas']['a-image.dto.imageDirectUploadRequest'];
27
+ export type ApiSchemaAImageDtoImageDirectUploadRequestPartial =
28
+ Partial<ApiSchemaAImageDtoImageDirectUploadRequest>;
29
+ export type ApiSchemaAImageDtoImageDirectUploadFinalizeResponse =
30
+ components['schemas']['a-image.dto.imageDirectUploadFinalizeResponse'];
31
+ export type ApiSchemaAImageDtoImageDirectUploadFinalizeResponsePartial =
32
+ Partial<ApiSchemaAImageDtoImageDirectUploadFinalizeResponse>;
33
+ export type ApiSchemaAImageDtoImageDirectUploadFinalizeRequest =
34
+ components['schemas']['a-image.dto.imageDirectUploadFinalizeRequest'];
35
+ export type ApiSchemaAImageDtoImageDirectUploadFinalizeRequestPartial =
36
+ Partial<ApiSchemaAImageDtoImageDirectUploadFinalizeRequest>;
37
+ export type ApiSchemaAImageDtoImageUploadUrlRequest =
38
+ components['schemas']['a-image.dto.imageUploadUrlRequest'];
39
+ export type ApiSchemaAImageDtoImageUploadUrlRequestPartial =
40
+ Partial<ApiSchemaAImageDtoImageUploadUrlRequest>;
41
+ export type ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b =
42
+ components['schemas']['a-image.dto.imageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
43
+ export type ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
44
+ Partial<ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
9
45
  export type ApiSchemaACaptchaDtoCaptchaData = components['schemas']['a-captcha.dto.captchaData'];
10
46
  export type ApiSchemaACaptchaDtoCaptchaDataPartial = Partial<ApiSchemaACaptchaDtoCaptchaData>;
11
47
  export type ApiSchemaAPayDtoPaymentSessionView =
@@ -43,42 +79,6 @@ export type ApiSchemaCommerceMemberDtoAddressView_2d063d28bc7243bed02ebd8bddf121
43
79
  components['schemas']['commerce-member.dto.addressView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875'];
44
80
  export type ApiSchemaCommerceMemberDtoAddressView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875Partial =
45
81
  Partial<ApiSchemaCommerceMemberDtoAddressView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875>;
46
- export type ApiSchemaAImageDtoImageUploadPolicyResponse =
47
- components['schemas']['a-image.dto.imageUploadPolicyResponse'];
48
- export type ApiSchemaAImageDtoImageUploadPolicyResponsePartial =
49
- Partial<ApiSchemaAImageDtoImageUploadPolicyResponse>;
50
- export type ApiSchemaAImageDtoImageUploadPolicyRequest =
51
- components['schemas']['a-image.dto.imageUploadPolicyRequest'];
52
- export type ApiSchemaAImageDtoImageUploadPolicyRequestPartial =
53
- Partial<ApiSchemaAImageDtoImageUploadPolicyRequest>;
54
- export type ApiSchemaAImageDtoImageUploadResponse =
55
- components['schemas']['a-image.dto.imageUploadResponse'];
56
- export type ApiSchemaAImageDtoImageUploadResponsePartial =
57
- Partial<ApiSchemaAImageDtoImageUploadResponse>;
58
- export type ApiSchemaAImageDtoImageDirectUploadResponse =
59
- components['schemas']['a-image.dto.imageDirectUploadResponse'];
60
- export type ApiSchemaAImageDtoImageDirectUploadResponsePartial =
61
- Partial<ApiSchemaAImageDtoImageDirectUploadResponse>;
62
- export type ApiSchemaAImageDtoImageDirectUploadRequest =
63
- components['schemas']['a-image.dto.imageDirectUploadRequest'];
64
- export type ApiSchemaAImageDtoImageDirectUploadRequestPartial =
65
- Partial<ApiSchemaAImageDtoImageDirectUploadRequest>;
66
- export type ApiSchemaAImageDtoImageDirectUploadFinalizeResponse =
67
- components['schemas']['a-image.dto.imageDirectUploadFinalizeResponse'];
68
- export type ApiSchemaAImageDtoImageDirectUploadFinalizeResponsePartial =
69
- Partial<ApiSchemaAImageDtoImageDirectUploadFinalizeResponse>;
70
- export type ApiSchemaAImageDtoImageDirectUploadFinalizeRequest =
71
- components['schemas']['a-image.dto.imageDirectUploadFinalizeRequest'];
72
- export type ApiSchemaAImageDtoImageDirectUploadFinalizeRequestPartial =
73
- Partial<ApiSchemaAImageDtoImageDirectUploadFinalizeRequest>;
74
- export type ApiSchemaAImageDtoImageUploadUrlRequest =
75
- components['schemas']['a-image.dto.imageUploadUrlRequest'];
76
- export type ApiSchemaAImageDtoImageUploadUrlRequestPartial =
77
- Partial<ApiSchemaAImageDtoImageUploadUrlRequest>;
78
- export type ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b =
79
- components['schemas']['a-image.dto.imageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
80
- export type ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
81
- Partial<ApiSchemaAImageDtoImageTransformOptions_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
82
82
  export type ApiSchemaHomeUserDtoAccountCurrent =
83
83
  components['schemas']['home-user.dto.accountCurrent'];
84
84
  export type ApiSchemaHomeUserDtoAccountCurrentPartial = Partial<ApiSchemaHomeUserDtoAccountCurrent>;
@@ -302,10 +302,10 @@ export type ApiSchemaCommerceTradeEntityStockBalance =
302
302
  components['schemas']['commerce-trade.entity.stockBalance'];
303
303
  export type ApiSchemaCommerceTradeEntityStockBalancePartial =
304
304
  Partial<ApiSchemaCommerceTradeEntityStockBalance>;
305
- export type ApiSchemaCommerceTradeDtoStockAdjust_0aab216abd3467dd07f61c69172266c2441af477 =
306
- components['schemas']['commerce-trade.dto.stockAdjust_0aab216abd3467dd07f61c69172266c2441af477'];
307
- export type ApiSchemaCommerceTradeDtoStockAdjust_0aab216abd3467dd07f61c69172266c2441af477Partial =
308
- Partial<ApiSchemaCommerceTradeDtoStockAdjust_0aab216abd3467dd07f61c69172266c2441af477>;
305
+ export type ApiSchemaCommerceTradeDtoStockAdjust_6a7c2f0bb21a25da3048650f263577ae4467750e =
306
+ components['schemas']['commerce-trade.dto.stockAdjust_6a7c2f0bb21a25da3048650f263577ae4467750e'];
307
+ export type ApiSchemaCommerceTradeDtoStockAdjust_6a7c2f0bb21a25da3048650f263577ae4467750ePartial =
308
+ Partial<ApiSchemaCommerceTradeDtoStockAdjust_6a7c2f0bb21a25da3048650f263577ae4467750e>;
309
309
  export type ApiSchemaCommerceTradeDtoStockBalanceSelectRes =
310
310
  components['schemas']['commerce-trade.dto.stockBalanceSelectRes'];
311
311
  export type ApiSchemaCommerceTradeDtoStockBalanceSelectResPartial =
@@ -366,10 +366,10 @@ export type ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02eb
366
366
  components['schemas']['commerce-catalog.dto.productPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
367
367
  export type ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
368
368
  Partial<ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
369
- export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7 =
370
- components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7'];
371
- export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7Partial =
372
- Partial<ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7>;
369
+ export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57 =
370
+ components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57'];
371
+ export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57Partial =
372
+ Partial<ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57>;
373
373
  export type ApiSchemaCommerceCatalogDtoProductUpdate =
374
374
  components['schemas']['commerce-catalog.dto.productUpdate'];
375
375
  export type ApiSchemaCommerceCatalogDtoProductUpdatePartial =
@@ -435,10 +435,10 @@ export type ApiSchemaAImageDtoImageView = components['schemas']['a-image.dto.ima
435
435
  export type ApiSchemaAImageDtoImageViewPartial = Partial<ApiSchemaAImageDtoImageView>;
436
436
  export type ApiSchemaAFileDtoFileView = components['schemas']['a-file.dto.fileView'];
437
437
  export type ApiSchemaAFileDtoFileViewPartial = Partial<ApiSchemaAFileDtoFileView>;
438
- export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875 =
439
- components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875'];
440
- export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875Partial =
441
- Partial<ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875>;
438
+ export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347 =
439
+ components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347'];
440
+ export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347Partial =
441
+ Partial<ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347>;
442
442
  export type ApiSchemaTrainingRecordDtoRecordUpdate =
443
443
  components['schemas']['training-record.dto.recordUpdate'];
444
444
  export type ApiSchemaTrainingRecordDtoRecordUpdatePartial =
@@ -463,10 +463,10 @@ export type ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1
463
463
  components['schemas']['a-image.dto.imageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6'];
464
464
  export type ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6Partial =
465
465
  Partial<ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6>;
466
- export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4e7e5941f704425ce1be04de1885c36427ccc436 =
467
- components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4e7e5941f704425ce1be04de1885c36427ccc436'];
468
- export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4e7e5941f704425ce1be04de1885c36427ccc436Partial =
469
- Partial<ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4e7e5941f704425ce1be04de1885c36427ccc436>;
466
+ export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60 =
467
+ components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60'];
468
+ export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60Partial =
469
+ Partial<ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60>;
470
470
  export type ApiSchemaTrainingStudentDtoStudentUpdate =
471
471
  components['schemas']['training-student.dto.studentUpdate'];
472
472
  export type ApiSchemaTrainingStudentDtoStudentUpdatePartial =
@@ -475,6 +475,10 @@ export type ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bdd
475
475
  components['schemas']['training-student.dto.studentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
476
476
  export type ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
477
477
  Partial<ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
478
+ export type ApiSchemaTrainingStudentDtoStudentDeleteBulk =
479
+ components['schemas']['training-student.dto.studentDeleteBulk'];
480
+ export type ApiSchemaTrainingStudentDtoStudentDeleteBulkPartial =
481
+ Partial<ApiSchemaTrainingStudentDtoStudentDeleteBulk>;
478
482
  export type ApiSchemaBasicMetricsDtoMetricsSnapshot =
479
483
  components['schemas']['basic-metrics.dto.metricsSnapshot'];
480
484
  export type ApiSchemaBasicMetricsDtoMetricsSnapshotPartial =
@@ -487,6 +491,18 @@ export type ApiSchemaBasicMetricsDtoMetricsQueue =
487
491
  components['schemas']['basic-metrics.dto.metricsQueue'];
488
492
  export type ApiSchemaBasicMetricsDtoMetricsQueuePartial =
489
493
  Partial<ApiSchemaBasicMetricsDtoMetricsQueue>;
494
+ export type ApiSchemaALayoutprofileDtoLayoutProfile_2d063d28bc7243bed02ebd8bddf1212a93c6305b =
495
+ components['schemas']['a-layoutprofile.dto.layoutProfile_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
496
+ export type ApiSchemaALayoutprofileDtoLayoutProfile_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
497
+ Partial<ApiSchemaALayoutprofileDtoLayoutProfile_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
498
+ export type ApiSchemaALayoutprofileDtoLayoutProfile =
499
+ components['schemas']['a-layoutprofile.dto.layoutProfile'];
500
+ export type ApiSchemaALayoutprofileDtoLayoutProfilePartial =
501
+ Partial<ApiSchemaALayoutprofileDtoLayoutProfile>;
502
+ export type ApiSchemaALayoutprofileDtoLayoutProfileSave =
503
+ components['schemas']['a-layoutprofile.dto.layoutProfileSave'];
504
+ export type ApiSchemaALayoutprofileDtoLayoutProfileSavePartial =
505
+ Partial<ApiSchemaALayoutprofileDtoLayoutProfileSave>;
490
506
  export type ApiSchemaAFileDtoFileUploadPolicyResponse =
491
507
  components['schemas']['a-file.dto.fileUploadPolicyResponse'];
492
508
  export type ApiSchemaAFileDtoFileUploadPolicyResponsePartial =