@nocobase/app 2.3.0-alpha.1 → 3.0.0-alpha.1

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 (273) hide show
  1. package/__tests__/browserChecker.test.ts +129 -0
  2. package/__tests__/settingsDevProxy.test.ts +96 -0
  3. package/__tests__/settingsPluginImports.test.ts +106 -0
  4. package/client/rsbuild.config.ts +37 -15
  5. package/client-settings/generatePluginImports.ts +36 -0
  6. package/client-settings/index.html +11 -0
  7. package/client-settings/rsbuild.config.ts +270 -0
  8. package/client-settings/src/.plugins/index.ts +4 -0
  9. package/client-settings/src/SettingsPresetPlugin.ts +56 -0
  10. package/client-settings/src/__tests__/runtimePublicPath.test.ts +23 -0
  11. package/client-settings/src/__tests__/runtimeScope.test.ts +29 -0
  12. package/client-settings/src/env.d.ts +22 -0
  13. package/client-settings/src/main.tsx +78 -0
  14. package/client-settings/src/runtimePublicPath.ts +21 -0
  15. package/client-settings/src/runtimeScope.ts +49 -0
  16. package/client-settings/tsconfig.json +19 -0
  17. package/client-v2/public/browser-checker.js +76 -1
  18. package/client-v2/rsbuild.config.ts +31 -9
  19. package/dist/client/assets/{index-800d06ee.js → index-b8e6cdd9.js} +369 -355
  20. package/dist/client/assets/{vendor-antd-f421fb70.js → vendor-antd-b77deb8f.js} +4 -4
  21. package/dist/client/index.html +1 -1
  22. package/dist/client/index.html.tpl +1 -1
  23. package/dist/client/settings/assets/1052-2ed99808.js +1 -0
  24. package/dist/client/settings/assets/108-76a3fdea.js +82 -0
  25. package/dist/client/settings/assets/108-76a3fdea.js.LICENSE.txt +17 -0
  26. package/dist/client/settings/assets/1101-53bb815a.js +1 -0
  27. package/dist/client/settings/assets/1179-1ec4826c.js +1 -0
  28. package/dist/client/settings/assets/1310-c0031389.js +59 -0
  29. package/dist/client/settings/assets/1329-0e47aabd.js +1 -0
  30. package/dist/client/settings/assets/1425-69534606.js +42 -0
  31. package/dist/client/settings/assets/1434-d603f255.js +1 -0
  32. package/dist/client/settings/assets/1463-11b9abe3.js +1 -0
  33. package/dist/client/settings/assets/1469-477cfa59.js +1 -0
  34. package/dist/client/settings/assets/1481-59e4188c.js +1 -0
  35. package/dist/client/settings/assets/1507-9a211af0.js +7 -0
  36. package/dist/client/settings/assets/158-5273dfbb.js +23 -0
  37. package/dist/client/settings/assets/1586-73831f88.js +1 -0
  38. package/dist/client/settings/assets/1667-88ad86eb.js +1 -0
  39. package/dist/client/settings/assets/1675-3cbafc50.js +1 -0
  40. package/dist/client/settings/assets/1676-5db7433e.js +9 -0
  41. package/dist/client/settings/assets/1725-d9ce2582.js +83 -0
  42. package/dist/client/settings/assets/1786-e6c321bb.js +16 -0
  43. package/dist/client/settings/assets/183-963396ee.js +1 -0
  44. package/dist/client/settings/assets/1846-0deb6fc0.js +1 -0
  45. package/dist/client/settings/assets/1848-0ef98f01.js +1 -0
  46. package/dist/client/settings/assets/1863-9160dd98.js +1 -0
  47. package/dist/client/settings/assets/1887-bf619cb3.js +1 -0
  48. package/dist/client/settings/assets/192-c347bb96.js +1 -0
  49. package/dist/client/settings/assets/1951-84be8ebc.js +55 -0
  50. package/dist/client/settings/assets/1979-a893b852.js +1 -0
  51. package/dist/client/settings/assets/1986-01c03982.js +1 -0
  52. package/dist/client/settings/assets/2017-29a9879a.js +26 -0
  53. package/dist/client/settings/assets/2110-961b6f8e.js +1 -0
  54. package/dist/client/settings/assets/212-0f8a26a2.js +18 -0
  55. package/dist/client/settings/assets/2203-9aa79271.js +4 -0
  56. package/dist/client/settings/assets/2258-f667d700.js +1 -0
  57. package/dist/client/settings/assets/2270-ff70d8cb.js +1 -0
  58. package/dist/client/settings/assets/2301-2db05359.js +1 -0
  59. package/dist/client/settings/assets/2322-b9f077c3.js +1 -0
  60. package/dist/client/settings/assets/2335-669f21bd.js +22 -0
  61. package/dist/client/settings/assets/242-c3e15c94.js +1 -0
  62. package/dist/client/settings/assets/2446-ac5fccd3.js +1 -0
  63. package/dist/client/settings/assets/2512-5343dabb.js +1185 -0
  64. package/dist/client/settings/assets/2512-5343dabb.js.LICENSE.txt +9 -0
  65. package/dist/client/settings/assets/2555-4ca49e21.js +31 -0
  66. package/dist/client/settings/assets/2565-ad63e92f.js +1 -0
  67. package/dist/client/settings/assets/2606-c4dcd1e1.js +1 -0
  68. package/dist/client/settings/assets/2613-98648bd2.js +1 -0
  69. package/dist/client/settings/assets/2622-3389992f.js +1 -0
  70. package/dist/client/settings/assets/2702-5ce93acd.js +5 -0
  71. package/dist/client/settings/assets/2710-e7286996.js +36 -0
  72. package/dist/client/settings/assets/2726-4d19faa1.js +23 -0
  73. package/dist/client/settings/assets/2861-48106fd8.js +3 -0
  74. package/dist/client/settings/assets/2898-7656f7f9.js +17 -0
  75. package/dist/client/settings/assets/2913-6b4e6c17.js +1 -0
  76. package/dist/client/settings/assets/2958-93de29a6.js +27 -0
  77. package/dist/client/settings/assets/300-ca09229f.js +1 -0
  78. package/dist/client/settings/assets/3005-1449fc4e.js +56 -0
  79. package/dist/client/settings/assets/3018-fc630932.js +3 -0
  80. package/dist/client/settings/assets/3028-efe6f61f.js +1 -0
  81. package/dist/client/settings/assets/3039-7f273921.js +1 -0
  82. package/dist/client/settings/assets/3102-b985963e.js +1 -0
  83. package/dist/client/settings/assets/3117-cc936eae.js +33 -0
  84. package/dist/client/settings/assets/32-88d3c82f.js +2 -0
  85. package/dist/client/settings/assets/3260-3b3c7cd3.js +1 -0
  86. package/dist/client/settings/assets/3279-8d73fd19.js +1 -0
  87. package/dist/client/settings/assets/3283-654f42f7.js +1 -0
  88. package/dist/client/settings/assets/3309-172e3f79.js +1 -0
  89. package/dist/client/settings/assets/335-da9c4d81.js +1 -0
  90. package/dist/client/settings/assets/338-2f192edd.js +3 -0
  91. package/dist/client/settings/assets/3396-4422ee26.js +1 -0
  92. package/dist/client/settings/assets/3458-2958f051.js +1 -0
  93. package/dist/client/settings/assets/3475-be655098.js +1 -0
  94. package/dist/client/settings/assets/3523-5313a211.js +1 -0
  95. package/dist/client/settings/assets/3526-17f4e8e7.js +1 -0
  96. package/dist/client/settings/assets/3641-c2439c22.js +1 -0
  97. package/dist/client/settings/assets/3646-aa6a2478.js +1 -0
  98. package/dist/client/settings/assets/3660-280439df.js +6 -0
  99. package/dist/client/settings/assets/3662-8dff1ffe.js +28 -0
  100. package/dist/client/settings/assets/3690-4a8bdf43.js +12 -0
  101. package/dist/client/settings/assets/3727-1cfef422.js +44 -0
  102. package/dist/client/settings/assets/3859-fa4f6d5d.js +1 -0
  103. package/dist/client/settings/assets/3898-6236af03.js +1 -0
  104. package/dist/client/settings/assets/3916-3b34f216.js +6 -0
  105. package/dist/client/settings/assets/3937-af967d62.js +3 -0
  106. package/dist/client/settings/assets/3977-3feadc2c.js +1 -0
  107. package/dist/client/settings/assets/3978-29c2602c.js +1 -0
  108. package/dist/client/settings/assets/3989-c8fcfd6c.js +27 -0
  109. package/dist/client/settings/assets/406-497829bb.js +1 -0
  110. package/dist/client/settings/assets/4076-f68c25bd.js +1 -0
  111. package/dist/client/settings/assets/4096-0050f491.js +1 -0
  112. package/dist/client/settings/assets/4171-0710965d.js +2 -0
  113. package/dist/client/settings/assets/4171-0710965d.js.LICENSE.txt +6 -0
  114. package/dist/client/settings/assets/4195-2a00794d.js +1 -0
  115. package/dist/client/settings/assets/4222-29a8147d.js +5 -0
  116. package/dist/client/settings/assets/4223-3821a30e.js +1 -0
  117. package/dist/client/settings/assets/4313-ab774fd9.js +28 -0
  118. package/dist/client/settings/assets/4358-0a504478.js +1 -0
  119. package/dist/client/settings/assets/4419-3ab9c709.js +1 -0
  120. package/dist/client/settings/assets/4456-49679669.js +1 -0
  121. package/dist/client/settings/assets/448-57d6a00d.js +1 -0
  122. package/dist/client/settings/assets/4594-4e72041f.js +1 -0
  123. package/dist/client/settings/assets/4672-573e9a61.js +1 -0
  124. package/dist/client/settings/assets/4686-afbf676f.js +1 -0
  125. package/dist/client/settings/assets/474-ce4285d1.js +1 -0
  126. package/dist/client/settings/assets/4767-8f9d30dc.js +1 -0
  127. package/dist/client/settings/assets/4784-c69aaa68.js +1 -0
  128. package/dist/client/settings/assets/4801-06781ed7.js +1 -0
  129. package/dist/client/settings/assets/492-937af2ba.js +1 -0
  130. package/dist/client/settings/assets/4930-41adc6b7.js +1 -0
  131. package/dist/client/settings/assets/5064-93d8e29e.js +10 -0
  132. package/dist/client/settings/assets/5087-c505a60e.js +1 -0
  133. package/dist/client/settings/assets/5108-a028f8af.js +1 -0
  134. package/dist/client/settings/assets/5122-649463de.js +1 -0
  135. package/dist/client/settings/assets/5123-0bd0a6f2.js +1 -0
  136. package/dist/client/settings/assets/5139-3039fde4.js +1 -0
  137. package/dist/client/settings/assets/5459-c1f208e3.js +1 -0
  138. package/dist/client/settings/assets/5501-387a31be.js +17 -0
  139. package/dist/client/settings/assets/5506-a1f27be3.js +1 -0
  140. package/dist/client/settings/assets/553-1c3126df.js +1 -0
  141. package/dist/client/settings/assets/557-950114e1.js +1 -0
  142. package/dist/client/settings/assets/5640-f846c2a0.js +1 -0
  143. package/dist/client/settings/assets/5642-5c0bab20.js +1 -0
  144. package/dist/client/settings/assets/5674-e33e384f.js +1 -0
  145. package/dist/client/settings/assets/5701-8fe417d1.js +1 -0
  146. package/dist/client/settings/assets/5721-af25e047.js +18 -0
  147. package/dist/client/settings/assets/5757-81a89522.js +1 -0
  148. package/dist/client/settings/assets/5759-2b3bdcc6.js +47 -0
  149. package/dist/client/settings/assets/5761-857b6bbb.js +28 -0
  150. package/dist/client/settings/assets/5791-7c59ba08.js +1 -0
  151. package/dist/client/settings/assets/58-77bfd6c9.js +1 -0
  152. package/dist/client/settings/assets/5815-04fc432a.js +1 -0
  153. package/dist/client/settings/assets/5819-225de680.js +1 -0
  154. package/dist/client/settings/assets/5861-ac056534.js +1 -0
  155. package/dist/client/settings/assets/5870-0c3ecc40.js +1 -0
  156. package/dist/client/settings/assets/5881-b4c942f1.js +1 -0
  157. package/dist/client/settings/assets/5905-a5c3fce6.js +1 -0
  158. package/dist/client/settings/assets/5933-fbe50cd6.js +1 -0
  159. package/dist/client/settings/assets/6062-0e469079.js +1 -0
  160. package/dist/client/settings/assets/6093-641fcafc.js +1 -0
  161. package/dist/client/settings/assets/6157-8e763248.js +1 -0
  162. package/dist/client/settings/assets/6241-55a319df.js +1 -0
  163. package/dist/client/settings/assets/6269-a8a1ea3f.js +1 -0
  164. package/dist/client/settings/assets/630-110e12f4.js +1 -0
  165. package/dist/client/settings/assets/6345-187e76cf.js +1 -0
  166. package/dist/client/settings/assets/6346-94bdf034.js +1 -0
  167. package/dist/client/settings/assets/6373-9d047c6b.js +13 -0
  168. package/dist/client/settings/assets/6437-3865fd7e.js +12 -0
  169. package/dist/client/settings/assets/6581-51c928bf.js +21 -0
  170. package/dist/client/settings/assets/6660-54e08a8d.js +1 -0
  171. package/dist/client/settings/assets/6738-c6598897.js +20 -0
  172. package/dist/client/settings/assets/6870-6a6dba63.js +1 -0
  173. package/dist/client/settings/assets/6914-00d913e7.js +1 -0
  174. package/dist/client/settings/assets/70-f4dc53ad.js +1 -0
  175. package/dist/client/settings/assets/700-e75b7faa.js +15 -0
  176. package/dist/client/settings/assets/7021-4975d54d.js +45 -0
  177. package/dist/client/settings/assets/7095-4f425b85.js +1 -0
  178. package/dist/client/settings/assets/7141-b8e2a787.js +1 -0
  179. package/dist/client/settings/assets/7201-5b49ce84.js +14 -0
  180. package/dist/client/settings/assets/7211-b8c71ed2.js +9 -0
  181. package/dist/client/settings/assets/7245-1058e96e.js +474 -0
  182. package/dist/client/settings/assets/7245-1058e96e.js.LICENSE.txt +2567 -0
  183. package/dist/client/settings/assets/7245-db3cd5c2.css +1 -0
  184. package/dist/client/settings/assets/7318-6e1c7877.js +1 -0
  185. package/dist/client/settings/assets/7386-2f5752d4.js +1 -0
  186. package/dist/client/settings/assets/7413-241d463c.js +1 -0
  187. package/dist/client/settings/assets/7492-5c593f52.js +5 -0
  188. package/dist/client/settings/assets/7507-a015d8cf.js +1 -0
  189. package/dist/client/settings/assets/754-41b763b9.js +17 -0
  190. package/dist/client/settings/assets/7555-f42cdb72.js +1 -0
  191. package/dist/client/settings/assets/7608-2b3f2db0.js +1 -0
  192. package/dist/client/settings/assets/7669-8bd94b73.js +1 -0
  193. package/dist/client/settings/assets/7761-637067c6.js +123 -0
  194. package/dist/client/settings/assets/7876-673cbc3c.js +6 -0
  195. package/dist/client/settings/assets/791-9cfa98c8.js +1 -0
  196. package/dist/client/settings/assets/7946-e07199df.js +13 -0
  197. package/dist/client/settings/assets/7959-f7ef21c6.js +40 -0
  198. package/dist/client/settings/assets/8053-fa93540e.js +1 -0
  199. package/dist/client/settings/assets/8087-90829087.js +1 -0
  200. package/dist/client/settings/assets/8138-e90c290e.js +24 -0
  201. package/dist/client/settings/assets/8217-de1369d7.js +1 -0
  202. package/dist/client/settings/assets/8242-3f880357.js +108 -0
  203. package/dist/client/settings/assets/8252-1153ffdd.js +1 -0
  204. package/dist/client/settings/assets/8262-7a324b59.js +9 -0
  205. package/dist/client/settings/assets/8269-52ea88cd.js +1 -0
  206. package/dist/client/settings/assets/8276-b3dfc452.js +1 -0
  207. package/dist/client/settings/assets/828-55028e33.js +1 -0
  208. package/dist/client/settings/assets/8294-9c81768d.js +1 -0
  209. package/dist/client/settings/assets/8295-447d3bb3.js +1 -0
  210. package/dist/client/settings/assets/8349-82eb3ecd.js +1 -0
  211. package/dist/client/settings/assets/8434-9140d106.js +25 -0
  212. package/dist/client/settings/assets/8438-d2ff6bc1.js +37 -0
  213. package/dist/client/settings/assets/8473-b1118703.js +1 -0
  214. package/dist/client/settings/assets/8480-c16f7ee4.js +1 -0
  215. package/dist/client/settings/assets/8562-ffa35312.js +17 -0
  216. package/dist/client/settings/assets/8624-847569d9.js +1 -0
  217. package/dist/client/settings/assets/8631-b2fd9aac.js +1 -0
  218. package/dist/client/settings/assets/8635-27980c94.js +1 -0
  219. package/dist/client/settings/assets/8676-987fe455.js +1 -0
  220. package/dist/client/settings/assets/8729-9adea5fe.js +1 -0
  221. package/dist/client/settings/assets/8759-4d7f7a69.js +1 -0
  222. package/dist/client/settings/assets/896-d07bab4d.js +1 -0
  223. package/dist/client/settings/assets/9021-ec1b8442.js +1 -0
  224. package/dist/client/settings/assets/9065-5df7b63d.js +1 -0
  225. package/dist/client/settings/assets/9170-efbfcc1e.js +1 -0
  226. package/dist/client/settings/assets/9204-6cb7a01b.js +1 -0
  227. package/dist/client/settings/assets/9217-f27c2dcb.js +1 -0
  228. package/dist/client/settings/assets/9248-ff8e06d0.js +1 -0
  229. package/dist/client/settings/assets/9274-83aa1da2.js +1 -0
  230. package/dist/client/settings/assets/929-a37c623d.js +1 -0
  231. package/dist/client/settings/assets/93-dc732e8a.js +1 -0
  232. package/dist/client/settings/assets/9518-4c8b8805.js +1 -0
  233. package/dist/client/settings/assets/9550-2daf603c.js +1 -0
  234. package/dist/client/settings/assets/9565-2158d75f.js +1 -0
  235. package/dist/client/settings/assets/9578-f64d8970.js +1 -0
  236. package/dist/client/settings/assets/9584-969e1d2b.js +1 -0
  237. package/dist/client/settings/assets/9592-523a3fa6.js +1 -0
  238. package/dist/client/settings/assets/9827-d1f02095.js +9 -0
  239. package/dist/client/settings/assets/9836-fcbb81f6.js +22 -0
  240. package/dist/client/settings/assets/9847-bc9f1ba4.js +1 -0
  241. package/dist/client/settings/assets/9953-407a1cde.js +1 -0
  242. package/dist/client/settings/assets/index-222fdff7.js +1946 -0
  243. package/dist/client/settings/assets/index-222fdff7.js.LICENSE.txt +1 -0
  244. package/dist/client/settings/assets/runtime-6b2f3ebe.js +1 -0
  245. package/dist/client/settings/browser-checker.js +282 -0
  246. package/dist/client/settings/favicon/favicon.ico +0 -0
  247. package/dist/client/settings/file-placeholder/ai-200-200.png +0 -0
  248. package/dist/client/settings/file-placeholder/audio-200-200.png +0 -0
  249. package/dist/client/settings/file-placeholder/docx-200-200.png +0 -0
  250. package/dist/client/settings/file-placeholder/eps-200-200.png +0 -0
  251. package/dist/client/settings/file-placeholder/gif-200-200.png +0 -0
  252. package/dist/client/settings/file-placeholder/jpeg-200-200.png +0 -0
  253. package/dist/client/settings/file-placeholder/pdf-200-200.png +0 -0
  254. package/dist/client/settings/file-placeholder/png-200-200.png +0 -0
  255. package/dist/client/settings/file-placeholder/pptx-200-200.png +0 -0
  256. package/dist/client/settings/file-placeholder/psd-200-200.png +0 -0
  257. package/dist/client/settings/file-placeholder/svg-200-200.png +0 -0
  258. package/dist/client/settings/file-placeholder/unknown-200-200.png +0 -0
  259. package/dist/client/settings/file-placeholder/video-200-200.png +0 -0
  260. package/dist/client/settings/file-placeholder/xlsx-200-200.png +0 -0
  261. package/dist/client/settings/file-placeholder/zip-200-200.png +0 -0
  262. package/dist/client/settings/global.css +63 -0
  263. package/dist/client/settings/index.html +22 -0
  264. package/dist/client/settings/nocobase.png +0 -0
  265. package/dist/client/settings/robots.txt +2 -0
  266. package/dist/client/v/assets/{index-2f7426fe.js → index-b2d53e82.js} +167 -153
  267. package/dist/client/v/assets/index-b2d53e82.js.LICENSE.txt +1 -0
  268. package/dist/client/v/browser-checker.js +76 -1
  269. package/dist/client/v/index.html +1 -1
  270. package/package.json +7 -7
  271. package/settingsDevProxy.ts +52 -0
  272. /package/dist/client/assets/{index-800d06ee.js.LICENSE.txt → index-b8e6cdd9.js.LICENSE.txt} +0 -0
  273. /package/dist/client/{v/assets/index-2f7426fe.js.LICENSE.txt → settings/assets/32-88d3c82f.js.LICENSE.txt} +0 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { readFileSync } from 'node:fs';
