@nocobase/cli-v1 3.0.0-alpha.1 → 3.0.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/nocobase.conf.tpl CHANGED
@@ -214,14 +214,28 @@ server {
214
214
 
215
215
 
216
216
 
217
- location ^~ {{publicPath}}x/apps/ {
217
+ location = {{publicPath}}{{portalClientPrefix}} {
218
218
  absolute_redirect off;
219
+ return 302 {{v2PublicPath}}$is_args$args;
220
+ }
221
+
222
+ location = {{publicPath}}{{portalClientPrefix}}/ {
223
+ absolute_redirect off;
224
+ return 302 {{v2PublicPath}}$is_args$args;
225
+ }
226
+
227
+ location ^~ {{publicPath}}{{portalClientPrefix}}/apps/ {
228
+ absolute_redirect off;
229
+
230
+ if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/?$) {
231
+ return 302 {{v2PublicPath}}apps/$subapp/$is_args$args;
232
+ }
219
233
 
220
- if ($uri ~ ^{{publicPath}}x/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)$) {
221
- return 308 {{publicPath}}x/apps/$subapp/$portal/$is_args$args;
234
+ if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)$) {
235
+ return 308 {{publicPath}}{{portalClientPrefix}}/apps/$subapp/$portal/$is_args$args;
222
236
  }
223
237
 
