cabloy 5.1.131 → 5.1.133

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 (210) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-worktree-environment/SKILL.md +6 -6
  3. package/.claude/skills/cabloy-worktree-environment/evals/evals.json +2 -2
  4. package/.github/workflows/vona-test-pg.yml +1 -1
  5. package/.github/workflows/vona-test-sqlite3.yml +1 -1
  6. package/CHANGELOG.md +28 -0
  7. package/cabloy-docs/backend/dto-guide.md +39 -4
  8. package/cabloy-docs/backend/dto-infer-generation.md +29 -0
  9. package/cabloy-docs/backend/openapi-guide.md +16 -0
  10. package/cabloy-docs/backend/validation-guide.md +45 -0
  11. package/cabloy-docs/frontend/environment-config-guide.md +8 -15
  12. package/cabloy-docs/frontend/navigation-guards-guide.md +3 -3
  13. package/cabloy-docs/frontend/page-route-guide.md +4 -4
  14. package/cabloy-docs/frontend/ssr-env.md +22 -29
  15. package/cabloy-docs/frontend/theme-guide.md +4 -4
  16. package/cabloy-docs/frontend/zova-router-under-the-hood.md +1 -1
  17. package/cabloy-docs/fullstack/deploy-cloudflare-docker.md +6 -6
  18. package/cabloy-docs/fullstack/parallel-worktree-environment.md +2 -2
  19. package/e2e/specs/a-commerce/commerce.spec.ts +479 -17
  20. package/e2e/specs/cabloy-basic/basic.spec.ts +30 -5
  21. package/package.json +7 -7
  22. package/vona/.claude/skills/detect-ssr-leak/SKILL.md +1 -1
  23. package/vona/packages-vona/vona/package.json +1 -1
  24. package/vona/pnpm-lock.yaml +120 -10
  25. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuCreate.tsx +3 -1
  26. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +13 -1
  27. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuUpdate.tsx +3 -1
  28. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuView.tsx +13 -1
  29. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/sku.tsx +6 -0
  30. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +227 -0
  31. package/vona/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +46 -36
  32. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressSelectResItem.tsx +5 -13
  33. package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +16 -1
  34. package/vona/src/suite/a-commerce/modules/commerce-member/test/addressPresentation.test.ts +210 -0
  35. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +13 -2
  36. package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +12 -0
  37. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/service/coupon.ts +7 -1
  38. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +45 -2
  39. package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +23 -0
  40. package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +23 -0
  41. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +31 -0
  42. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineBase.tsx +56 -0
  43. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineResItem.tsx +17 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineView.tsx +13 -0
  45. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +26 -2
  46. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderView.tsx +197 -3
  47. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryAction.tsx +19 -0
  48. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryView.tsx +70 -0
  49. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditSelectResItem.tsx +7 -1
  50. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditView.tsx +21 -1
  51. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceSelectResItem.tsx +7 -1
  52. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceView.tsx +3 -1
  53. package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/order.tsx +12 -0
  54. package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +15 -2
  55. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +215 -3
  56. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockAudit.ts +25 -2
  57. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockBalance.ts +14 -3
  58. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +4 -4
  59. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderPresentation.test.ts +358 -0
  60. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +8 -8
  61. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +5 -1
  62. package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +50 -1
  63. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockPresentation.test.ts +324 -0
  64. package/vona/src/suite/a-home/modules/home-base/package.json +3 -2
  65. package/vona/src/suite/a-home/modules/home-base/src/.metadata/index.ts +93 -16
  66. package/vona/src/suite/a-home/modules/home-base/src/controller/siteCatalog.ts +21 -0
  67. package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectRes.ts +11 -0
  68. package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectResItem.ts +15 -0
  69. package/vona/src/suite/a-home/modules/home-base/src/service/siteCatalog.ts +29 -0
  70. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +3 -0
  71. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/en-us.ts +1 -0
  72. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/zh-cn.ts +1 -0
  73. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +3 -0
  74. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/en-us.ts +1 -0
  75. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/zh-cn.ts +1 -0
  76. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +1 -0
  77. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
  78. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/env.ts +1 -3
  79. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +2 -1
  80. package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
  81. package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  82. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +67 -0
  83. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +1 -0
  84. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +5 -4
  85. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +8 -0
  86. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +22 -0
  87. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +1 -1
  88. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +6 -0
  89. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +3 -0
  90. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperationRecoveryAudit.tsx +53 -0
  91. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +6 -0
  92. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperationRecoveryAudit.ts +12 -0
  93. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +6 -2
  94. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +236 -30
  95. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +8 -5
  96. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +34 -0
  97. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +4 -0
  98. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +6 -0
  99. package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
  100. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +15 -7
  101. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +9 -5
  102. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
  103. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +289 -86
  104. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/paypalGateway.ts +9 -1
  105. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
  106. package/vona/src/suite-vendor/a-pay/package.json +5 -5
  107. package/vona/src/suite-vendor/a-vona/modules/a-openapi/package.json +1 -1
  108. package/vona/src/suite-vendor/a-vona/modules/a-openapi/src/types/rest.ts +1 -0
  109. package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
  110. package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/utils.ts +12 -0
  111. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  112. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoCreate.ts +5 -1
  113. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoUpdate.ts +5 -1
  114. package/vona/src/suite-vendor/a-vona/modules/a-validation/package.json +1 -1
  115. package/vona/src/suite-vendor/a-vona/modules/a-validation/src/bean/bean.validator.ts +60 -1
  116. package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
  117. package/vona/src/suite-vendor/a-vona/modules/a-web/src/lib/decorator/bean.ts +7 -4
  118. package/vona/src/suite-vendor/a-vona/modules/a-web/src/types/dto.ts +2 -1
  119. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  120. package/zova/env/.env +3 -5
  121. package/zova/env/.env.cabloyBasicAdmin +1 -4
  122. package/zova/env/.env.cabloyBasicWeb +1 -5
  123. package/zova/env/.env.cabloyCommerce +1 -5
  124. package/zova/env/.env.cabloyCommerceAdmin +1 -4
  125. package/zova/env/.env.ssr.admin +1 -4
  126. package/zova/env/.env.ssr.web +1 -5
  127. package/zova/package.original.json +1 -1
  128. package/zova/packages-utils/zova-jsx/package.json +2 -2
  129. package/zova/packages-zova/zova/package.json +3 -3
  130. package/zova/packages-zova/zova-core/package.json +2 -1
  131. package/zova/packages-zova/zova-core/src/core/component/locale.ts +10 -4
  132. package/zova/packages-zova/zova-core/src/core/sys/config.ts +14 -6
  133. package/zova/packages-zova/zova-core/src/types/utils/env.ts +4 -2
  134. package/zova/pnpm-lock.yaml +24 -21
  135. package/zova/src/front/config/config/config.ts +22 -7
  136. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/routes.ts +2 -2
  137. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +16 -8
  138. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +150 -216
  139. package/zova/src/suite/a-commerce/modules/commerce-member/src/model/addressMine.ts +1 -2
  140. package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +5 -8
  141. package/zova/src/suite/a-commerce/modules/commerce-member/src/routes.ts +1 -1
  142. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/model/coupon.ts +1 -2
  143. package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/routes.ts +3 -1
  144. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +3 -0
  145. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +72 -0
  146. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +8 -0
  147. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +226 -16
  148. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +15 -0
  149. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +155 -36
  150. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +7 -0
  151. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +7 -0
  152. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/cart.ts +3 -4
  153. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +42 -0
  154. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +2 -4
  155. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +5 -1
  156. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +14 -10
  157. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +5 -8
  158. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +5 -8
  159. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +151 -24
  160. package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +5 -5
  161. package/zova/src/suite/a-demo/modules/demo-basic/src/routes.ts +26 -7
  162. package/zova/src/suite/a-demo/modules/demo-todo/src/routes.ts +2 -2
  163. package/zova/src/suite/a-devui/modules/devui-adapter/src/bean/meta.themeHandler.ts +1 -1
  164. package/zova/src/suite/a-home/modules/home-base/package.json +1 -0
  165. package/zova/src/suite/a-home/modules/home-base/src/routes.ts +5 -0
  166. package/zova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts +1 -1
  167. package/zova/src/suite/a-home/modules/home-base/src/service/ssrLayout.ts +18 -14
  168. package/zova/src/suite/a-home/modules/home-indexadmin/src/routes.ts +1 -1
  169. package/zova/src/suite/a-home/modules/home-indexweb/src/routes.ts +1 -0
  170. package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +12 -4
  171. package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts +8 -0
  172. package/zova/src/suite/a-home/modules/home-layoutadmin/src/model/layout.ts +5 -8
  173. package/zova/src/suite/a-home/modules/home-layoutempty/src/.metadata/index.ts +10 -3
  174. package/zova/src/suite/a-home/modules/home-layoutempty/src/component/layoutEmpty/controller.tsx +9 -3
  175. package/zova/src/suite/a-home/modules/home-layoutempty/src/config/config.ts +12 -0
  176. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +13 -8
  177. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +1 -1
  178. package/zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts +4 -0
  179. package/zova/src/suite/a-home/modules/home-layoutweb/src/model/layout.ts +5 -8
  180. package/zova/src/suite/a-home/modules/home-login/src/routes.ts +1 -0
  181. package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -3
  182. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/routes.ts +3 -1
  183. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  184. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +1 -1
  185. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.ts +3 -0
  186. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  187. package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  188. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +2 -2
  189. package/zova/src/suite-vendor/a-pay/package.json +2 -2
  190. package/zova/src/suite-vendor/a-zova/modules/a-interceptor/package.json +1 -1
  191. package/zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.jwt.ts +1 -1
  192. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  193. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +1 -1
  194. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +1 -0
  195. package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
  196. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/config/config.ts +1 -17
  197. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/bodyReadyObserver.ts +27 -0
  198. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/index.ts +2 -0
  199. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +33 -0
  200. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrMetaStore.ts +3 -35
  201. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrProfile.ts +38 -0
  202. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/monkey.ts +10 -0
  203. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/config.ts +3 -10
  204. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/ssr.ts +17 -8
  205. package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/package.json +1 -1
  206. package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/src/service/ssrHandler.ts +33 -18
  207. package/zova/src/suite-vendor/a-zova/modules/a-style/package.json +1 -1
  208. package/zova/src/suite-vendor/a-zova/modules/a-style/src/bean/bean.theme.ts +2 -2
  209. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  210. package/zova/src/suite-vendor/a-zova/package.json +7 -7