11
+ import { resolve } from 'node:path';
12
+ import vm from 'node:vm';
13
+ import { describe, expect, it } from 'vitest';
14
+
15
+ const browserCheckerSource = readFileSync(resolve(__dirname, '../client-v2/public/browser-checker.js'), 'utf8');
16
+
17
+ interface RunBrowserCheckerOptions {
18
+ appClientEntryMode?: string;
19
+ currentScriptSrc?: string;
20
+ hash?: string;
21
+ modernPrefix?: string;
22
+ pathname: string;
23
+ publicPath?: string;
24
+ search?: string;
25
+ }
26
+
27
+ function runBrowserChecker(options: RunBrowserCheckerOptions) {
28
+ const replacements: string[] = [];
29
+ const windowObject: Record<string, unknown> = {
30
+ __nocobase_app_client_entry_mode__: options.appClientEntryMode,
31
+ __nocobase_modern_client_prefix__: options.modernPrefix,
32
+ __nocobase_public_path__: options.publicPath ?? '/v/',
33
+ console: {
34
+ log: () => undefined,
35
+ },
36
+ devicePixelRatio: 1,
37
+ location: {
38
+ hash: options.hash ?? '',
39
+ origin: 'https://example.test',
40
+ pathname: options.pathname,
41
+ replace: (url: string) => replacements.push(url),
42
+ search: options.search ?? '',
43
+ },
44
+ outerHeight: 720,
45
+ outerWidth: 1280,
46
+ };
47
+ const documentElement = {
48
+ className: 'no-js',
49
+ clientHeight: 720,
50
+ clientWidth: 1280,
51
+ };
52
+
53
+ vm.runInNewContext(browserCheckerSource, {
54
+ console: {
55
+ debug: () => undefined,
56
+ log: () => undefined,
57
+ },
58
+ document: {
59
+ currentScript: {
60
+ src: options.currentScriptSrc ?? 'https://example.test/v/browser-checker.js',
61
+ },
62
+ documentElement,
63
+ },
64
+ navigator: {
65
+ userAgent:
66
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
67
+ },
68
+ window: windowObject,
69
+ });
70
+
71
+ return {
72
+ className: documentElement.className,
73
+ replacements,
74
+ };
75
+ }
76
+
77
+ describe('v2 browser checker', () => {
78
+ it('redirects the modern client root to Settings only in modern-only mode', () => {
79
+ expect(
80
+ runBrowserChecker({
81
+ appClientEntryMode: 'modern-only',
82
+ pathname: '/v/',
83
+ }).replacements,
84
+ ).toEqual(['https://example.test/settings']);
85
+
86
+ expect(
87
+ runBrowserChecker({
88
+ appClientEntryMode: 'modern-default',
89
+ pathname: '/v/',
90
+ }).replacements,
91
+ ).toEqual([]);
92
+
93
+ expect(
94
+ runBrowserChecker({
95
+ pathname: '/v/',
96
+ }).replacements,
97
+ ).toEqual([]);
98
+ });
99
+
100
+ it('redirects scoped modern client roots to scoped Settings only in modern-only mode', () => {
101
+ expect(
102
+ runBrowserChecker({
103
+ appClientEntryMode: 'modern-only',
104
+ pathname: '/v/apps/demo',
105
+ search: '?from=admin',
106
+ hash: '#portal',
107
+ }).replacements,
108
+ ).toEqual(['https://example.test/settings/apps/demo?from=admin#portal']);
109
+
110
+ expect(
111
+ runBrowserChecker({
112
+ appClientEntryMode: 'modern-default',
113
+ pathname: '/v/apps/demo',
114
+ search: '?from=admin',
115
+ hash: '#portal',
116
+ }).replacements,
117
+ ).toEqual([]);
118
+ });
119
+
120
+ it('keeps Settings scoped trailing slash normalization independent from entry mode', () => {
121
+ expect(
122
+ runBrowserChecker({
123
+ currentScriptSrc: 'https://example.test/settings/browser-checker.js',
124
+ pathname: '/settings/apps/demo',
125
+ publicPath: '/',
126
+ }).replacements,
127
+ ).toEqual(['https://example.test/settings/apps/demo/']);
128
+ });
129
+ });
@@ -0,0 +1,96 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { describe, expect, it } from 'vitest';
11
+ import { createSettingsDevProxyOptions, isSettingsDevPath, rewriteSettingsDevProxyPath } from '../settingsDevProxy';
12
+
13
+ describe('settings dev proxy', () => {
14
+ it.each([
15
+ ['/settings', true],
16
+ ['/settings/signin', true],
17
+ ['/settings/signup', true],
18
+ ['/settings/forgot-password', true],
19
+ ['/settings/reset-password?resetToken=test-token', true],
20
+ ['/settings/2fa?redirect=%2Fsettings%2Fworkflow', true],
21
+ ['/settings/workflow/workflows/1?tab=nodes', true],
22
+ ['/settings/apps/demo/signin', true],
23
+ ['/settings/apps/demo', true],
24
+ ['/settings/apps/demo/workflow/workflows/1', true],
25
+ ['/settings/_app/demo/reset-password?resetToken=test-token', true],
26
+ ['/settings/_app/demo/ai/knowledge-base/detail/k1', true],
27
+ ['/nocobase/settings/assets/index.js', false],
28
+ ['/admin/settings', false],
29
+ ['/v/admin/settings', false],
30
+ ['/apps/demo/settings', false],
31
+ ['/_app/demo/settings', false],
32
+ ['/apps/demo/admin/settings', false],
33
+ ])('matches only standalone Settings paths: %s', (pathname, expected) => {
34
+ expect(isSettingsDevPath(pathname, '/')).toBe(expected);
35
+ });
36
+
37
+ it.each([
38
+ ['/nocobase/settings', true],
39
+ ['/nocobase/settings/signin', true],
40
+ ['/nocobase/settings/2fa?redirect=%2Fnocobase%2Fsettings', true],
41
+ ['/nocobase/settings/workflow/workflows/1', true],
42
+ ['/nocobase/settings/apps/demo/forgot-password', true],
43
+ ['/nocobase/settings/apps/demo', true],
44
+ ['/nocobase/settings/_app/demo/reset-password?resetToken=test-token', true],
45
+ ['/nocobase/settings/_app/demo/ai/knowledge-base/detail/k1', true],
46
+ ['/settings', false],
47
+ ['/nocobase/admin/settings', false],
48
+ ['/nocobase/apps/demo/settings', false],
49
+ ])('honors APP_PUBLIC_PATH: %s', (pathname, expected) => {
50
+ expect(isSettingsDevPath(pathname, '/nocobase/')).toBe(expected);
51
+ });
52
+
53
+ it.each([
54
+ ['/settings', '/', '/settings/'],
55
+ ['/settings?from=admin', '/', '/settings/?from=admin'],
56
+ ['/settings/apps/demo', '/', '/settings/apps/demo'],
57
+ ['/settings/_app/demo?from=admin', '/', '/settings/_app/demo?from=admin'],
58
+ ['/nocobase/settings', '/nocobase/', '/nocobase/settings/'],
59
+ ['/nocobase/settings/apps/demo?from=admin', '/nocobase/', '/nocobase/settings/apps/demo?from=admin'],
60
+ ['/nocobase/settings/_app/demo#portal', '/nocobase/', '/nocobase/settings/_app/demo#portal'],
61
+ ])('normalizes a Settings root to the dev-server base: %s', (pathname, publicPath, expected) => {
62
+ expect(rewriteSettingsDevProxyPath(pathname, publicPath)).toBe(expected);
63
+ });
64
+
65
+ it('preserves application-scoped documents for the Settings dev server', () => {
66
+ expect(rewriteSettingsDevProxyPath('/settings/apps/demo/workflow/workflows/1?tab=nodes', '/')).toBe(
67
+ '/settings/apps/demo/workflow/workflows/1?tab=nodes',
68
+ );
69
+ expect(rewriteSettingsDevProxyPath('/nocobase/settings/apps/demo/a#hash', '/nocobase/')).toBe(
70
+ '/nocobase/settings/apps/demo/a#hash',
71
+ );
72
+ expect(rewriteSettingsDevProxyPath('/settings/assets/index.js', '/')).toBe('/settings/assets/index.js');
73
+ expect(rewriteSettingsDevProxyPath('/settings/__rspack_hmr', '/')).toBe('/settings/__rspack_hmr');
74
+ });
75
+
76
+ it('creates a websocket-capable proxy for the Settings port', () => {
77
+ const options = createSettingsDevProxyOptions('/nocobase/', 13004);
78
+
79
+ expect(options).toMatchObject({
80
+ target: 'http://127.0.0.1:13004',
81
+ changeOrigin: true,
82
+ ws: true,
83
+ xfwd: true,
84
+ });
85
+ expect(options.context?.('/nocobase/settings/__rspack_hmr')).toBe(true);
86
+ expect(options.context?.('/nocobase/settings/signin')).toBe(true);
87
+ expect(options.context?.('/nocobase/settings/apps/demo/workflow')).toBe(true);
88
+ expect(options.context?.('/nocobase/settings/apps/demo/2fa')).toBe(true);
89
+ expect(options.context?.('/nocobase/settings/_app/demo/ai')).toBe(true);
90
+ expect(options.context?.('/nocobase/apps/demo/settings/workflow')).toBe(false);
91
+ expect(options.context?.('/nocobase/admin/settings')).toBe(false);
92
+ expect(options.pathRewrite?.('/nocobase/settings/apps/demo/workflow')).toBe(
93
+ '/nocobase/settings/apps/demo/workflow',
94
+ );
95
+ });
96
+ });
@@ -0,0 +1,106 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
11
+ import { tmpdir } from 'node:os';
12
+ import path from 'node:path';
13
+ import { afterEach, describe, expect, it } from 'vitest';
14
+ import { generateSettingsPluginImports } from '../client-settings/generatePluginImports';
15
+
16
+ const temporaryDirectories: string[] = [];
17
+
18
+ function createTemporaryDirectory() {
19
+ const directory = mkdtempSync(path.join(tmpdir(), 'nocobase-settings-plugin-imports-'));
20
+ temporaryDirectories.push(directory);
21
+ return directory;
22
+ }
23
+
24
+ function createV2Plugin(pluginRoot: string) {
25
+ const pluginDirectory = path.join(pluginRoot, '@example', 'plugin-demo');
26
+ mkdirSync(pluginDirectory, { recursive: true });
27
+ writeFileSync(
28
+ path.join(pluginDirectory, 'package.json'),
29
+ JSON.stringify({ name: '@example/plugin-demo', version: '1.0.0' }),
30
+ );
31
+ writeFileSync(path.join(pluginDirectory, 'client-v2.js'), 'module.exports = {};');
32
+ mkdirSync(path.join(pluginDirectory, 'src', 'client-v2'), { recursive: true });
33
+ writeFileSync(path.join(pluginDirectory, 'src', 'client-v2', 'index.ts'), 'export default class DemoPlugin {}');
34
+ }
35
+
36
+ afterEach(() => {
37
+ for (const directory of temporaryDirectories.splice(0)) {
38
+ rmSync(directory, { recursive: true, force: true });
39
+ }
40
+ });
41
+
42
+ describe('Settings plugin imports', () => {
43
+ it('generates the existing V2 plugin lane into a Settings-owned directory', () => {
44
+ const root = createTemporaryDirectory();
45
+ const pluginRoot = path.join(root, 'plugins');
46
+ const settingsOutput = path.join(root, 'client-settings', 'src', '.plugins');
47
+ const clientV2Output = path.join(root, 'client-v2', 'src', '.plugins');
48
+ createV2Plugin(pluginRoot);
49
+ mkdirSync(clientV2Output, { recursive: true });
50
+ writeFileSync(path.join(clientV2Output, 'index.ts'), 'export const clientV2DevManifest = true;');
51
+
52
+ const localPluginsOnly = process.env.NOCOBASE_DEV_LOCAL_PLUGINS_ONLY;
53
+ process.env.NOCOBASE_DEV_LOCAL_PLUGINS_ONLY = 'true';
54
+ try {
55
+ generateSettingsPluginImports(settingsOutput, [pluginRoot]);
56
+ } finally {
57
+ if (localPluginsOnly === undefined) {
58
+ delete process.env.NOCOBASE_DEV_LOCAL_PLUGINS_ONLY;
59
+ } else {
60
+ process.env.NOCOBASE_DEV_LOCAL_PLUGINS_ONLY = localPluginsOnly;
61
+ }
62
+ }
63
+
64
+ expect(JSON.parse(readFileSync(path.join(settingsOutput, 'packageMap.json'), 'utf8'))).toEqual({
65
+ '@example/plugin-demo': 'example_plugin_demo.ts',
66
+ });
67
+ expect(readFileSync(path.join(clientV2Output, 'index.ts'), 'utf8')).toBe(
68
+ 'export const clientV2DevManifest = true;',
69
+ );
70
+ expect(existsSync(path.join(settingsOutput, 'packages', 'example_plugin_demo.ts'))).toBe(true);
71
+ });
72
+
73
+ it('keeps a production Settings manifest isolated from the Client V2 development manifest', () => {
74
+ const root = createTemporaryDirectory();
75
+ const settingsOutput = path.join(root, 'client-settings', 'src', '.plugins');
76
+ const clientV2Output = path.join(root, 'client-v2', 'src', '.plugins');
77
+ mkdirSync(clientV2Output, { recursive: true });
78
+ writeFileSync(path.join(clientV2Output, 'index.ts'), 'export const clientV2DevManifest = true;');
79
+
80
+ const nodeEnv = process.env.NODE_ENV;
81
+ process.env.NODE_ENV = 'production';
82
+ try {
83
+ generateSettingsPluginImports(settingsOutput, []);
84
+ } finally {
85
+ if (nodeEnv === undefined) {
86
+ delete process.env.NODE_ENV;
87
+ } else {
88
+ process.env.NODE_ENV = nodeEnv;
89
+ }
90
+ }
91
+
92
+ expect(readFileSync(path.join(settingsOutput, 'index.ts'), 'utf8')).toContain('return Promise.resolve(null)');
93
+ expect(readFileSync(path.join(clientV2Output, 'index.ts'), 'utf8')).toBe(
94
+ 'export const clientV2DevManifest = true;',
95
+ );
96
+ });
97
+
98
+ it('wires the Settings config and entry to the Settings-owned generated directory', () => {
99
+ const configSource = readFileSync(path.resolve(__dirname, '../client-settings/rsbuild.config.ts'), 'utf8');
100
+ const entrySource = readFileSync(path.resolve(__dirname, '../client-settings/src/main.tsx'), 'utf8');
101
+
102
+ expect(configSource).not.toContain('generateV2Plugins');
103
+ expect(configSource).toContain("generateSettingsPluginImports(path.resolve(__dirname, 'src/.plugins'))");
104
+ expect(entrySource).toContain("from './.plugins'");
105
+ });
106
+ });
@@ -16,6 +16,7 @@ import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill';
16
16
  import { pluginReact } from '@rsbuild/plugin-react';