224
- if ($uri !~ ^{{publicPath}}x/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
238
+ if ($uri !~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
225
239
  return 404;
226
240
  }
227
241
 
@@ -238,14 +252,14 @@ server {
238
252
  =404;
239
253
  }
240
254
 
241
- location ^~ {{publicPath}}x/ {
255
+ location ^~ {{publicPath}}{{portalClientPrefix}}/ {
242
256
  absolute_redirect off;
243
257
 
244
- if ($uri ~ ^{{publicPath}}x/(?<portal>[A-Za-z0-9_-]+)$) {
245
- return 308 {{publicPath}}x/$portal/$is_args$args;
258
+ if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/(?<portal>[A-Za-z0-9_-]+)$) {
259
+ return 308 {{publicPath}}{{portalClientPrefix}}/$portal/$is_args$args;
246
260
  }
247
261
 
248
- if ($uri !~ ^{{publicPath}}x/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
262
+ if ($uri !~ ^{{publicPath}}{{portalClientPrefix}}/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
249
263
  return 404;
250
264
  }
251
265
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/cli-v1",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-alpha.12",
4
4
  "description": "",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./src/index.js",
@@ -9,9 +9,9 @@
9
9
  "nocobase-v1": "./bin/index.js"
10
10
  },
11
11
  "dependencies": {
12
- "@nocobase/cli": "3.0.0-alpha.1",
12
+ "@nocobase/cli": "3.0.0-alpha.12",
13
13
  "@nocobase/license-kit": "^0.3.8",
14
- "@nocobase/utils": "3.0.0-alpha.1",
14
+ "@nocobase/utils": "3.0.0-alpha.12",
15
15
  "chalk": "^4.1.1",
16
16
  "commander": "^9.2.0",
17
17
  "deepmerge": "^4.3.1",
@@ -33,5 +33,5 @@
33
33
  "url": "git+https://github.com/nocobase/nocobase.git",
34
34
  "directory": "packages/core/cli"
35
35
  },
36
- "gitHead": "22d8be8ece179cfa5c8a4ebb2c896c92bd418e03"
36
+ "gitHead": "2ba035885741a9977d76bbabf8f2caf44b199139"
37
37
  }
@@ -87,6 +87,20 @@ describe('cli-v1 buildIndexHtml', () => {
87
87
  fs.removeSync(appRoot);
88
88
  });
89
89
 
90
+ test('injects settings-default as a valid client entry mode', () => {
91
+ const appRoot = createAppPackageRoot();
92
+ process.argv = ['node', 'nocobase-v1', 'start'];
93
+ process.env.APP_PACKAGE_ROOT = appRoot;
94
+ process.env.APP_PUBLIC_PATH = '/';
95
+ process.env.APP_CLIENT_ENTRY_MODE = 'settings-default';
96
+
97
+ buildIndexHtml();
98
+
99
+ const html = fs.readFileSync(path.join(appRoot, 'dist/client/index.html'), 'utf-8');
100
+ expect(html).toContain("window['__nocobase_app_client_entry_mode__'] = 'settings-default';");
101
+ fs.removeSync(appRoot);
102
+ });
103
+
90
104
  test('refreshes cached tpl when new runtime placeholders are missing', () => {
91
105
  const appRoot = createAppPackageRoot();
92
106
  const tplPath = path.join(appRoot, 'dist/client/index.html.tpl');
@@ -15,7 +15,7 @@ const path = require('path');
15
15
 
16
16
  const registerCreateNginxConf = require('../commands/create-nginx-conf');
17
17
 
18
- describe('create-nginx-conf Settings SPA routing', () => {
18
+ describe('create-nginx-conf routing', () => {
19
19
  const originalEnv = { ...process.env };
20
20
  let storagePath;
21
21
 
@@ -65,4 +65,23 @@ describe('create-nginx-conf Settings SPA routing', () => {
65
65
  expect(config).toContain('try_files $uri $uri/ /index.html;');
66
66
  },
67
67
  );
68
+
69
+ test.each([
70
+ ['root mount', '/', '/x', '/v/'],
71
+ ['custom public path', '/nocobase/', '/nocobase/x', '/nocobase/v/'],
72
+ ])('redirects Portal roots to the Modern Client for %s', async (_label, publicPath, portalRoot, modernRoot) => {
73
+ const config = await renderConfig(publicPath);
74
+
75
+ expect(config).toContain(`location = ${portalRoot} {
76
+ absolute_redirect off;
77
+ return 302 ${modernRoot}$is_args$args;
78
+ }`);
79
+ expect(config).toContain(`location = ${portalRoot}/ {
80
+ absolute_redirect off;
81
+ return 302 ${modernRoot}$is_args$args;
82
+ }`);
83
+ expect(config).toContain(`return 302 ${modernRoot}$is_args$args;`);
84
+ expect(config).toContain(`if ($uri ~ ^${portalRoot}/apps/(?<subapp>[A-Za-z0-9_-]+)/?$) {`);
85
+ expect(config).toContain(`return 302 ${modernRoot}apps/$subapp/$is_args$args;`);
86
+ });
68
87
  });
@@ -67,6 +67,16 @@ describe('cli-v1 dev command', () => {
67
67
  });
68
68
  });
69
69
 
70
+ test('resolveDevRuntimeMode keeps all clients in settings-default', () => {
71
+ expect(resolveDevRuntimeMode({ appClientEntryMode: 'settings-default' })).toMatchObject({
72
+ useModernOnlyEntryMode: false,
73
+ shouldRunClient: true,
74
+ shouldRunClientV2: true,
75
+ shouldRunSettings: true,
76
+ shouldRunServer: true,
77
+ });
78
+ });
79
+
70
80
  test('resolveDevRuntimeMode preserves explicit client-v2-only flag behavior', () => {
71
81
  expect(resolveDevRuntimeMode({ clientV2Only: true, appClientEntryMode: 'legacy-default' })).toMatchObject({
72
82
  useModernOnlyEntryMode: false,
@@ -11,6 +11,8 @@ const { resolve, posix } = require('path');
11
11
  const { storagePathJoin, resolvePublicPath, resolveV2PublicPath, normalizeModernClientPrefix } = require('../util');
12
12
  const { readFileSync, writeFileSync } = require('fs');
13
13
 
14
+ const PORTAL_CLIENT_PREFIX = 'x';
15
+
14
16
  function escapeRegExp(value) {
15
17
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
16
18
  }
@@ -70,6 +72,7 @@ module.exports = (cli) => {
70
72
  .replace(/\{\{distPath\}\}/g, distPath)
71
73
  .replace(/\{\{v2PublicPath\}\}/g, v2PublicPath)
72
74
  .replace(/\{\{v2PublicPathNoTrailingSlash\}\}/g, v2PublicPathWithoutTrailingSlash)
75
+ .replace(/\{\{portalClientPrefix\}\}/g, PORTAL_CLIENT_PREFIX)
73
76
  .replace(/\{\{settingsAssetsPath\}\}/g, settingsAssetsPath)
74
77
  .replace(/\{\{settingsDocumentPattern\}\}/g, settingsDocumentPattern)
75
78
  .replace(/\{\{apiPort\}\}/g, process.env.APP_PORT)
@@ -57,6 +57,8 @@ function createCdnClient() {
57
57
  * @param {string} timestampDir
58
58
  */
59
59
  const REWRITE_RULES = [
60
+ // AI API 请求保持原路径,避免被后续规则补上文档版本的时间戳前缀
61
+ { sourceUrl: '^/api/ai/(.*)$', targetTemplate: () => '/api/ai/$1', flag: 'break' },
60
62
  // /en/ 下无后缀的页面路由,去掉 /en/ 前缀并改写到目录式 index.html
61
63
  { sourceUrl: '^/en/([^.]*[^/.])$', targetTemplate: (ts) => `/${ts}/$1/index.html`, flag: 'break' },
62
64
  // 其他语言和默认语言的无后缀页面路由,统一改写到目录式 index.html
@@ -147,7 +149,11 @@ async function waitForRewriteRule(cdnClient, domain, timestampDir) {
147
149
  if (!config) return false;
148
150
  const args = config.functionArgs?.functionArg || [];
149
151
  const targetArg = args.find((a) => a.argName === 'target_url');
150
- return config.status === 'success' && (targetArg?.argValue || '').startsWith(expectedPrefix);
152
+ const expectedTarget = rule.targetTemplate(timestampDir);
153
+ const targetMatches = expectedTarget.startsWith(expectedPrefix)
154
+ ? (targetArg?.argValue || '').startsWith(expectedPrefix)
155
+ : targetArg?.argValue === expectedTarget;
156
+ return config.status === 'success' && targetMatches;
151
157
  });
152
158
 
153
159
  if (allEffective) {
package/src/util.js CHANGED
@@ -433,7 +433,7 @@ const DEFAULT_MODERN_CLIENT_PREFIX = 'v';
433
433
  exports.DEFAULT_MODERN_CLIENT_PREFIX = DEFAULT_MODERN_CLIENT_PREFIX;
434
434
 
435
435
  const DEFAULT_APP_CLIENT_ENTRY_MODE = 'legacy-default';
436
- const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only']);
436
+ const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only', 'settings-default']);
437
437
 
438
438
  exports.DEFAULT_APP_CLIENT_ENTRY_MODE = DEFAULT_APP_CLIENT_ENTRY_MODE;
439
439