@@ -39,6 +39,9 @@ async function loginAsAdmin(page: Page) {
39
39
  }
40
40
 
41
41
  await expect(page.locator('html')).toHaveAttribute('data-zova-hydrated', 'admin');
42
+ const dashboardResponse = await page.goto('/admin/', { waitUntil: 'load' });
43
+ await expect(page.locator('html')).toHaveAttribute('data-zova-hydrated', 'admin');
44
+ return dashboardResponse;
42
45
  }
43
46
 
44
47
  function waitForStudentSelect(page: Page) {
@@ -112,7 +115,15 @@ test(
112
115
  async ({ page, request }) => {
113
116
  const response = await request.get('/');
114
117
  expect(response.ok()).toBeTruthy();
115
- expect((await response.text()).toLowerCase()).not.toContain('data-zova-hydrated');
118
+ expect(response.headers()['cache-control']).toBe('public, max-age=600');
119
+ const html = await response.text();
120
+ expect(html.toLowerCase()).not.toContain('data-zova-hydrated');
121
+ expect(html).not.toContain('ssr-body-ready-observer');
122
+ expect(html).not.toContain('__leftDrawerOpenJS');
123
+
124
+ const routeOverrideResponse = await request.get('/demo/basic/routeQueryB');
125
+ expect(routeOverrideResponse.ok()).toBeTruthy();
126
+ expect(routeOverrideResponse.headers()['cache-control']).toBe('public, max-age=300');
116
127
 
117
128
  const pageErrors = collectPageErrors(page);
118
129
  const documentResponse = await page.goto('/', { waitUntil: 'load' });
@@ -133,12 +144,16 @@ test(
133
144
  async ({ page, request }) => {
134
145
  const response = await request.get('/admin/', { maxRedirects: 0 });
135
146
  expect(response.status()).toBe(302);
147
+ expect(response.headers()['cache-control']).toBe('private, no-store');
136
148
  const loginPath = response.headers().location;
137
149
  expect(loginPath).toMatch(/^\/admin\/login(?:\?|$)/);
138
150
 
139
151
  const loginResponse = await request.get(loginPath!);
140
152
  expect(loginResponse.ok()).toBeTruthy();
141
- expect((await loginResponse.text()).toLowerCase()).not.toContain('data-zova-hydrated');
153
+ const loginHtml = await loginResponse.text();
154
+ expect(loginHtml.toLowerCase()).not.toContain('data-zova-hydrated');
155
+ expect(loginHtml).not.toContain('ssr-body-ready-observer');
156
+ expect(loginHtml).not.toContain('__leftDrawerOpenJS');
142
157
 
143
158
  let releaseRequest: (() => void) | undefined;
144
159
  const requestHeld = new Promise<void>(resolve => {
@@ -190,7 +205,13 @@ test(
190
205
  await page.setViewportSize({ width: 1440, height: 900 });
191
206
  const pageErrors = collectPageErrors(page);
192
207
 
193
- await loginAsAdmin(page);
208
+ const dashboardResponse = await loginAsAdmin(page);
209
+ expect(dashboardResponse?.ok()).toBeTruthy();
210
+ expect(dashboardResponse?.headers()['cache-control']).toBe('private, no-store');
211
+ const dashboardHtml = await dashboardResponse!.text();
212
+ expect(dashboardHtml).toMatch(/<body[^>]+style="[^"]*display:none;/);
213
+ expect(dashboardHtml).toContain('__leftDrawerOpenJS');
214
+ expect(dashboardHtml).toContain('ssr-body-ready-observer');
194
215
 
195
216
  const initialSelect = waitForStudentSelect(page);
196
217
  await page.getByRole('link', { name: 'Student', exact: true }).click();
@@ -233,8 +254,10 @@ test(
233
254
  });
234
255
  expect(actionFlowMatchesFieldFlow).toBeTruthy();
235
256
 
236
- await page.setViewportSize({ width: 700, height: 900 });
237
257
  const drawer = page.locator('.drawer').first();
258
+ await expect(drawer).toHaveClass(/\bdrawer-open\b/);
259
+
260
+ await page.setViewportSize({ width: 1023, height: 900 });
238
261
  await expect(drawer).not.toHaveClass(/\bdrawer-open\b/);
239
262
  await expect
240
263
  .poll(
@@ -259,8 +282,10 @@ test(
259
282
  expect(createdAtEndBox!.x + createdAtEndBox!.width).toBeLessThanOrEqual(viewport.width + 1);
260
283
  await expect.poll(() => getDocumentHorizontalOverflow(page)).toBeLessThanOrEqual(1);
261
284
 
262
- await page.setViewportSize({ width: 1440, height: 900 });
285
+ await page.setViewportSize({ width: 1024, height: 900 });
263
286
  await expect(drawer).toHaveClass(/\bdrawer-open\b/);
287
+
288
+ await page.setViewportSize({ width: 1440, height: 900 });
264
289
  await name.fill('Flow E2E');
265
290
  await level.selectOption('2');
266
291
  await createdAtStart.fill('2026-01-10');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.131",
3
+ "version": "5.1.133",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -61,8 +61,8 @@
61
61
  "deps:zova": "pnpm --dir zova run zova :tools:deps",
62
62
  "format": "oxfmt --check",
63
63
  "format:fix": "oxfmt --write",
64
- "lint": "oxlint",
65
- "lint:fix": "oxlint --fix",
64
+ "lint": "oxlint --disable-nested-config",
65
+ "lint:fix": "oxlint --disable-nested-config --fix",
66
66
  "docs:dev": "pnpm --dir cabloy-docs docs:dev",
67
67
  "docs:build": "pnpm --dir cabloy-docs docs:build",
68
68
  "docs:preview": "pnpm --dir cabloy-docs docs:preview",
@@ -79,13 +79,13 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cabloy/dotenv": "^1.2.8",
82
- "@cabloy/lint": "^5.1.27",
82
+ "@cabloy/lint": "^5.1.31",
83
83
  "@cabloy/process-helper": "^3.1.3",
84
- "@playwright/test": "^1.61.1",
84
+ "@playwright/test": "^1.62.1",
85
85
  "@types/fs-extra": "^11.0.4",
86
- "@types/node": "^22.19.17",
86
+ "@types/node": "^26.1.2",
87
87
  "husky": "^9.1.7",
88
- "lerna": "^9.0.7",
88
+ "lerna": "^10.0.0",
89
89
  "lint-staged": "^17.0.5",
90
90
  "minimist": "^1.2.8",
91
91
  "oxfmt": "^0.62.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: detect-ssr-leak
3
- description: Detect server-side memory leaks in Node.js SSR services. Use when user asks to "check for memory leak", "detect leak", "SSR memory leak", "内存泄漏", or wants to diagnose growing memory usage on a Node.js server. TRIGGER when user mentions memory leak detection, especially for SSR/Vue/React server-side rendering.
3
+ description: Detect server-side memory leaks in Node.js SSR services. Use when user asks to "check for memory leak", "detect leak", "SSR memory leak", "memory leak", or wants to diagnose growing memory usage on a Node.js server. TRIGGER when user mentions memory leak detection, especially for SSR/Vue/React server-side rendering.
4
4
  allowed-tools: Bash(fetch *) Bash(curl *) Bash(ps *) Bash(node *) Bash(npm *) Bash(npx *) Bash(pkill *) Bash(kill *) Bash(lsof *) Bash(wc *) Bash(ls *) Bash(rm *) Bash(cat *) Bash(mkdir *) Bash(cp *) Bash(sleep *)
5
5
  ---
6
6
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona",
3
- "version": "5.1.85",
3
+ "version": "5.1.86",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "Vona is an intuitive, elegant and powerful Node.js framework for rapidly developing enterprise applications of any size",
6
6
  "keywords": [
@@ -24,7 +24,7 @@ importers:
24
24
  dependencies:
25
25
  '@babel/core':
26
26
  specifier: ^7.29.0
27
- version: 7.29.7
27
+ version: 7.29.7(supports-color@5.5.0)
28
28
  '@babel/traverse':
29
29
  specifier: ^7.29.0
30
30
  version: 7.29.7
@@ -69,7 +69,7 @@ importers:
69
69
  version: 8.0.1
70
70
  bullmq:
71
71
  specifier: ^5.74.1
72
- version: 5.79.1
72
+ version: 5.79.1(supports-color@5.5.0)
73
73
  chalk:
74
74
  specifier: ^5.6.2
75
75
  version: 5.6.2
@@ -81,7 +81,7 @@ importers:
81
81
  version: 11.3.5
82
82
  ioredis:
83
83
  specifier: ^5.10.1
84
- version: 5.11.1
84
+ version: 5.11.1(supports-color@5.5.0)
85
85
  knex:
86
86
  specifier: ^3.3.0
87
87
  version: 3.3.0(better-sqlite3@12.11.1)
@@ -463,6 +463,9 @@ importers:
463
463
  zova-rest-cabloy-commerce-admin:
464
464
  specifier: workspace:^
465
465
  version: link:.zova-rest/cabloy-commerce-admin
466
+ zova-rest-cabloy-commerce-member:
467
+ specifier: workspace:^
468
+ version: link:.zova-rest/cabloy-commerce-member
466
469
  devDependencies:
467
470
  '@cabloy/cli':
468
471
  specifier: workspace:^
@@ -852,6 +855,84 @@ importers:
852
855
  specifier: ^5.1.42
853
856
  version: 5.1.42
854
857
 
858
+ .zova-rest/cabloy-commerce-member:
859
+ dependencies:
860
+ '@tanstack/query-core':
861
+ specifier: ^5.101.1
862
+ version: 5.101.2
863
+ '@tanstack/vue-query':
864
+ specifier: ^5.101.1
865
+ version: 5.101.2(vue@3.5.39(typescript@5.9.3))
866
+ openapi3-ts:
867
+ specifier: ^4.6.0
868
+ version: 4.6.0
869
+ table-identity:
870
+ specifier: ^1.1.7
871
+ version: link:../../packages-utils/table-identity
872
+ vue:
873
+ specifier: ^3.5.38
874
+ version: 3.5.39(typescript@5.9.3)
875
+ zod:
876
+ specifier: npm:@cabloy/zod@4.3.8
877
+ version: '@cabloy/zod@4.3.8'
878
+ zova:
879
+ specifier: ^5.1.145
880
+ version: 5.1.145(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3))
881
+ zova-jsx:
882
+ specifier: ^1.1.82
883
+ version: 1.1.82(typescript@5.9.3)
884
+ zova-module-a-api:
885
+ specifier: ^5.1.21
886
+ version: 5.1.21
887
+ zova-module-a-bean:
888
+ specifier: ^5.1.32
889
+ version: 5.1.32
890
+ zova-module-a-behavior:
891
+ specifier: ^5.1.25
892
+ version: 5.1.25
893
+ zova-module-a-command:
894
+ specifier: ^5.1.33
895
+ version: 5.1.33
896
+ zova-module-a-form:
897
+ specifier: ^5.1.46
898
+ version: 5.1.46(vue@3.5.39(typescript@5.9.3))
899
+ zova-module-a-icon:
900
+ specifier: ^5.1.26
901
+ version: 5.1.26
902
+ zova-module-a-interceptor:
903
+ specifier: ^5.1.29
904
+ version: 5.1.29
905
+ zova-module-a-model:
906
+ specifier: ^5.1.33
907
+ version: 5.1.33(vue@3.5.39(typescript@5.9.3))
908
+ zova-module-a-openapi:
909
+ specifier: ^5.1.47
910
+ version: 5.1.47
911
+ zova-module-a-pay:
912
+ specifier: ^5.0.3
913
+ version: 5.0.3
914
+ zova-module-a-router:
915
+ specifier: ^5.1.31
916
+ version: 5.1.31
917
+ zova-module-a-routertabs:
918
+ specifier: ^5.1.33
919
+ version: 5.1.33
920
+ zova-module-a-ssr:
921
+ specifier: ^5.1.32
922
+ version: 5.1.32
923
+ zova-module-a-style:
924
+ specifier: ^5.1.32
925
+ version: 5.1.32
926
+ zova-module-a-table:
927
+ specifier: ^5.1.37
928
+ version: 5.1.37(vue@3.5.39(typescript@5.9.3))
929
+ zova-module-pay-mock:
930
+ specifier: ^5.0.2
931
+ version: 5.0.2
932
+ zova-module-rest-resource:
933
+ specifier: ^5.1.42
934
+ version: 5.1.42
935
+
855
936
  packages-cli/cabloy-cli:
856
937
  dependencies:
857
938
  '@babel/parser':
@@ -2756,7 +2837,7 @@ importers:
2756
2837
  dependencies:
2757
2838
  bullmq:
2758
2839
  specifier: ^5.74.1
2759
- version: 5.79.1
2840
+ version: 5.79.1(supports-color@5.5.0)
2760
2841
  devDependencies:
2761
2842
  clean-package:
2762
2843
  specifier: ^2.2.0
@@ -2778,7 +2859,7 @@ importers:
2778
2859
  dependencies:
2779
2860
  ioredis:
2780
2861
  specifier: ^5.10.1
2781
- version: 5.11.1
2862
+ version: 5.11.1(supports-color@5.5.0)
2782
2863
  devDependencies:
2783
2864
  clean-package:
2784
2865
  specifier: ^2.2.0
@@ -8970,6 +9051,26 @@ snapshots:
8970
9051
  transitivePeerDependencies:
8971
9052
  - supports-color
8972
9053
 
9054
+ '@babel/core@7.29.7(supports-color@5.5.0)':
9055
+ dependencies:
9056
+ '@babel/code-frame': 7.29.7
9057
+ '@babel/generator': 7.29.7
9058
+ '@babel/helper-compilation-targets': 7.29.7
9059
+ '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@5.5.0))
9060
+ '@babel/helpers': 7.29.7
9061
+ '@babel/parser': 7.29.7
9062
+ '@babel/template': 7.29.7
9063
+ '@babel/traverse': 7.29.7
9064
+ '@babel/types': 7.29.7
9065
+ '@jridgewell/remapping': 2.3.5
9066
+ convert-source-map: 2.0.0
9067
+ debug: 4.4.3(supports-color@5.5.0)
9068
+ gensync: 1.0.0-beta.2
9069
+ json5: 2.2.3
9070
+ semver: 6.3.1
9071
+ transitivePeerDependencies:
9072
+ - supports-color
9073
+
8973
9074
  '@babel/generator@7.29.7':
8974
9075
  dependencies:
8975
9076
  '@babel/parser': 7.29.7
@@ -9019,6 +9120,15 @@ snapshots:
9019
9120
  transitivePeerDependencies:
9020
9121
  - supports-color
9021
9122
 
9123
+ '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@5.5.0))':
9124
+ dependencies:
9125
+ '@babel/core': 7.29.7(supports-color@5.5.0)
9126
+ '@babel/helper-module-imports': 7.29.7
9127
+ '@babel/helper-validator-identifier': 7.29.7
9128
+ '@babel/traverse': 7.29.7
9129
+ transitivePeerDependencies:
9130
+ - supports-color
9131
+
9022
9132
  '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
9023
9133
  dependencies:
9024
9134
  '@babel/core': 7.29.7
@@ -9985,7 +10095,7 @@ snapshots:
9985
10095
 
9986
10096
  '@sesamecare-oss/redlock@1.4.0(ioredis@5.11.1)':
9987
10097
  dependencies:
9988
- ioredis: 5.11.1
10098
+ ioredis: 5.11.1(supports-color@5.5.0)
9989
10099
 
9990
10100
  '@sindresorhus/merge-streams@2.3.0': {}
9991
10101
 
@@ -10891,10 +11001,10 @@ snapshots:
10891
11001
  base64-js: 1.5.1
10892
11002
  ieee754: 1.2.1
10893
11003
 
10894
- bullmq@5.79.1:
11004
+ bullmq@5.79.1(supports-color@5.5.0):
10895
11005
  dependencies:
10896
11006
  cron-parser: 4.9.0
10897
- ioredis: 5.10.1
11007
+ ioredis: 5.10.1(supports-color@5.5.0)
10898
11008
  msgpackr: 2.0.2
10899
11009
  node-abort-controller: 3.1.1
10900
11010
  semver: 7.8.1
@@ -12040,7 +12150,7 @@ snapshots:
12040
12150
 
12041
12151
  interpret@2.2.0: {}
12042
12152
 
12043
- ioredis@5.10.1:
12153
+ ioredis@5.10.1(supports-color@5.5.0):
12044
12154
  dependencies:
12045
12155
  '@ioredis/commands': 1.5.1
12046
12156
  cluster-key-slot: 1.1.2
@@ -12054,7 +12164,7 @@ snapshots:
12054
12164
  transitivePeerDependencies:
12055
12165
  - supports-color
12056
12166
 
12057
- ioredis@5.11.1:
12167
+ ioredis@5.11.1(supports-color@5.5.0):
12058
12168
  dependencies:
12059
12169
  '@ioredis/commands': 1.10.0
12060
12170
  cluster-key-slot: 1.1.1
@@ -25,4 +25,6 @@ export interface IDtoOptionsSkuCreate extends IDecoratorDtoOptions {}
25
25
  }),
26
26
  ],
27
27
  })
28
- export class DtoSkuCreate extends $Dto.create(() => ModelSku) {}
28
+ export class DtoSkuCreate extends $Dto.create(() => ModelSku, {
29
+ columns: ['code', 'productId', 'priceCents', 'lifecycle'],
30
+ }) {}
@@ -46,7 +46,19 @@ export interface IDtoOptionsSkuSelectResItem extends IDecoratorDtoOptions {}
46
46
  }),
47
47
  ],