17
17
  import { pluginSvgr } from '@rsbuild/plugin-svgr';
18
18
  import { generatePlugins, getRsbuildBrowserAlias } from '@nocobase/devtools/rsbuildConfig';
19
+ import { createSettingsDevProxyOptions } from '../settingsDevProxy';
19
20
 
20
21
  const __filename = fileURLToPath(import.meta.url);
21
22
  const __dirname = path.dirname(__filename);
@@ -46,11 +47,19 @@ function toDefineLiteral(value: string | undefined) {
46
47
  return value === undefined ? 'undefined' : JSON.stringify(value);
47
48
  }
48
49
 
49
- function createRuntimeHeadScript(appPublicPath: string, isBuild: boolean) {
50
- const modernClientPrefix =
51
- String(process.env.APP_MODERN_CLIENT_PREFIX || 'v')
50
+ function normalizeModernClientPrefix(value: string | undefined) {
51
+ const normalized =
52
+ String(value || 'v')
52
53
  .trim()
53
54
  .replace(/^\/+|\/+$/g, '') || 'v';
55
+ if (normalized === 'settings') {
56
+ throw new Error('APP_MODERN_CLIENT_PREFIX "settings" is reserved for the standalone Settings application.');
57
+ }
58
+ return normalized;
59
+ }
60
+
61
+ function createRuntimeHeadScript(appPublicPath: string, isBuild: boolean) {
62
+ const modernClientPrefix = normalizeModernClientPrefix(process.env.APP_MODERN_CLIENT_PREFIX);
54
63
  const appClientEntryMode = process.env.APP_CLIENT_ENTRY_MODE;
55
64
  if (!isBuild) {
56
65
  return [
@@ -109,16 +118,15 @@ export default defineConfig(({ command }) => {
109
118
  const localStorageBasePath = ensurePublicPath(`${resolvedAppPublicPath}storage/uploads/`, '/storage/uploads/');
110
119
  const staticBasePath = ensurePublicPath(`${resolvedAppPublicPath}static/`, '/static/');
111
120
  const wsBasePath = ensurePublicPath(process.env.WS_PATH, '/ws/');
112
- const modernClientPrefix =
113
- String(process.env.APP_MODERN_CLIENT_PREFIX || 'v')
114
- .trim()
115
- .replace(/^\/+|\/+$/g, '') || 'v';
121
+ const modernClientPrefix = normalizeModernClientPrefix(process.env.APP_MODERN_CLIENT_PREFIX);
116
122
  const v2BasePath = ensurePublicPath(
117
123
  `${resolvedAppPublicPath.replace(/\/$/, '')}/${modernClientPrefix}/`,
118
124
  `/${modernClientPrefix}/`,
119
125
  );
126
+ const portalBasePath = ensurePublicPath(`${resolvedAppPublicPath.replace(/\/$/, '')}/x/`, '/x/');
120
127
  const clientPort = toNumber(process.env.APP_PORT, 13001);
121
128
  const v2Port = toNumber(process.env.APP_V2_PORT, clientPort + 2);
129
+ const settingsPort = toNumber(process.env.APP_SETTINGS_PORT, clientPort + 3);
122
130
  const hmrPath = `${resolvedAppPublicPath.replace(/\/$/, '')}/__rspack_hmr`;
123
131
  const proxyTargetUrl = process.env.PROXY_TARGET_URL || `http://127.0.0.1:${clientPort + 1}`;
124
132
  const hmrClientHost = process.env.RSPACK_HMR_CLIENT_HOST;
@@ -207,8 +215,10 @@ export default defineConfig(({ command }) => {
207
215
  publicDir: {
208
216
  name: path.resolve(__dirname, 'public'),
209
217
  },
210
- proxy: {
211
- [apiBasePath]: {
218
+ proxy: [
219
+ createSettingsDevProxyOptions(resolvedAppPublicPath, settingsPort),
220
+ {
221
+ context: apiBasePath,
212
222
  target: proxyTargetUrl,
213
223
  changeOrigin: true,
214
224
  ws: true,
@@ -226,25 +236,30 @@ export default defineConfig(({ command }) => {
226
236
  }
227
237
  },
228
238
  },
229
- [localStorageBasePath]: {
239
+ {
240
+ context: localStorageBasePath,
230
241
  target: proxyTargetUrl,
231
242
  changeOrigin: true,
232
243
  },
233
- [fileBasePath]: {
244
+ {
245
+ context: fileBasePath,
234
246
  target: proxyTargetUrl,
235
247
  changeOrigin: true,
236
248
  },
237
- [staticBasePath]: {
249
+ {
250
+ context: staticBasePath,
238
251
  target: proxyTargetUrl,
239
252
  changeOrigin: true,
240
253
  },
241
- [wsBasePath]: {
254
+ {
255
+ context: wsBasePath,
242
256
  target: proxyTargetUrl,
243
257
  changeOrigin: true,
244
258
  ws: true,
245
259
  xfwd: true,
246
260
  },
247
- [v2BasePath]: {
261
+ {
262
+ context: v2BasePath,
248
263
  target: `http://127.0.0.1:${v2Port}`,
249
264
  changeOrigin: true,
250
265
  ws: true,
@@ -253,7 +268,14 @@ export default defineConfig(({ command }) => {
253
268
  },
254
269
  xfwd: true,
255
270
  },
256
- },
271
+ {
272
+ context: portalBasePath,
273
+ target: proxyTargetUrl,
274
+ changeOrigin: true,
275
+ ws: true,
276
+ xfwd: true,
277
+ },
278
+ ],
257
279
  historyApiFallback: {
258
280
  disableDotRule: true,
259
281
  index: `${resolvedAppPublicPath}index.html`,
@@ -0,0 +1,36 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import path from 'node:path';
11
+ import { IndexGenerator } from '../../devtools/common.js';
12
+
13
+ type V2PluginIndexGenerator = new (
14
+ outputPath: string,
15
+ pluginPaths: string[],
16
+ options: {
17
+ clientModuleName: string;
18
+ clientRootFile: string;
19
+ clientSourceDir: string;
20
+ },
21
+ ) => { generate(): void };
22
+
23
+ function getPluginDirectories() {
24
+ return (process.env.PLUGIN_PATH || 'packages/plugins/,packages/samples/,packages/pro-plugins/')
25
+ .split(',')
26
+ .map((directory) => path.resolve(process.cwd(), directory));
27
+ }
28
+
29
+ export function generateSettingsPluginImports(outputPath: string, pluginPaths = getPluginDirectories()) {
30
+ const Generator = IndexGenerator as unknown as V2PluginIndexGenerator;
31
+ new Generator(outputPath, pluginPaths, {
32
+ clientModuleName: 'client-v2',
33
+ clientRootFile: 'client-v2.js',
34
+ clientSourceDir: 'client-v2',
35
+ }).generate();
36
+ }
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
+ <title>Loading...</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ </body>
11
+ </html>