48
48
  })
49
- export class DtoSkuSelectResItem extends $Dto.get(() => ModelSku) {
49
+ export class DtoSkuSelectResItem extends $Dto.get(() => ModelSku, {
50
+ columns: [
51
+ 'id',
52
+ 'code',
53
+ 'productId',
54
+ 'priceCents',
55
+ 'lifecycle',
56
+ 'iid',
57
+ 'deleted',
58
+ 'createdAt',
59
+ 'updatedAt',
60
+ ],
61
+ }) {
50
62
  @Api.field(
51
63
  v.title($locale('Operations')),
52
64
  ZovaRender.order(1, 'max'),
@@ -25,4 +25,6 @@ export interface IDtoOptionsSkuUpdate extends IDecoratorDtoOptions {}
25
25
  }),
26
26
  ],
27
27
  })
28
- export class DtoSkuUpdate extends $Dto.update(() => ModelSku) {}
28
+ export class DtoSkuUpdate extends $Dto.update(() => ModelSku, {
29
+ columns: ['code', 'productId', 'priceCents', 'lifecycle'],
30
+ }) {}
@@ -22,4 +22,16 @@ export interface IDtoOptionsSkuView extends IDecoratorDtoOptions {}
22
22
  }),
23
23
  ],
24
24
  })
25
- export class DtoSkuView extends $Dto.get(() => ModelSku) {}
25
+ export class DtoSkuView extends $Dto.get(() => ModelSku, {
26
+ columns: [
27
+ 'id',
28
+ 'code',
29
+ 'productId',
30
+ 'priceCents',
31
+ 'lifecycle',
32
+ 'iid',
33
+ 'deleted',
34
+ 'createdAt',
35
+ 'updatedAt',
36
+ ],
37
+ }) {}
@@ -9,6 +9,8 @@ import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
9
9
  import { $locale } from '../.metadata/locales.ts';
10
10
  import { DtoSkuAttribute } from '../dto/skuAttribute.tsx';
11
11
 
12
+ const currencyRendererOptions = { fixed: 2, exp: 2, zero: 2 };
13
+
12
14
  export const skuLifecycleItems = [
13
15
  { value: 'draft', title: $locale('SkuLifecycleDraft') },
14
16
  { value: 'active', title: $locale('SkuLifecycleActive') },
@@ -53,6 +55,8 @@ export class EntitySku extends EntityBase {
53
55
  v.title($locale('PriceCents')),
54
56
  v.required(),
55
57
  ZovaRender.order(3),
58
+ ZovaRender.field('basic-currency:formFieldCurrency', currencyRendererOptions),
59
+ ZovaRender.cell('basic-currency:currency', currencyRendererOptions),
56
60
  z.number().int().nonnegative(),
57
61
  )
58
62
  priceCents: number;
@@ -69,6 +73,8 @@ export class EntitySku extends EntityBase {
69
73
  v.title($locale('SkuLifecycle')),
70
74
  v.default('draft'),
71
75
  ZovaRender.order(5),
76
+ ZovaRender.field('basic-select:formFieldSelect', { items: skuLifecycleItems }),
77
+ ZovaRender.cell('basic-select:select', { items: skuLifecycleItems }),
72
78
  z.enum(['draft', 'active', 'inactive', 'archived']),
73
79
  )
74
80
  lifecycle: 'draft' | 'active' | 'inactive' | 'archived';
@@ -0,0 +1,227 @@
1
+ import assert from 'node:assert';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { describe, it } from 'node:test';
4
+ import { app } from 'vona-mock';
5
+ import {
6
+ DtoSkuCreate,
7
+ DtoSkuSelectResItem,
8
+ DtoSkuUpdate,
9
+ DtoSkuView,
10
+ } from 'vona-module-commerce-catalog';
11
+
12
+ function findComponent(apiJson: any, predicate: (properties: any) => boolean) {
13
+ return Object.values(apiJson.components!.schemas as any).find(item => {
14
+ return predicate((item as any).properties);
15
+ }) as any;
16
+ }
17
+
18
+ function getEntryForm(component: any) {
19
+ const pageEntry = component?.rest?.blocks?.[0];
20
+ const formBlock = pageEntry?.options?.blocks?.[0];
21
+ const toolbarBlock = pageEntry?.options?.blocks?.[1];
22
+ assert.equal(pageEntry?.render, 'basic-pageentry:blockPageEntry');
23
+ assert.equal(formBlock?.render, 'basic-pageentry:blockForm');
24
+ assert.equal(toolbarBlock?.render, 'basic-pageentry:blockToolbarRow');
25
+ return toolbarBlock;
26
+ }
27
+
28
+ function assertLifecycleItems(items: any[]) {
29
+ assert.deepEqual(
30
+ items.map(item => item.value),
31
+ ['draft', 'active', 'inactive', 'archived'],
32
+ );
33
+ for (const item of items) assert.ok(item.title);
34
+ }
35
+
36
+ describe('skuPresentation.test.ts', () => {
37
+ it('action:sku:presentationMetadata', async () => {
38
+ await app.bean.executor.mockCtx(async () => {
39
+ const currencyOptions = { fixed: 2, exp: 2, zero: 2 };
40
+
41
+ const createJson = await app.bean.openapi.generateJsonOfClass(DtoSkuCreate);
42
+ const createComponent = findComponent(createJson, properties => {
43
+ return properties?.code && properties?.productId && properties?.priceCents;
44
+ });
45
+ assert.deepEqual(Object.keys(createComponent.properties).sort(), [
46
+ 'code',
47
+ 'lifecycle',
48
+ 'priceCents',
49
+ 'productId',
50
+ ]);
51
+ assert.equal(createComponent.properties.attributes, undefined);
52
+ assert.equal(createComponent.properties.product, undefined);
53
+ assert.equal(
54
+ createComponent.properties.priceCents.rest.form.render,
55
+ 'basic-currency:formFieldCurrency',
56
+ );
57
+ assert.deepEqual(createComponent.properties.priceCents.rest.form.options, currencyOptions);
58
+ assert.equal(
59
+ createComponent.properties.priceCents.rest.table.render,
60
+ 'basic-currency:currency',
61
+ );
62
+ assert.deepEqual(
63
+ createComponent.properties.priceCents.rest.table.columnProps,
64
+ currencyOptions,
65
+ );
66
+ assert.equal(
67
+ createComponent.properties.lifecycle.rest.form.render,
68
+ 'basic-select:formFieldSelect',
69
+ );
70
+ assertLifecycleItems(createComponent.properties.lifecycle.rest.form.options.items);
71
+ const createToolbar = getEntryForm(createComponent);
72
+ assert.deepEqual(
73
+ createToolbar.options.actions.map((action: any) => action.render),
74
+ ['basic-form:actionSubmit', 'basic-form:actionBack'],
75
+ );
76
+
77
+ const updateJson = await app.bean.openapi.generateJsonOfClass(DtoSkuUpdate);
78
+ const updateComponent = findComponent(updateJson, properties => {
79
+ return properties?.code && properties?.productId && properties?.priceCents;
80
+ });
81
+ assert.deepEqual(Object.keys(updateComponent.properties).sort(), [
82
+ 'code',
83
+ 'lifecycle',
84
+ 'priceCents',
85
+ 'productId',
86
+ ]);
87
+ assert.equal(updateComponent.properties.attributes, undefined);
88
+ assert.equal(
89
+ updateComponent.properties.lifecycle.rest.form.render,
90
+ 'basic-select:formFieldSelect',
91
+ );
92
+ assertLifecycleItems(updateComponent.properties.lifecycle.rest.form.options.items);
93
+ const updateToolbar = getEntryForm(updateComponent);
94
+ assert.deepEqual(
95
+ updateToolbar.options.actions.map((action: any) => action.render),
96
+ ['basic-form:actionSubmit', 'basic-form:actionBack'],
97
+ );
98
+
99
+ const viewJson = await app.bean.openapi.generateJsonOfClass(DtoSkuView);
100
+ const viewComponent = findComponent(viewJson, properties => {
101
+ return (
102
+ properties?.id &&
103
+ properties?.productId &&
104
+ properties?.priceCents &&
105
+ properties?.lifecycle &&
106
+ properties?.iid &&
107
+ properties?.deleted
108
+ );
109
+ });
110
+ assert.equal(Object.hasOwn(viewComponent.properties, 'attributes'), false);
111
+ assert.equal(viewComponent.properties.iid.rest.visible, false);
112
+ assert.equal(viewComponent.properties.deleted.rest.visible, false);
113
+ assert.equal(
114
+ viewComponent.properties.priceCents.rest.table.render,
115
+ 'basic-currency:currency',
116
+ );
117
+ assert.deepEqual(viewComponent.properties.priceCents.rest.table.columnProps, currencyOptions);
118
+ assert.equal(viewComponent.properties.lifecycle.rest.table.render, 'basic-select:select');
119
+ assertLifecycleItems(viewComponent.properties.lifecycle.rest.table.columnProps.items);
120
+ const viewToolbar = getEntryForm(viewComponent);
121
+ assert.deepEqual(
122
+ viewToolbar.options.actions.map((action: any) => action.render),
123
+ ['basic-form:actionBack'],
124
+ );
125
+
126
+ const listJson = await app.bean.openapi.generateJsonOfClass(DtoSkuSelectResItem);
127
+ const listComponent = findComponent(listJson, properties => properties?._operationsRow);
128
+ assert.equal(Object.hasOwn(listComponent.properties, 'attributes'), false);
129
+ assert.equal(listComponent.properties.code.rest.table.render, 'basic-table:actionView');
130
+ assert.equal(
131
+ listComponent.properties.priceCents.rest.table.render,
132
+ 'basic-currency:currency',
133
+ );
134
+ assert.deepEqual(listComponent.properties.priceCents.rest.table.columnProps, currencyOptions);
135
+ assert.equal(listComponent.properties.lifecycle.rest.table.render, 'basic-select:select');
136
+ assertLifecycleItems(listComponent.properties.lifecycle.rest.table.columnProps.items);
137
+ assert.equal(listComponent.properties.productId.rest?.form?.render, undefined);
138
+ assert.equal(listComponent.properties.productId.rest?.table?.render, undefined);
139
+ assert.deepEqual(
140
+ listComponent.properties._operationsRow.rest.table.columnProps.actions.map(
141
+ (action: any) => action.render,
142
+ ),
143
+ ['basic-table:actionUpdate', 'basic-table:actionDelete'],
144
+ );
145
+
146
+ const filterBlock = listComponent.rest.blocks[0].options.blocks[0];
147
+ const filterLayout = filterBlock.options.blocks[0].options.formLayout;
148
+ const section = filterLayout.children[0];
149
+ assert.equal(section.type, 'section');
150
+ assert.equal(section.layout, 'flow');
151
+ assert.deepEqual(
152
+ section.children.slice(0, 2).map((field: any) => field.name),
153
+ ['code', 'createdAt'],
154
+ );
155
+ assert.equal(section.children[2].block.render, 'basic-page:blockFilterActions');
156
+ });
157
+ });
158
+
159
+ it('action:sku:runtimeBoundary', async () => {
160
+ await app.bean.executor.mockCtx(async () => {
161
+ const suffix = randomUUID().slice(0, 12);
162
+ let categoryId: number | string | undefined;
163
+ let productId: number | string | undefined;
164
+ let skuId: number | string | undefined;
165
+ await app.bean.passport.signinMock();
166
+ try {
167
+ categoryId = await app.bean.executor.performAction('post', '/commerce/catalog/category', {
168
+ body: { name: `presentation-sku-category-${suffix}`, published: true },
169
+ });
170
+ productId = await app.bean.executor.performAction('post', '/commerce/catalog/product', {
171
+ body: {
172
+ categoryId,
173
+ title: `presentation-sku-product-${suffix}`,
174
+ published: true,
175
+ },
176
+ });
177
+ skuId = await app.bean.executor.performAction('post', '/commerce/catalog/sku', {
178
+ body: {
179
+ code: `presentation-sku-${suffix}`,
180
+ productId,
181
+ priceCents: 1234,
182
+ lifecycle: 'draft',
183
+ },
184
+ });
185
+
186
+ const view: any = await app.bean.executor.performAction(
187
+ 'get',
188
+ '/commerce/catalog/sku/:id',
189
+ {
190
+ params: { id: skuId },
191
+ },
192
+ );
193
+ assert.equal(String(view.id), String(skuId));
194
+ assert.equal(String(view.productId), String(productId));
195
+ assert.equal(view.priceCents, 1234);
196
+ assert.equal(view.lifecycle, 'draft');
197
+ assert.equal(view.product, undefined);
198
+ assert.equal(view.attributes, undefined);
199
+
200
+ const select: any = await app.bean.executor.performAction('get', '/commerce/catalog/sku', {
201
+ query: { code: `presentation-sku-${suffix}` },
202
+ });
203
+ assert.equal(select.list.length, 1);
204
+ assert.equal(String(select.list[0].id), String(skuId));
205
+ assert.equal(select.list[0].product, undefined);
206
+ assert.equal(select.list[0].attributes, undefined);
207
+ } finally {
208
+ if (skuId) {
209
+ await app.bean.executor.performAction('delete', '/commerce/catalog/sku/:id', {
210
+ params: { id: skuId },
211
+ });
212
+ }
213
+ if (productId) {
214
+ await app.bean.executor.performAction('delete', '/commerce/catalog/product/:id', {
215
+ params: { id: productId },
216
+ });
217
+ }
218
+ if (categoryId) {
219
+ await app.bean.executor.performAction('delete', '/commerce/catalog/category/:id', {
220
+ params: { id: categoryId },
221
+ });
222
+ }
223
+ await app.bean.passport.signout();
224
+ }
225
+ });
226
+ });
227
+ });