@pactor-app/module-pack 1.55.0 → 1.57.0

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/dist/index.cjs CHANGED
@@ -21,18 +21,28 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  CLIENT_EXTERNALS: () => CLIENT_EXTERNALS,
24
+ CLIENT_STYLES_ENTRY: () => CLIENT_STYLES_ENTRY,
24
25
  CONFIG_DEFAULTS: () => CONFIG_DEFAULTS,
25
26
  CONFIG_FILE: () => CONFIG_FILE,
26
27
  ConfigError: () => ConfigError,
27
28
  DEFAULT_TARGET: () => DEFAULT_TARGET,
28
29
  INCLUDE_KEY: () => INCLUDE_KEY,
29
30
  IncludeError: () => IncludeError,
31
+ MODULE_ID_PREFIX: () => MODULE_ID_PREFIX,
30
32
  ModuleBuildError: () => ModuleBuildError,
31
33
  ProfileError: () => ProfileError,
34
+ SERVER_BUNDLE_FILE: () => SERVER_BUNDLE_FILE,
35
+ SERVER_ENTRY: () => SERVER_ENTRY,
36
+ SERVER_EXTERNALS: () => SERVER_EXTERNALS,
37
+ ServerBundleError: () => ServerBundleError,
32
38
  buildModule: () => buildModule,
39
+ bumpPackageVersion: () => bumpPackageVersion,
40
+ bumpVersion: () => bumpVersion,
33
41
  bundleClient: () => bundleClient,
42
+ bundleServer: () => bundleServer,
34
43
  collectModuleSource: () => collectModuleSource,
35
44
  compileTailwind: () => compileTailwind,
45
+ deriveApiPrefix: () => deriveApiPrefix,
36
46
  deriveModuleId: () => deriveModuleId,
37
47
  discoverActions: () => discoverActions,
38
48
  discoverComponents: () => discoverComponents,
@@ -43,6 +53,7 @@ __export(index_exports, {
43
53
  initModule: () => initModule,
44
54
  innospotsWebShellV1: () => innospotsWebShellV1,
45
55
  innospotsWebShellV2: () => innospotsWebShellV2,
56
+ innospotsWebShellV3: () => innospotsWebShellV3,
46
57
  listProfiles: () => listProfiles,
47
58
  loadModuleConfig: () => loadModuleConfig,
48
59
  loadYamlExpanded: () => loadYamlExpanded,
@@ -51,6 +62,8 @@ __export(index_exports, {
51
62
  parseYamlFile: () => parseYamlFile,
52
63
  readProjectVersion: () => readProjectVersion,
53
64
  renderClientEntry: () => renderClientEntry,
65
+ renderModuleStyles: () => renderModuleStyles,
66
+ renderServerEntry: () => renderServerEntry,
54
67
  resolvePactorVersionRange: () => resolvePactorVersionRange,
55
68
  rewriteDslUrls: () => rewriteDslUrls,
56
69
  rewriteNavigationTo: () => rewriteNavigationTo,
@@ -62,8 +75,8 @@ __export(index_exports, {
62
75
  module.exports = __toCommonJS(index_exports);
63
76
 
64
77
  // src/build.ts
65
- var import_node_fs9 = require("fs");
66
- var import_node_path9 = require("path");
78
+ var import_node_fs10 = require("fs");
79
+ var import_node_path10 = require("path");
67
80
 
68
81
  // src/bundle-client.ts
69
82
  var import_node_fs = require("fs");
@@ -180,17 +193,68 @@ function parseJsonc(text) {
180
193
  return JSON.parse(out.replace(/,(\s*[}\]])/g, "$1"));
181
194
  }
182
195
 
183
- // src/collect.ts
196
+ // src/bundle-server.ts
184
197
  var import_node_fs2 = require("fs");
185
198
  var import_node_path2 = require("path");
199
+ var import_esbuild2 = require("esbuild");
200
+ var SERVER_EXTERNALS = [
201
+ "react",
202
+ "react-dom",
203
+ "react-dom/*",
204
+ "next",
205
+ "next/*",
206
+ "pactor-app",
207
+ "pactor-app/*",
208
+ "@pactor-app/*"
209
+ ];
210
+ var SERVER_BUNDLE_FILE = "index.mjs";
211
+ var ServerBundleError = class extends Error {
212
+ };
213
+ function bundleServer(options) {
214
+ const projectRoot = (0, import_node_path2.resolve)(options.projectDir);
215
+ const entry = (0, import_node_path2.resolve)(projectRoot, options.serverEntry);
216
+ if (!entry.startsWith(`${projectRoot}${import_node_path2.sep}`)) {
217
+ throw new ServerBundleError(
218
+ `server \u5165\u53E3\u5FC5\u987B\u4F4D\u4E8E\u5DE5\u7A0B\u6839\u5185: ${options.serverEntry}`
219
+ );
220
+ }
221
+ if (!(0, import_node_fs2.existsSync)(entry)) {
222
+ throw new ServerBundleError(`server \u5165\u53E3\u4E0D\u5B58\u5728: ${options.serverEntry}`);
223
+ }
224
+ (0, import_node_fs2.mkdirSync)(options.outDir, { recursive: true });
225
+ (0, import_esbuild2.buildSync)({
226
+ entryPoints: [entry],
227
+ bundle: true,
228
+ format: "esm",
229
+ platform: "node",
230
+ target: "node20",
231
+ outdir: options.outDir,
232
+ entryNames: "index",
233
+ outExtension: { ".js": ".mjs" },
234
+ sourcemap: true,
235
+ alias: tsconfigAliases(projectRoot),
236
+ external: [...SERVER_EXTERNALS],
237
+ logLevel: "silent"
238
+ });
239
+ if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(options.outDir, SERVER_BUNDLE_FILE))) {
240
+ throw new ServerBundleError(
241
+ `server \u6253\u5305\u672A\u4EA7\u51FA ${SERVER_BUNDLE_FILE}\uFF08\u8BF7\u68C0\u67E5 serverEntry \u4E0E esbuild \u914D\u7F6E\uFF09`
242
+ );
243
+ }
244
+ return { bundled: true, entry: SERVER_BUNDLE_FILE };
245
+ }
246
+
247
+ // src/collect.ts
248
+ var import_node_fs3 = require("fs");
249
+ var import_node_path3 = require("path");
186
250
  function collectModuleSource(yamlRoot) {
187
251
  const pages = /* @__PURE__ */ new Map();
188
252
  const layouts = [];
189
253
  const fragments = [];
190
254
  const warnings = [];
191
255
  const walk = (dir) => {
192
- for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
193
- const full = (0, import_node_path2.join)(dir, entry.name);
256
+ for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
257
+ const full = (0, import_node_path3.join)(dir, entry.name);
194
258
  if (entry.isDirectory()) {
195
259
  walk(full);
196
260
  continue;
@@ -198,7 +262,7 @@ function collectModuleSource(yamlRoot) {
198
262
  if (!entry.name.endsWith(".yaml") || entry.name === "sitemap.yaml") {
199
263
  continue;
200
264
  }
201
- const rel = (0, import_node_path2.relative)(yamlRoot, full);
265
+ const rel = (0, import_node_path3.relative)(yamlRoot, full);
202
266
  if (entry.name.endsWith(".layout.yaml")) {
203
267
  layouts.push(rel);
204
268
  continue;
@@ -225,20 +289,20 @@ function collectModuleSource(yamlRoot) {
225
289
 
226
290
  // src/compile-styles.ts
227
291
  var import_node_child_process = require("child_process");
228
- var import_node_fs3 = require("fs");
292
+ var import_node_fs4 = require("fs");
229
293
  var import_node_os = require("os");
230
- var import_node_path3 = require("path");
294
+ var import_node_path4 = require("path");
231
295
  function compileTailwind(options) {
232
296
  const warnings = [];
233
297
  if (!options.tailwind.enabled) {
234
298
  return { compiled: false, warnings };
235
299
  }
236
- const work = (0, import_node_fs3.mkdtempSync)((0, import_node_path3.join)((0, import_node_os.tmpdir)(), "pactor-tailwind-"));
300
+ const work = (0, import_node_fs4.mkdtempSync)((0, import_node_path4.join)((0, import_node_os.tmpdir)(), "pactor-tailwind-"));
237
301
  try {
238
302
  let input;
239
303
  if (options.tailwind.input !== void 0) {
240
- input = (0, import_node_path3.join)(options.projectDir, options.tailwind.input);
241
- if (!(0, import_node_fs3.existsSync)(input)) {
304
+ input = (0, import_node_path4.join)(options.projectDir, options.tailwind.input);
305
+ if (!(0, import_node_fs4.existsSync)(input)) {
242
306
  warnings.push(`tailwind.input \u4E0D\u5B58\u5728: ${options.tailwind.input}\uFF0C\u8DF3\u8FC7\u9884\u7F16\u8BD1`);
243
307
  return { compiled: false, warnings };
244
308
  }
@@ -246,22 +310,22 @@ function compileTailwind(options) {
246
310
  const scan = (options.tailwind.scan ?? options.scanDirs).map(
247
311
  (dir) => `@source "${dir.replace(/\\/g, "/")}";`
248
312
  );
249
- input = (0, import_node_path3.join)(work, "input.css");
250
- (0, import_node_fs3.writeFileSync)(input, `@import "tailwindcss";
313
+ input = (0, import_node_path4.join)(work, "input.css");
314
+ (0, import_node_fs4.writeFileSync)(input, `@import "tailwindcss";
251
315
  ${scan.join("\n")}
252
316
  `, "utf8");
253
317
  }
254
- const out = (0, import_node_path3.join)(work, "tailwind.css");
318
+ const out = (0, import_node_path4.join)(work, "tailwind.css");
255
319
  (0, import_node_child_process.execFileSync)(
256
320
  "npx",
257
321
  ["--no-install", "tailwindcss", "--input", input, "--output", out],
258
322
  { cwd: options.projectDir, stdio: "pipe" }
259
323
  );
260
- if ((0, import_node_fs3.existsSync)(out)) {
261
- const css = (0, import_node_fs3.readFileSync)(out, "utf8");
324
+ if ((0, import_node_fs4.existsSync)(out)) {
325
+ const css = (0, import_node_fs4.readFileSync)(out, "utf8");
262
326
  if (css.trim().length > 0) {
263
- (0, import_node_fs3.mkdirSync)((0, import_node_path3.dirname)(options.cssFile), { recursive: true });
264
- (0, import_node_fs3.appendFileSync)(
327
+ (0, import_node_fs4.mkdirSync)((0, import_node_path4.dirname)(options.cssFile), { recursive: true });
328
+ (0, import_node_fs4.appendFileSync)(
265
329
  options.cssFile,
266
330
  `
267
331
  /* tailwind utilities\uFF08pactor module build \u9884\u7F16\u8BD1\uFF09 */
@@ -278,13 +342,13 @@ ${css}`,
278
342
  warnings.push(`tailwind \u4E0D\u53EF\u7528\u6216\u7F16\u8BD1\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u8DF3\u8FC7\u9884\u7F16\u8BD1\uFF08${firstLine}\uFF09`);
279
343
  return { compiled: false, warnings };
280
344
  } finally {
281
- (0, import_node_fs3.rmSync)(work, { recursive: true, force: true });
345
+ (0, import_node_fs4.rmSync)(work, { recursive: true, force: true });
282
346
  }
283
347
  }
284
348
 
285
349
  // src/config.ts
286
- var import_node_fs4 = require("fs");
287
- var import_node_path4 = require("path");
350
+ var import_node_fs5 = require("fs");
351
+ var import_node_path5 = require("path");
288
352
 
289
353
  // src/profiles/innospots-web-shell.ts
290
354
  var base = {
@@ -293,7 +357,8 @@ var base = {
293
357
  stripMenuPaths: true,
294
358
  rewriteNavigation: { basePath: true, excludeApiUrls: true },
295
359
  rewriteAssetUrls: (id, version) => `/modules/${id}/${version}/`,
296
- forbidRootBasePath: true
360
+ forbidRootBasePath: true,
361
+ moduleServerApi: false
297
362
  };
298
363
  var innospotsWebShellV1 = {
299
364
  ...base,
@@ -305,15 +370,22 @@ var innospotsWebShellV2 = {
305
370
  version: 2,
306
371
  forceInlinePages: false
307
372
  };
373
+ var innospotsWebShellV3 = {
374
+ ...base,
375
+ version: 3,
376
+ forceInlinePages: false,
377
+ moduleServerApi: true
378
+ };
308
379
 
309
380
  // src/profiles/index.ts
310
381
  var ProfileError = class extends Error {
311
382
  };
312
383
  var registry = /* @__PURE__ */ new Map([
313
384
  [`${innospotsWebShellV1.name}@${innospotsWebShellV1.version}`, innospotsWebShellV1],
314
- [`${innospotsWebShellV2.name}@${innospotsWebShellV2.version}`, innospotsWebShellV2]
385
+ [`${innospotsWebShellV2.name}@${innospotsWebShellV2.version}`, innospotsWebShellV2],
386
+ [`${innospotsWebShellV3.name}@${innospotsWebShellV3.version}`, innospotsWebShellV3]
315
387
  ]);
316
- var DEFAULT_TARGET = `${innospotsWebShellV2.name}@${innospotsWebShellV2.version}`;
388
+ var DEFAULT_TARGET = `${innospotsWebShellV3.name}@${innospotsWebShellV3.version}`;
317
389
  function listProfiles() {
318
390
  return [...registry.keys()];
319
391
  }
@@ -337,13 +409,13 @@ var CONFIG_DEFAULTS = {
337
409
  outDir: "dist-module"
338
410
  };
339
411
  function loadModuleConfig(projectDir, configPath) {
340
- const file = configPath ? (0, import_node_path4.resolve)(projectDir, configPath) : (0, import_node_path4.join)(projectDir, CONFIG_FILE);
341
- if (!(0, import_node_fs4.existsSync)(file)) {
412
+ const file = configPath ? (0, import_node_path5.resolve)(projectDir, configPath) : (0, import_node_path5.join)(projectDir, CONFIG_FILE);
413
+ if (!(0, import_node_fs5.existsSync)(file)) {
342
414
  throw new ConfigError(`\u7F3A\u5C11\u914D\u7F6E\u6587\u4EF6: ${file}\uFF08\u53EF\u5148\u6267\u884C pactor module init \u751F\u6210\uFF09`);
343
415
  }
344
416
  let raw;
345
417
  try {
346
- raw = JSON.parse((0, import_node_fs4.readFileSync)(file, "utf8"));
418
+ raw = JSON.parse((0, import_node_fs5.readFileSync)(file, "utf8"));
347
419
  } catch (error) {
348
420
  throw new ConfigError(`\u914D\u7F6E\u89E3\u6790\u5931\u8D25: ${file}: ${error.message}`);
349
421
  }
@@ -359,19 +431,32 @@ function loadModuleConfig(projectDir, configPath) {
359
431
  if (!basePath.startsWith("/")) basePath = `/${basePath}`;
360
432
  if (basePath.length > 1 && basePath.endsWith("/")) basePath = basePath.slice(0, -1);
361
433
  const actions = raw.actions === void 0 ? [] : readStringArray(raw.actions, "actions", file);
362
- const demo = isRecord(raw.demo) ? raw.demo : {};
434
+ if (raw.demo !== void 0) {
435
+ throw new ConfigError(
436
+ `${file}: demo.public \u5DF2\u79FB\u9664\uFF0C\u8BF7\u6539\u7528 "access": { "default": "public" }\uFF08\u7F3A\u7701\u586B\u5145\u8BED\u4E49\uFF0C\u4E0D\u8986\u76D6\u663E\u5F0F permission\uFF09`
437
+ );
438
+ }
439
+ const access = isRecord(raw.access) ? raw.access : {};
440
+ const accessDefault = readString(access, "default", file, "access") ?? "authenticated";
441
+ if (accessDefault !== "public" && accessDefault !== "authenticated") {
442
+ throw new ConfigError(`${file}: access.default \u53EA\u652F\u6301 "public" | "authenticated"`);
443
+ }
363
444
  const tailwind = isRecord(raw.tailwind) ? raw.tailwind : {};
364
445
  const rewrite = isRecord(raw.rewrite) ? raw.rewrite : {};
446
+ const serverEntry = readString(raw, "serverEntry", file);
447
+ const apiPrefixes = raw.apiPrefixes === void 0 ? void 0 : readStringArray(raw.apiPrefixes, "apiPrefixes", file);
448
+ validateServerConfig({ id, serverEntry, apiPrefixes, file });
365
449
  return {
366
450
  id,
367
451
  name,
368
452
  basePath,
369
453
  yamlRoot: readString(raw, "yamlRoot", file) ?? CONFIG_DEFAULTS.yamlRoot,
370
454
  clientEntry: readString(raw, "clientEntry", file) ?? CONFIG_DEFAULTS.clientEntry,
455
+ ...serverEntry !== void 0 ? { serverEntry, apiPrefixes } : {},
371
456
  actions,
372
457
  publicDir: readString(raw, "publicDir", file) ?? CONFIG_DEFAULTS.publicDir,
373
458
  target: readString(raw, "target", file) ?? CONFIG_DEFAULTS.target,
374
- demo: { public: readBoolean(demo, "public", file, "demo") ?? false },
459
+ access: { default: accessDefault },
375
460
  tailwind: {
376
461
  enabled: readBoolean(tailwind, "enabled", file, "tailwind") ?? false,
377
462
  input: readString(tailwind, "input", file, "tailwind"),
@@ -409,12 +494,59 @@ function readStringArray(value, label, file) {
409
494
  }
410
495
  return value;
411
496
  }
497
+ var URL_SAFE_MODULE_ID_RE = /^[A-Za-z0-9._~-]+$/;
498
+ var API_PREFIX_RE = /^\/api\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/;
499
+ var RESERVED_API_PREFIXES = ["/api/modules", "/api/runtime"];
500
+ function validateServerConfig(input) {
501
+ const { id, serverEntry, apiPrefixes, file } = input;
502
+ if (serverEntry === void 0 && apiPrefixes === void 0) return;
503
+ if (serverEntry === void 0 || apiPrefixes === void 0) {
504
+ throw new ConfigError(`${file}: serverEntry \u4E0E apiPrefixes \u5FC5\u987B\u540C\u65F6\u914D\u7F6E\uFF08\u7F3A\u4E00\u4E0D\u53EF\uFF09`);
505
+ }
506
+ if (apiPrefixes.length === 0) {
507
+ throw new ConfigError(`${file}: \u914D\u7F6E serverEntry \u65F6 apiPrefixes \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4`);
508
+ }
509
+ if (!URL_SAFE_MODULE_ID_RE.test(id)) {
510
+ throw new ConfigError(
511
+ `${file}: \u542F\u7528 serverEntry \u65F6 id \u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001. _ ~ -\uFF08\u5F53\u524D: ${JSON.stringify(id)}\uFF09`
512
+ );
513
+ }
514
+ for (const prefix of apiPrefixes) {
515
+ if (!API_PREFIX_RE.test(prefix)) {
516
+ throw new ConfigError(
517
+ `${file}: apiPrefixes \u542B\u975E\u6CD5\u524D\u7F00 ${JSON.stringify(prefix)}\uFF08\u8981\u6C42\u5F62\u5982 /api/risk-analysis\uFF0C\u4E0D\u80FD\u542B query / hash / \u5C3E\u659C\u6760 / \u901A\u914D / :param\uFF09`
518
+ );
519
+ }
520
+ const reserved = RESERVED_API_PREFIXES.find(
521
+ (item) => prefix === item || prefix.startsWith(`${item}/`)
522
+ );
523
+ if (reserved) {
524
+ throw new ConfigError(
525
+ `${file}: apiPrefixes \u4E0D\u80FD\u4F7F\u7528\u4FDD\u7559\u524D\u7F00 ${reserved}\uFF08Shell \u81EA\u5E26\u8DEF\u7531\uFF09: ${prefix}`
526
+ );
527
+ }
528
+ }
529
+ for (let i = 0; i < apiPrefixes.length; i += 1) {
530
+ for (let j = i + 1; j < apiPrefixes.length; j += 1) {
531
+ const a = apiPrefixes[i];
532
+ const b = apiPrefixes[j];
533
+ if (a === b) {
534
+ throw new ConfigError(`${file}: apiPrefixes \u5B58\u5728\u91CD\u590D\u524D\u7F00: ${a}`);
535
+ }
536
+ if (a.startsWith(`${b}/`) || b.startsWith(`${a}/`)) {
537
+ throw new ConfigError(
538
+ `${file}: apiPrefixes \u524D\u7F00\u4E92\u76F8\u5305\u542B\uFF08\u540C\u4E00\u6A21\u5757\u5185\u65E0\u6CD5\u786E\u5B9A\u5F52\u5C5E\uFF09: ${a} / ${b}`
539
+ );
540
+ }
541
+ }
542
+ }
543
+ }
412
544
 
413
545
  // src/emit-manifest.ts
414
546
  var import_node_crypto = require("crypto");
415
- var import_node_fs5 = require("fs");
547
+ var import_node_fs6 = require("fs");
416
548
  var import_node_module = require("module");
417
- var import_node_path5 = require("path");
549
+ var import_node_path6 = require("path");
418
550
  var import_yaml = require("yaml");
419
551
  function emitModule(input) {
420
552
  const dslResult = emitDsl(input);
@@ -423,22 +555,22 @@ function emitModule(input) {
423
555
  }
424
556
  function emitDsl(input) {
425
557
  const { config, projectDir, outDir, site, pages } = input;
426
- const dslDir = (0, import_node_path5.join)(outDir, "dsl");
427
- (0, import_node_fs5.mkdirSync)(dslDir, { recursive: true });
428
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dslDir, "sitemap.yaml"), (0, import_yaml.stringify)(site, { lineWidth: 0 }), "utf8");
558
+ const dslDir = (0, import_node_path6.join)(outDir, "dsl");
559
+ (0, import_node_fs6.mkdirSync)(dslDir, { recursive: true });
560
+ (0, import_node_fs6.writeFileSync)((0, import_node_path6.join)(dslDir, "sitemap.yaml"), (0, import_yaml.stringify)(site, { lineWidth: 0 }), "utf8");
429
561
  for (const [id, dsl] of pages) {
430
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dslDir, `${id}.yaml`), (0, import_yaml.stringify)(dsl, { lineWidth: 0 }), "utf8");
562
+ (0, import_node_fs6.writeFileSync)((0, import_node_path6.join)(dslDir, `${id}.yaml`), (0, import_yaml.stringify)(dsl, { lineWidth: 0 }), "utf8");
431
563
  }
432
- const publicDir = (0, import_node_path5.join)(projectDir, config.publicDir);
433
- const assetsDir = (0, import_node_path5.join)(outDir, "assets");
434
- if ((0, import_node_fs5.existsSync)(publicDir)) {
435
- (0, import_node_fs5.cpSync)(publicDir, assetsDir, { recursive: true });
564
+ const publicDir = (0, import_node_path6.join)(projectDir, config.publicDir);
565
+ const assetsDir = (0, import_node_path6.join)(outDir, "assets");
566
+ if ((0, import_node_fs6.existsSync)(publicDir)) {
567
+ (0, import_node_fs6.cpSync)(publicDir, assetsDir, { recursive: true });
436
568
  } else {
437
- (0, import_node_fs5.mkdirSync)(assetsDir, { recursive: true });
569
+ (0, import_node_fs6.mkdirSync)(assetsDir, { recursive: true });
438
570
  }
439
571
  const assets = hashAssets(assetsDir, assetsDir);
440
- (0, import_node_fs5.writeFileSync)(
441
- (0, import_node_path5.join)(outDir, "module-assets.json"),
572
+ (0, import_node_fs6.writeFileSync)(
573
+ (0, import_node_path6.join)(outDir, "module-assets.json"),
442
574
  `${JSON.stringify({ module: config.id, assets }, null, 2)}
443
575
  `,
444
576
  "utf8"
@@ -459,10 +591,12 @@ function writeManifest(input) {
459
591
  dslRoot: "dsl",
460
592
  assetsRoot: "assets",
461
593
  ...input.clientEntry ? { clientEntry: input.clientEntry } : {},
462
- ...input.styles ? { styles: input.styles } : {}
594
+ ...input.styles ? { styles: input.styles } : {},
595
+ ...input.serverEntry ? { serverEntry: input.serverEntry } : {},
596
+ ...input.apiPrefixes && input.apiPrefixes.length > 0 ? { apiPrefixes: input.apiPrefixes } : {}
463
597
  };
464
- (0, import_node_fs5.writeFileSync)(
465
- (0, import_node_path5.join)(outDir, "manifest.json"),
598
+ (0, import_node_fs6.writeFileSync)(
599
+ (0, import_node_path6.join)(outDir, "manifest.json"),
466
600
  `${JSON.stringify(manifest, null, 2)}
467
601
  `,
468
602
  "utf8"
@@ -470,10 +604,10 @@ function writeManifest(input) {
470
604
  return manifest;
471
605
  }
472
606
  function readProjectVersion(projectDir) {
473
- const pkgFile = (0, import_node_path5.join)(projectDir, "package.json");
474
- if (!(0, import_node_fs5.existsSync)(pkgFile)) return "0.0.0";
607
+ const pkgFile = (0, import_node_path6.join)(projectDir, "package.json");
608
+ if (!(0, import_node_fs6.existsSync)(pkgFile)) return "0.0.0";
475
609
  try {
476
- const pkg = JSON.parse((0, import_node_fs5.readFileSync)(pkgFile, "utf8"));
610
+ const pkg = JSON.parse((0, import_node_fs6.readFileSync)(pkgFile, "utf8"));
477
611
  return typeof pkg.version === "string" && pkg.version.length > 0 ? pkg.version : "0.0.0";
478
612
  } catch {
479
613
  return "0.0.0";
@@ -481,18 +615,18 @@ function readProjectVersion(projectDir) {
481
615
  }
482
616
  function resolvePactorVersionRange(projectDir, warnings) {
483
617
  try {
484
- const require2 = (0, import_node_module.createRequire)((0, import_node_path5.join)(projectDir, "package.json"));
618
+ const require2 = (0, import_node_module.createRequire)((0, import_node_path6.join)(projectDir, "package.json"));
485
619
  for (const name of ["pactor-app/package.json", "@pactor-app/app/package.json"]) {
486
620
  try {
487
621
  const pkgFile = require2.resolve(name);
488
- const pkg2 = JSON.parse((0, import_node_fs5.readFileSync)(pkgFile, "utf8"));
622
+ const pkg2 = JSON.parse((0, import_node_fs6.readFileSync)(pkgFile, "utf8"));
489
623
  if (typeof pkg2.version === "string" && pkg2.version.length > 0) {
490
624
  return `^${pkg2.version}`;
491
625
  }
492
626
  } catch {
493
627
  }
494
628
  }
495
- const pkg = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path5.join)(projectDir, "package.json"), "utf8"));
629
+ const pkg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path6.join)(projectDir, "package.json"), "utf8"));
496
630
  for (const section of ["dependencies", "peerDependencies", "devDependencies"]) {
497
631
  const range = pkg[section]?.["pactor-app"];
498
632
  if (typeof range === "string" && range.length > 0) {
@@ -506,35 +640,35 @@ function resolvePactorVersionRange(projectDir, warnings) {
506
640
  }
507
641
  function hashAssets(dir, root) {
508
642
  const entries = [];
509
- if (!(0, import_node_fs5.existsSync)(dir)) return entries;
510
- for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true }).sort(
643
+ if (!(0, import_node_fs6.existsSync)(dir)) return entries;
644
+ for (const entry of (0, import_node_fs6.readdirSync)(dir, { withFileTypes: true }).sort(
511
645
  (a, b) => a.name.localeCompare(b.name)
512
646
  )) {
513
- const full = (0, import_node_path5.join)(dir, entry.name);
647
+ const full = (0, import_node_path6.join)(dir, entry.name);
514
648
  if (entry.isDirectory()) {
515
649
  entries.push(...hashAssets(full, root));
516
650
  continue;
517
651
  }
518
652
  if (!entry.isFile()) continue;
519
- const content = (0, import_node_fs5.readFileSync)(full);
653
+ const content = (0, import_node_fs6.readFileSync)(full);
520
654
  entries.push({
521
655
  path: full.slice(root.length + 1).split("\\").join("/"),
522
656
  sha256: (0, import_node_crypto.createHash)("sha256").update(content).digest("hex"),
523
- size: (0, import_node_fs5.statSync)(full).size
657
+ size: (0, import_node_fs6.statSync)(full).size
524
658
  });
525
659
  }
526
660
  return entries;
527
661
  }
528
662
 
529
663
  // src/expand-include.ts
530
- var import_node_fs6 = require("fs");
531
- var import_node_path6 = require("path");
664
+ var import_node_fs7 = require("fs");
665
+ var import_node_path7 = require("path");
532
666
  var import_yaml2 = require("yaml");
533
667
  var INCLUDE_KEY = "$include";
534
668
  var IncludeError = class extends Error {
535
669
  };
536
670
  function parseYamlFile(file) {
537
- const doc = (0, import_yaml2.parseDocument)((0, import_node_fs6.readFileSync)(file, "utf8"));
671
+ const doc = (0, import_yaml2.parseDocument)((0, import_node_fs7.readFileSync)(file, "utf8"));
538
672
  if (doc.errors.length > 0) {
539
673
  throw new IncludeError(
540
674
  `${file}: ${doc.errors.map((error) => error.message).join("; ")}`
@@ -546,7 +680,7 @@ function loadYamlExpanded(yamlRoot, relPath, stack = []) {
546
680
  if (stack.includes(relPath)) {
547
681
  throw new IncludeError(`\u5FAA\u73AF\u5F15\u7528: ${[...stack, relPath].join(" -> ")}`);
548
682
  }
549
- const value = parseYamlFile((0, import_node_path6.join)(yamlRoot, relPath));
683
+ const value = parseYamlFile((0, import_node_path7.join)(yamlRoot, relPath));
550
684
  return expandIncludes(value, { yamlRoot, current: relPath, stack: [...stack, relPath] });
551
685
  }
552
686
  function expandIncludes(value, ctx) {
@@ -573,8 +707,8 @@ function expandIncludes(value, ctx) {
573
707
  }
574
708
 
575
709
  // src/rewrite-urls.ts
576
- var import_node_fs7 = require("fs");
577
- var import_node_path7 = require("path");
710
+ var import_node_fs8 = require("fs");
711
+ var import_node_path8 = require("path");
578
712
  var NAVIGATION_ACTIONS = /* @__PURE__ */ new Set(["navigate", "app.reload"]);
579
713
  var ABSOLUTE_API_RE = /^https?:\/\/[^/]+(\/api\/.+)$/;
580
714
  function rewriteDslUrls(value, ctx) {
@@ -629,11 +763,14 @@ function matchPathPattern(pattern, value) {
629
763
  function rewriteString(value, ctx, warnings) {
630
764
  const absoluteApi = ABSOLUTE_API_RE.exec(value);
631
765
  if (absoluteApi) {
632
- warnings.push(
633
- `\u7EDD\u5BF9 API \u5730\u5740: ${value}${ctx.absoluteApiToRelative ? "\uFF08\u5DF2\u91CD\u5199\u4E3A\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u9700\u5E95\u5EA7 BFF/\u4EE3\u7406\u627F\u63A5\uFF09" : ""}`
634
- );
635
- return ctx.absoluteApiToRelative ? absoluteApi[1] : value;
766
+ const relative3 = absoluteApi[1];
767
+ const namespaced2 = ctx.absoluteApiToRelative ? namespaceModuleApi(relative3, ctx) : void 0;
768
+ const action = ctx.absoluteApiToRelative ? namespaced2 !== void 0 ? "\uFF08\u5DF2\u91CD\u5199\u4E3A\u6A21\u5757 API \u76F8\u5BF9\u8DEF\u5F84\uFF09" : "\uFF08\u5DF2\u91CD\u5199\u4E3A\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u9700\u5E95\u5EA7 BFF/\u4EE3\u7406\u627F\u63A5\uFF09" : "\uFF08absoluteApiToRelative=false\uFF0C\u4FDD\u6301\u7EDD\u5BF9\u5730\u5740\uFF0C\u4E0D\u4F1A\u8D70\u6A21\u5757 API \u8DEF\u7531\uFF09";
769
+ warnings.push(`\u7EDD\u5BF9 API \u5730\u5740: ${value}${action}`);
770
+ return ctx.absoluteApiToRelative ? namespaced2 ?? relative3 : value;
636
771
  }
772
+ const namespaced = namespaceModuleApi(value, ctx);
773
+ if (namespaced !== void 0) return namespaced;
637
774
  if (!ctx.rewriteAssets) return value;
638
775
  if (!value.startsWith("/") || value.startsWith("//")) return value;
639
776
  if (value.startsWith("/api/")) return value;
@@ -645,10 +782,18 @@ function rewriteString(value, ctx, warnings) {
645
782
  if (!isPublicFile(ctx.publicDir, value)) return value;
646
783
  return `${ctx.assetPrefix}${value}`;
647
784
  }
785
+ function namespaceModuleApi(value, ctx) {
786
+ const { moduleId, apiPrefixes } = ctx;
787
+ if (!moduleId || !apiPrefixes || apiPrefixes.length === 0) return void 0;
788
+ const pathOnly = value.split(/[?#]/, 1)[0];
789
+ const hit = [...apiPrefixes].sort((a, b) => b.length - a.length).some((prefix) => pathOnly === prefix || pathOnly.startsWith(`${prefix}/`));
790
+ if (!hit) return void 0;
791
+ return `/api/modules/${encodeURIComponent(moduleId)}${value.slice("/api".length)}`;
792
+ }
648
793
  function isPublicFile(publicDir, urlPath) {
649
- const file = (0, import_node_path7.join)(publicDir, urlPath);
794
+ const file = (0, import_node_path8.join)(publicDir, urlPath);
650
795
  try {
651
- return (0, import_node_fs7.existsSync)(file) && (0, import_node_fs7.statSync)(file).isFile();
796
+ return (0, import_node_fs8.existsSync)(file) && (0, import_node_fs8.statSync)(file).isFile();
652
797
  } catch {
653
798
  return false;
654
799
  }
@@ -659,7 +804,8 @@ function isRecord2(value) {
659
804
 
660
805
  // src/transform-sitemap.ts
661
806
  function transformSitemap(site, options) {
662
- const { profile, demoPublic, loadLayout } = options;
807
+ const { profile, accessDefault, loadLayout } = options;
808
+ const fillPublic = accessDefault === "public";
663
809
  const next = { ...site };
664
810
  const rawLayouts = isRecord3(site.layouts) ? site.layouts : {};
665
811
  const layouts = {};
@@ -673,7 +819,7 @@ function transformSitemap(site, options) {
673
819
  if (profile.forceInlinePages) {
674
820
  delete nextPage.lazy;
675
821
  }
676
- if (demoPublic) {
822
+ if (fillPublic && isAccessUndeclared(nextPage)) {
677
823
  nextPage.public = true;
678
824
  }
679
825
  return nextPage;
@@ -684,7 +830,7 @@ function transformSitemap(site, options) {
684
830
  if (profile.stripMenuPaths) {
685
831
  delete nextMenu.path;
686
832
  }
687
- if (demoPublic) {
833
+ if (fillPublic && isAccessUndeclared(nextMenu)) {
688
834
  nextMenu.public = true;
689
835
  }
690
836
  if (Array.isArray(nextMenu.children)) {
@@ -705,10 +851,13 @@ function transformSitemap(site, options) {
705
851
  function isRecord3(value) {
706
852
  return value !== null && typeof value === "object" && !Array.isArray(value);
707
853
  }
854
+ function isAccessUndeclared(entry) {
855
+ return entry.public === void 0 && entry.permission === void 0;
856
+ }
708
857
 
709
858
  // src/validate.ts
710
- var import_node_fs8 = require("fs");
711
- var import_node_path8 = require("path");
859
+ var import_node_fs9 = require("fs");
860
+ var import_node_path9 = require("path");
712
861
  var import_yaml3 = require("yaml");
713
862
  var REQUIRED_MANIFEST_FIELDS = [
714
863
  "schemaVersion",
@@ -722,7 +871,7 @@ var REQUIRED_MANIFEST_FIELDS = [
722
871
  "assetsRoot"
723
872
  ];
724
873
  function validateModule(options = {}) {
725
- const projectDir = (0, import_node_path8.resolve)(options.dir ?? process.cwd());
874
+ const projectDir = (0, import_node_path9.resolve)(options.dir ?? process.cwd());
726
875
  const errors = [];
727
876
  const warnings = [];
728
877
  let config;
@@ -740,15 +889,15 @@ function validateModule(options = {}) {
740
889
  config = void 0;
741
890
  }
742
891
  }
743
- const moduleDir = options.moduleDir ?? (0, import_node_path8.join)(projectDir, config?.outDir ?? CONFIG_DEFAULTS.outDir);
744
- const manifestFile = (0, import_node_path8.join)(moduleDir, "manifest.json");
745
- if (!(0, import_node_fs8.existsSync)(manifestFile)) {
892
+ const moduleDir = options.moduleDir ?? (0, import_node_path9.join)(projectDir, config?.outDir ?? CONFIG_DEFAULTS.outDir);
893
+ const manifestFile = (0, import_node_path9.join)(moduleDir, "manifest.json");
894
+ if (!(0, import_node_fs9.existsSync)(manifestFile)) {
746
895
  errors.push(`\u4EA7\u7269\u4E0D\u5B58\u5728: ${manifestFile}\uFF08\u5148\u6267\u884C pactor module build\uFF09`);
747
896
  return { ok: false, errors, warnings };
748
897
  }
749
898
  let manifest;
750
899
  try {
751
- manifest = JSON.parse((0, import_node_fs8.readFileSync)(manifestFile, "utf8"));
900
+ manifest = JSON.parse((0, import_node_fs9.readFileSync)(manifestFile, "utf8"));
752
901
  } catch (error) {
753
902
  errors.push(`manifest.json \u89E3\u6790\u5931\u8D25: ${error.message}`);
754
903
  return { ok: false, errors, warnings };
@@ -763,11 +912,11 @@ function validateModule(options = {}) {
763
912
  }
764
913
  const dslRoot = typeof manifest.dslRoot === "string" ? manifest.dslRoot : "dsl";
765
914
  const sitemapRel = typeof manifest.sitemap === "string" ? manifest.sitemap : "dsl/sitemap.yaml";
766
- const sitemapFile = (0, import_node_path8.join)(moduleDir, sitemapRel);
767
- if (!(0, import_node_fs8.existsSync)(sitemapFile)) {
915
+ const sitemapFile = (0, import_node_path9.join)(moduleDir, sitemapRel);
916
+ if (!(0, import_node_fs9.existsSync)(sitemapFile)) {
768
917
  errors.push(`sitemap \u4E0D\u5B58\u5728: ${sitemapRel}`);
769
918
  } else {
770
- const doc = (0, import_yaml3.parseDocument)((0, import_node_fs8.readFileSync)(sitemapFile, "utf8"));
919
+ const doc = (0, import_yaml3.parseDocument)((0, import_node_fs9.readFileSync)(sitemapFile, "utf8"));
771
920
  if (doc.errors.length > 0) {
772
921
  errors.push(`sitemap YAML \u89E3\u6790\u5931\u8D25: ${doc.errors.map((e) => e.message).join("; ")}`);
773
922
  } else {
@@ -779,7 +928,7 @@ function validateModule(options = {}) {
779
928
  errors.push("sitemap.pages \u5B58\u5728\u7F3A\u5C11 id \u7684\u9875\u9762\u9879");
780
929
  continue;
781
930
  }
782
- if (findPageDslFile((0, import_node_path8.join)(moduleDir, dslRoot), id) === null) {
931
+ if (findPageDslFile((0, import_node_path9.join)(moduleDir, dslRoot), id) === null) {
783
932
  errors.push(`\u9875\u9762 ${id} \u7F3A\u5C11 DSL \u6587\u4EF6\uFF08${dslRoot}/ \u4E0B\u672A\u627E\u5230 ${id}.yaml\uFF09`);
784
933
  }
785
934
  }
@@ -793,34 +942,60 @@ function validateModule(options = {}) {
793
942
  }
794
943
  }
795
944
  }
796
- const dslDir = (0, import_node_path8.join)(moduleDir, dslRoot);
945
+ const dslDir = (0, import_node_path9.join)(moduleDir, dslRoot);
797
946
  for (const file of listFiles(dslDir)) {
798
- if ((0, import_node_fs8.readFileSync)(file, "utf8").includes(INCLUDE_KEY)) {
799
- errors.push(`$include \u6B8B\u7559: ${(0, import_node_path8.relative)(moduleDir, file)}`);
947
+ if ((0, import_node_fs9.readFileSync)(file, "utf8").includes(INCLUDE_KEY)) {
948
+ errors.push(`$include \u6B8B\u7559: ${(0, import_node_path9.relative)(moduleDir, file)}`);
800
949
  }
801
950
  }
802
951
  if (typeof manifest.clientEntry === "string") {
803
- const clientFile = (0, import_node_path8.join)(moduleDir, manifest.clientEntry);
804
- if (!(0, import_node_fs8.existsSync)(clientFile)) {
952
+ const clientFile = (0, import_node_path9.join)(moduleDir, manifest.clientEntry);
953
+ if (!(0, import_node_fs9.existsSync)(clientFile)) {
805
954
  errors.push(`client bundle \u4E0D\u5B58\u5728: ${manifest.clientEntry}`);
806
955
  } else {
807
- const text = (0, import_node_fs8.readFileSync)(clientFile, "utf8");
956
+ const text = (0, import_node_fs9.readFileSync)(clientFile, "utf8");
808
957
  if (/\bvar React\b|react\.production\.min|__REACT_DEVTOOLS_GLOBAL_HOOK__/.test(text)) {
809
958
  errors.push("client bundle \u7591\u4F3C\u5185\u5D4C react\uFF08react \u5FC5\u987B\u4FDD\u6301 external\uFF0C\u907F\u514D\u53CC\u5B9E\u4F8B\uFF09");
810
959
  }
811
960
  if (/node_modules\/@pactor-app\//.test(text) || /node_modules\/pactor-app\//.test(text)) {
812
961
  errors.push("client bundle \u7591\u4F3C\u5185\u5D4C pactor \u8FD0\u884C\u65F6\u4EE3\u7801\uFF08@pactor-app/* \u5FC5\u987B\u4FDD\u6301 external\uFF09");
813
962
  }
814
- const sizeKb = Math.round((0, import_node_fs8.statSync)(clientFile).size / 1024);
963
+ const sizeKb = Math.round((0, import_node_fs9.statSync)(clientFile).size / 1024);
815
964
  if (sizeKb > 512) {
816
965
  warnings.push(`client bundle \u4F53\u79EF\u8F83\u5927\uFF08${sizeKb}KB\uFF09\uFF0C\u8BF7\u786E\u8BA4 react / pactor \u5DF2 external`);
817
966
  }
818
967
  }
819
968
  }
820
- const pkgFile = (0, import_node_path8.join)(projectDir, "package.json");
821
- if ((0, import_node_fs8.existsSync)(pkgFile)) {
969
+ const hasServerEntry = typeof manifest.serverEntry === "string";
970
+ const hasApiPrefixes = Array.isArray(manifest.apiPrefixes);
971
+ if (hasServerEntry !== hasApiPrefixes) {
972
+ errors.push("manifest.serverEntry \u4E0E apiPrefixes \u5FC5\u987B\u6210\u5BF9\u51FA\u73B0");
973
+ }
974
+ if (hasServerEntry) {
975
+ const serverRel = manifest.serverEntry;
976
+ const serverFile = (0, import_node_path9.resolve)(moduleDir, serverRel);
977
+ if (!isInsideDir(moduleDir, serverFile)) {
978
+ errors.push(`server bundle \u8DEF\u5F84\u8D8A\u754C: ${serverRel}`);
979
+ } else if (!(0, import_node_fs9.existsSync)(serverFile)) {
980
+ errors.push(`server bundle \u4E0D\u5B58\u5728: ${serverRel}`);
981
+ } else {
982
+ const text = (0, import_node_fs9.readFileSync)(serverFile, "utf8");
983
+ if (/node_modules\/(?:next|react|react-dom|@pactor-app|pactor-app)\//.test(text)) {
984
+ warnings.push(
985
+ "server bundle \u7591\u4F3C\u5185\u5D4C next / react / pactor\uFF08\u5E94\u4FDD\u6301 external\uFF0C\u7531\u5BBF\u4E3B\u63D0\u4F9B\uFF09"
986
+ );
987
+ }
988
+ }
989
+ if (!Array.isArray(manifest.apiPrefixes) || manifest.apiPrefixes.length === 0) {
990
+ errors.push("manifest.apiPrefixes \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4");
991
+ } else if (manifest.apiPrefixes.some((prefix) => typeof prefix !== "string")) {
992
+ errors.push("manifest.apiPrefixes \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4");
993
+ }
994
+ }
995
+ const pkgFile = (0, import_node_path9.join)(projectDir, "package.json");
996
+ if ((0, import_node_fs9.existsSync)(pkgFile)) {
822
997
  try {
823
- const pkg = JSON.parse((0, import_node_fs8.readFileSync)(pkgFile, "utf8"));
998
+ const pkg = JSON.parse((0, import_node_fs9.readFileSync)(pkgFile, "utf8"));
824
999
  const exportsMap = pkg.exports ?? {};
825
1000
  if (exportsMap["./manifest"] === void 0) {
826
1001
  errors.push('package.json exports \u7F3A\u5C11 "./manifest"\uFF08Shell \u88C5\u914D\u5668\u7ECF require.resolve("<pkg>/manifest") \u5B9A\u4F4D\uFF09');
@@ -828,6 +1003,9 @@ function validateModule(options = {}) {
828
1003
  if (typeof manifest.clientEntry === "string" && exportsMap["./client"] === void 0) {
829
1004
  errors.push('package.json exports \u7F3A\u5C11 "./client"\uFF08client-registry \u9759\u6001 import "<pkg>/client"\uFF09');
830
1005
  }
1006
+ if (typeof manifest.serverEntry === "string" && exportsMap["./server"] === void 0) {
1007
+ errors.push('package.json exports \u7F3A\u5C11 "./server"\uFF08Shell \u88C5\u914D\u5668\u7ECF require.resolve("<pkg>/server") \u5B9A\u4F4D\uFF09');
1008
+ }
831
1009
  if (typeof pkg.version === "string" && typeof manifest.version === "string" && pkg.version !== manifest.version) {
832
1010
  warnings.push(
833
1011
  `manifest.version (${manifest.version}) \u4E0E package.json version (${pkg.version}) \u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0 build`
@@ -841,13 +1019,17 @@ function validateModule(options = {}) {
841
1019
  }
842
1020
  return { ok: errors.length === 0, errors, warnings };
843
1021
  }
1022
+ function isInsideDir(dir, file) {
1023
+ const root = (0, import_node_path9.resolve)(dir);
1024
+ return file.startsWith(`${root}${import_node_path9.sep}`);
1025
+ }
844
1026
  function findPageDslFile(dslRootDir, pageId) {
845
- if (!(0, import_node_fs8.existsSync)(dslRootDir)) return null;
1027
+ if (!(0, import_node_fs9.existsSync)(dslRootDir)) return null;
846
1028
  const queue = [dslRootDir];
847
1029
  while (queue.length > 0) {
848
1030
  const dir = queue.pop();
849
- for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
850
- const full = (0, import_node_path8.join)(dir, entry.name);
1031
+ for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
1032
+ const full = (0, import_node_path9.join)(dir, entry.name);
851
1033
  if (entry.isDirectory()) {
852
1034
  queue.push(full);
853
1035
  continue;
@@ -858,11 +1040,11 @@ function findPageDslFile(dslRootDir, pageId) {
858
1040
  return null;
859
1041
  }
860
1042
  function listFiles(dir) {
861
- if (!(0, import_node_fs8.existsSync)(dir)) return [];
1043
+ if (!(0, import_node_fs9.existsSync)(dir)) return [];
862
1044
  const files = [];
863
1045
  const walk = (target) => {
864
- for (const entry of (0, import_node_fs8.readdirSync)(target, { withFileTypes: true })) {
865
- const full = (0, import_node_path8.join)(target, entry.name);
1046
+ for (const entry of (0, import_node_fs9.readdirSync)(target, { withFileTypes: true })) {
1047
+ const full = (0, import_node_path9.join)(target, entry.name);
866
1048
  if (entry.isDirectory()) {
867
1049
  walk(full);
868
1050
  } else if (entry.isFile()) {
@@ -882,7 +1064,7 @@ var ModuleBuildError = class extends Error {
882
1064
  }
883
1065
  };
884
1066
  function buildModule(options = {}) {
885
- const projectDir = (0, import_node_path9.resolve)(options.dir ?? process.cwd());
1067
+ const projectDir = (0, import_node_path10.resolve)(options.dir ?? process.cwd());
886
1068
  const config = loadModuleConfig(projectDir, options.config);
887
1069
  const profile = getProfile(config.target);
888
1070
  if (profile.forbidRootBasePath && config.basePath === "/") {
@@ -891,8 +1073,17 @@ function buildModule(options = {}) {
891
1073
  [`basePath: "/" \u4E0E profile ${config.target} \u7684 forbidRootBasePath \u51B2\u7A81\uFF0C\u8BF7\u6539\u7528\u5982 /${config.id} \u7684\u524D\u7F00`]
892
1074
  );
893
1075
  }
894
- const yamlRoot = (0, import_node_path9.join)(projectDir, config.yamlRoot);
895
- if (!(0, import_node_fs9.existsSync)(yamlRoot)) {
1076
+ if (config.serverEntry !== void 0 && !profile.moduleServerApi) {
1077
+ throw new ModuleBuildError(
1078
+ `target ${config.target} \u4E0D\u652F\u6301\u6A21\u5757 server entry\uFF08\u9700\u8981 innospots-web-shell@3\uFF09`,
1079
+ [
1080
+ `\u914D\u7F6E\u4E86 serverEntry / apiPrefixes\uFF0C\u4F46 profile ${config.target} \u7684 moduleServerApi=false`,
1081
+ '\u8BF7\u628A pactor.module.json \u7684 target \u5347\u5230 "innospots-web-shell@3" \u540E\u91CD\u65B0\u6784\u5EFA'
1082
+ ]
1083
+ );
1084
+ }
1085
+ const yamlRoot = (0, import_node_path10.join)(projectDir, config.yamlRoot);
1086
+ if (!(0, import_node_fs10.existsSync)(yamlRoot)) {
896
1087
  throw new ModuleBuildError(`yamlRoot \u4E0D\u5B58\u5728: ${config.yamlRoot}`, [
897
1088
  `yamlRoot \u4E0D\u5B58\u5728: ${yamlRoot}`
898
1089
  ]);
@@ -932,7 +1123,7 @@ function buildModule(options = {}) {
932
1123
  }
933
1124
  const transformed = transformSitemap(site, {
934
1125
  profile,
935
- demoPublic: config.demo.public,
1126
+ accessDefault: config.access.default,
936
1127
  loadLayout: (rel) => loadYamlExpanded(yamlRoot, rel)
937
1128
  });
938
1129
  const version = readProjectVersion(projectDir);
@@ -941,11 +1132,13 @@ function buildModule(options = {}) {
941
1132
  basePath: config.basePath,
942
1133
  pagePaths: sitePages.map((page) => page.path).filter((path) => typeof path === "string"),
943
1134
  loginPath: typeof siteAuth.loginPath === "string" ? siteAuth.loginPath : "/login",
944
- publicDir: (0, import_node_path9.join)(projectDir, config.publicDir),
1135
+ publicDir: (0, import_node_path10.join)(projectDir, config.publicDir),
945
1136
  rewriteNavigation: profile.rewriteNavigation.basePath,
946
1137
  rewriteAssets: true,
947
1138
  assetPrefix: profile.rewriteAssetUrls(config.id, version).replace(/\/+$/, ""),
948
- absoluteApiToRelative: config.rewrite.absoluteApiToRelative
1139
+ absoluteApiToRelative: config.rewrite.absoluteApiToRelative,
1140
+ moduleId: config.id,
1141
+ apiPrefixes: config.apiPrefixes
949
1142
  };
950
1143
  const sitemapRewrite = rewriteDslUrls(transformed.site, rewriteCtx);
951
1144
  warnings.push(...sitemapRewrite.warnings);
@@ -955,17 +1148,22 @@ function buildModule(options = {}) {
955
1148
  warnings.push(...result.warnings.map((warning) => `${id}: ${warning}`));
956
1149
  rewrittenPages.set(id, result.value);
957
1150
  }
958
- const outDir = (0, import_node_path9.join)(projectDir, config.outDir);
959
- const temp = (0, import_node_fs9.mkdtempSync)((0, import_node_path9.join)(projectDir, ".module-pack-"));
1151
+ const outDir = (0, import_node_path10.join)(projectDir, config.outDir);
1152
+ const temp = (0, import_node_fs10.mkdtempSync)((0, import_node_path10.join)(projectDir, ".module-pack-"));
960
1153
  try {
961
1154
  const bundle = bundleClient({
962
1155
  projectDir,
963
1156
  clientEntry: config.clientEntry,
964
- outDir: (0, import_node_path9.join)(temp, "client")
1157
+ outDir: (0, import_node_path10.join)(temp, "client")
965
1158
  });
966
1159
  if (bundle.message !== void 0) {
967
1160
  warnings.push(bundle.message);
968
1161
  }
1162
+ const server = config.serverEntry ? bundleServer({
1163
+ projectDir,
1164
+ serverEntry: config.serverEntry,
1165
+ outDir: (0, import_node_path10.join)(temp, "server")
1166
+ }) : void 0;
969
1167
  const emitted = emitDsl({
970
1168
  config,
971
1169
  projectDir,
@@ -977,18 +1175,20 @@ function buildModule(options = {}) {
977
1175
  const tailwind = compileTailwind({
978
1176
  projectDir,
979
1177
  tailwind: config.tailwind,
980
- scanDirs: [(0, import_node_path9.join)(temp, "dsl"), (0, import_node_path9.dirname)((0, import_node_path9.join)(projectDir, config.clientEntry))],
981
- cssFile: (0, import_node_path9.join)(temp, "client", "index.css")
1178
+ scanDirs: [(0, import_node_path10.join)(temp, "dsl"), (0, import_node_path10.dirname)((0, import_node_path10.join)(projectDir, config.clientEntry))],
1179
+ cssFile: (0, import_node_path10.join)(temp, "client", "index.css")
982
1180
  });
983
1181
  warnings.push(...tailwind.warnings);
984
1182
  }
985
- const hasCss = (0, import_node_fs9.existsSync)((0, import_node_path9.join)(temp, "client", "index.css"));
1183
+ const hasCss = (0, import_node_fs10.existsSync)((0, import_node_path10.join)(temp, "client", "index.css"));
986
1184
  writeManifest({
987
1185
  config,
988
1186
  projectDir,
989
1187
  outDir: temp,
990
1188
  clientEntry: bundle.bundled ? "client/index.js" : void 0,
991
1189
  styles: bundle.bundled && hasCss ? ["client/index.css"] : void 0,
1190
+ serverEntry: server ? "server/index.mjs" : void 0,
1191
+ apiPrefixes: server ? config.apiPrefixes : void 0,
992
1192
  warnings
993
1193
  });
994
1194
  const validation = validateModule({ dir: projectDir, config: options.config, moduleDir: temp });
@@ -999,9 +1199,9 @@ function buildModule(options = {}) {
999
1199
  validation.errors
1000
1200
  );
1001
1201
  }
1002
- (0, import_node_fs9.rmSync)(outDir, { recursive: true, force: true });
1003
- (0, import_node_fs9.mkdirSync)((0, import_node_path9.dirname)(outDir), { recursive: true });
1004
- (0, import_node_fs9.renameSync)(temp, outDir);
1202
+ (0, import_node_fs10.rmSync)(outDir, { recursive: true, force: true });
1203
+ (0, import_node_fs10.mkdirSync)((0, import_node_path10.dirname)(outDir), { recursive: true });
1204
+ (0, import_node_fs10.renameSync)(temp, outDir);
1005
1205
  return {
1006
1206
  outDir,
1007
1207
  stats: {
@@ -1011,77 +1211,142 @@ function buildModule(options = {}) {
1011
1211
  assets: emitted.assetCount
1012
1212
  },
1013
1213
  clientBundled: bundle.bundled,
1214
+ serverBundled: server !== void 0,
1014
1215
  warnings
1015
1216
  };
1016
1217
  } catch (error) {
1017
- (0, import_node_fs9.rmSync)(temp, { recursive: true, force: true });
1218
+ (0, import_node_fs10.rmSync)(temp, { recursive: true, force: true });
1018
1219
  throw error;
1019
1220
  }
1020
1221
  }
1021
1222
 
1022
1223
  // src/init.ts
1023
- var import_node_fs10 = require("fs");
1024
- var import_node_path10 = require("path");
1224
+ var import_node_fs11 = require("fs");
1225
+ var import_node_path11 = require("path");
1226
+ var CLIENT_STYLES_ENTRY = "module/module.css";
1227
+ var SERVER_ENTRY = "module/server.ts";
1025
1228
  function initModule(options = {}) {
1026
- const projectDir = (0, import_node_path10.resolve)(options.dir ?? process.cwd());
1027
- const result = { created: [], skipped: [], warnings: [] };
1028
- const pkgFile = (0, import_node_path10.join)(projectDir, "package.json");
1029
- if (!(0, import_node_fs10.existsSync)(pkgFile)) {
1229
+ const projectDir = (0, import_node_path11.resolve)(options.dir ?? process.cwd());
1230
+ const overwrite = options.overwrite ?? false;
1231
+ const server = options.server ?? false;
1232
+ const result = { created: [], overwritten: [], skipped: [], warnings: [] };
1233
+ const pkgFile = (0, import_node_path11.join)(projectDir, "package.json");
1234
+ if (!(0, import_node_fs11.existsSync)(pkgFile)) {
1030
1235
  throw new Error(`\u672A\u627E\u5230 package.json: ${projectDir}\uFF08\u8BF7\u5728\u76EE\u6807\u5DE5\u7A0B\u6839\u6267\u884C\uFF09`);
1031
1236
  }
1032
- const pkg = JSON.parse((0, import_node_fs10.readFileSync)(pkgFile, "utf8"));
1237
+ const pkg = JSON.parse((0, import_node_fs11.readFileSync)(pkgFile, "utf8"));
1033
1238
  const id = deriveModuleId(pkg.name);
1034
1239
  const actions = discoverActions(projectDir);
1035
1240
  const hasComponents = discoverComponents(projectDir);
1036
- const configFile = (0, import_node_path10.join)(projectDir, CONFIG_FILE);
1037
- if ((0, import_node_fs10.existsSync)(configFile)) {
1241
+ const configFile = (0, import_node_path11.join)(projectDir, CONFIG_FILE);
1242
+ const renderConfig = () => ({
1243
+ id,
1244
+ name: typeof pkg.name === "string" ? pkg.name : id,
1245
+ basePath: `/${id}`,
1246
+ yamlRoot: CONFIG_DEFAULTS.yamlRoot,
1247
+ clientEntry: CONFIG_DEFAULTS.clientEntry,
1248
+ // 只有显式 --server 才写入,避免纯 DSL 模块被迫启用 server entry
1249
+ ...server ? { serverEntry: SERVER_ENTRY, apiPrefixes: [deriveApiPrefix(id)] } : {},
1250
+ actions: actions.map((action) => action.specifier.replace(/^\.\.\//, "")),
1251
+ publicDir: CONFIG_DEFAULTS.publicDir,
1252
+ target: DEFAULT_TARGET
1253
+ });
1254
+ const configExisted = (0, import_node_fs11.existsSync)(configFile);
1255
+ if (configExisted && !overwrite) {
1038
1256
  result.skipped.push(`${CONFIG_FILE}\uFF08\u5DF2\u5B58\u5728\uFF09`);
1039
1257
  } else {
1040
- const config = {
1041
- id,
1042
- name: typeof pkg.name === "string" ? pkg.name : id,
1043
- basePath: `/${id}`,
1044
- yamlRoot: CONFIG_DEFAULTS.yamlRoot,
1045
- clientEntry: CONFIG_DEFAULTS.clientEntry,
1046
- actions: actions.map((action) => action.specifier.replace(/^\.\.\//, "")),
1047
- publicDir: CONFIG_DEFAULTS.publicDir,
1048
- target: DEFAULT_TARGET,
1049
- demo: { public: false }
1050
- };
1051
- (0, import_node_fs10.writeFileSync)(configFile, `${JSON.stringify(config, null, 2)}
1258
+ (0, import_node_fs11.writeFileSync)(configFile, `${JSON.stringify(renderConfig(), null, 2)}
1052
1259
  `, "utf8");
1053
- result.created.push(CONFIG_FILE);
1260
+ if (configExisted) {
1261
+ result.overwritten.push(CONFIG_FILE);
1262
+ } else {
1263
+ result.created.push(CONFIG_FILE);
1264
+ }
1054
1265
  }
1055
- const clientFile = (0, import_node_path10.join)(projectDir, CONFIG_DEFAULTS.clientEntry);
1056
- if ((0, import_node_fs10.existsSync)(clientFile)) {
1266
+ const clientFile = (0, import_node_path11.join)(projectDir, CONFIG_DEFAULTS.clientEntry);
1267
+ if ((0, import_node_fs11.existsSync)(clientFile) && !overwrite) {
1057
1268
  result.skipped.push(`${CONFIG_DEFAULTS.clientEntry}\uFF08\u5DF2\u5B58\u5728\uFF09`);
1058
1269
  } else {
1059
- (0, import_node_fs10.mkdirSync)((0, import_node_path10.join)(projectDir, "module"), { recursive: true });
1060
- (0, import_node_fs10.writeFileSync)(clientFile, renderClientEntry(hasComponents, actions), "utf8");
1061
- result.created.push(CONFIG_DEFAULTS.clientEntry);
1270
+ const clientExisted = (0, import_node_fs11.existsSync)(clientFile);
1271
+ (0, import_node_fs11.mkdirSync)((0, import_node_path11.dirname)(clientFile), { recursive: true });
1272
+ (0, import_node_fs11.writeFileSync)(clientFile, renderClientEntry(hasComponents, actions), "utf8");
1273
+ if (clientExisted) {
1274
+ result.overwritten.push(CONFIG_DEFAULTS.clientEntry);
1275
+ } else {
1276
+ result.created.push(CONFIG_DEFAULTS.clientEntry);
1277
+ }
1278
+ }
1279
+ const stylesFile = (0, import_node_path11.join)(projectDir, CLIENT_STYLES_ENTRY);
1280
+ if ((0, import_node_fs11.existsSync)(stylesFile) && !overwrite) {
1281
+ result.skipped.push(`${CLIENT_STYLES_ENTRY}\uFF08\u5DF2\u5B58\u5728\uFF09`);
1282
+ } else {
1283
+ const stylesExisted = (0, import_node_fs11.existsSync)(stylesFile);
1284
+ (0, import_node_fs11.mkdirSync)((0, import_node_path11.dirname)(stylesFile), { recursive: true });
1285
+ (0, import_node_fs11.writeFileSync)(stylesFile, renderModuleStyles(), "utf8");
1286
+ if (stylesExisted) {
1287
+ result.overwritten.push(CLIENT_STYLES_ENTRY);
1288
+ } else {
1289
+ result.created.push(CLIENT_STYLES_ENTRY);
1290
+ }
1291
+ }
1292
+ if (server) {
1293
+ const serverFile = (0, import_node_path11.join)(projectDir, SERVER_ENTRY);
1294
+ if ((0, import_node_fs11.existsSync)(serverFile) && !overwrite) {
1295
+ result.skipped.push(`${SERVER_ENTRY}\uFF08\u5DF2\u5B58\u5728\uFF09`);
1296
+ } else {
1297
+ const serverExisted = (0, import_node_fs11.existsSync)(serverFile);
1298
+ (0, import_node_fs11.mkdirSync)((0, import_node_path11.dirname)(serverFile), { recursive: true });
1299
+ (0, import_node_fs11.writeFileSync)(serverFile, renderServerEntry(id), "utf8");
1300
+ if (serverExisted) {
1301
+ result.overwritten.push(SERVER_ENTRY);
1302
+ } else {
1303
+ result.created.push(SERVER_ENTRY);
1304
+ }
1305
+ }
1062
1306
  }
1063
- injectPackageJson(pkg, result);
1064
- (0, import_node_fs10.writeFileSync)(pkgFile, `${JSON.stringify(pkg, null, 2)}
1307
+ const hasServerEntry = (0, import_node_fs11.existsSync)((0, import_node_path11.join)(projectDir, SERVER_ENTRY));
1308
+ injectPackageJson(pkg, result, hasServerEntry);
1309
+ if (hasServerEntry && !configDeclaresServerEntry(configFile)) {
1310
+ result.warnings.push(
1311
+ '\u68C0\u6D4B\u5230 module/server.ts\uFF1A\u5DF2\u6CE8\u5165 "./server" export\uFF1B\u8BF7\u5728 pactor.module.json \u4E2D\u540C\u65F6\u914D\u7F6E serverEntry \u4E0E apiPrefixes \u540E\u518D\u6784\u5EFA\uFF08\u7F3A\u4E00\u6784\u5EFA\u4F1A\u5931\u8D25\uFF09'
1312
+ );
1313
+ }
1314
+ (0, import_node_fs11.writeFileSync)(pkgFile, `${JSON.stringify(pkg, null, 2)}
1065
1315
  `, "utf8");
1066
1316
  result.created.push("package.json\uFF08\u6CE8\u5165 files / exports / scripts / peerDependencies\uFF09");
1067
1317
  return result;
1068
1318
  }
1319
+ function configDeclaresServerEntry(configFile) {
1320
+ if (!(0, import_node_fs11.existsSync)(configFile)) return false;
1321
+ try {
1322
+ const raw = JSON.parse((0, import_node_fs11.readFileSync)(configFile, "utf8"));
1323
+ return raw.serverEntry === SERVER_ENTRY;
1324
+ } catch {
1325
+ return false;
1326
+ }
1327
+ }
1328
+ var MODULE_ID_PREFIX = "pactor-app-";
1069
1329
  function deriveModuleId(name) {
1070
1330
  const base2 = typeof name === "string" && name.length > 0 ? name : "module";
1071
1331
  const withoutScope = base2.startsWith("@") ? base2.slice(base2.indexOf("/") + 1) : base2;
1072
1332
  const kebab = withoutScope.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1073
- return kebab.length > 0 ? kebab : "module";
1333
+ const id = kebab.length > 0 ? kebab : "module";
1334
+ return id.startsWith(MODULE_ID_PREFIX) ? id : `${MODULE_ID_PREFIX}${id}`;
1335
+ }
1336
+ function deriveApiPrefix(moduleId) {
1337
+ const slug = moduleId.startsWith(MODULE_ID_PREFIX) ? moduleId.slice(MODULE_ID_PREFIX.length) : moduleId;
1338
+ return `/api/${slug.length > 0 ? slug : "module"}`;
1074
1339
  }
1075
1340
  function discoverActions(projectDir) {
1076
- const dir = (0, import_node_path10.join)(projectDir, "src/pactor");
1077
- if (!(0, import_node_fs10.existsSync)(dir)) return [];
1341
+ const dir = (0, import_node_path11.join)(projectDir, "src/pactor");
1342
+ if (!(0, import_node_fs11.existsSync)(dir)) return [];
1078
1343
  const sources = [];
1079
- for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true }).sort(
1344
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true }).sort(
1080
1345
  (a, b) => a.name.localeCompare(b.name)
1081
1346
  )) {
1082
1347
  if (!entry.isFile() || !entry.name.endsWith("-actions.ts")) continue;
1083
- const file = (0, import_node_path10.join)(dir, entry.name);
1084
- const content = (0, import_node_fs10.readFileSync)(file, "utf8");
1348
+ const file = (0, import_node_path11.join)(dir, entry.name);
1349
+ const content = (0, import_node_fs11.readFileSync)(file, "utf8");
1085
1350
  const exports2 = [...content.matchAll(/export\s+const\s+([A-Za-z_$][\w$]*)/g)].map(
1086
1351
  (match) => match[1]
1087
1352
  );
@@ -1094,9 +1359,9 @@ function discoverActions(projectDir) {
1094
1359
  return sources;
1095
1360
  }
1096
1361
  function discoverComponents(projectDir) {
1097
- const file = (0, import_node_path10.join)(projectDir, "src/pactor/components/index.ts");
1098
- if (!(0, import_node_fs10.existsSync)(file)) return false;
1099
- return /export\s+(const|\{[^}]*)\s*pactorComponents/.test((0, import_node_fs10.readFileSync)(file, "utf8"));
1362
+ const file = (0, import_node_path11.join)(projectDir, "src/pactor/components/index.ts");
1363
+ if (!(0, import_node_fs11.existsSync)(file)) return false;
1364
+ return /export\s+(const|\{[^}]*)\s*pactorComponents/.test((0, import_node_fs11.readFileSync)(file, "utf8"));
1100
1365
  }
1101
1366
  function renderClientEntry(hasComponents, actions) {
1102
1367
  const imports = [];
@@ -1112,18 +1377,48 @@ function renderClientEntry(hasComponents, actions) {
1112
1377
  }
1113
1378
  const components = hasComponents ? "pactorComponents" : "{}";
1114
1379
  const actionsExpr = spreads.length > 0 ? `{ ${spreads.join(", ")} }` : "{}";
1380
+ const importsBlock = imports.length > 0 ? `${imports.join("\n")}
1381
+ ` : "";
1115
1382
  return `// \u7531 \`pactor module init\` \u751F\u6210\uFF1A\u6A21\u5757 client \u5165\u53E3\u3002
1116
1383
  // Shell \u88C5\u914D\u5668\u751F\u6210 client-registry.ts \u65F6\u9759\u6001 import "<pkg>/client"\uFF0C
1117
1384
  // \u8981\u6C42\u6B64\u5904\u5177\u540D\u5BFC\u51FA extensions\uFF08components / actions \u6CE8\u518C\u8868\uFF09\u3002
1118
- ${imports.join("\n")}
1119
-
1385
+ // module.css \u7531 esbuild \u62BD\u6210 client/index.css\uFF0CShell \u6309 manifest.styles \u52A0\u8F7D\u3002
1386
+ import './module.css';
1387
+ ${importsBlock}
1120
1388
  export const extensions = {
1121
1389
  components: ${components},
1122
1390
  actions: ${actionsExpr},
1123
1391
  };
1124
1392
  `;
1125
1393
  }
1126
- function injectPackageJson(pkg, result) {
1394
+ function renderModuleStyles() {
1395
+ return `/**
1396
+ * \u6A21\u5757\u81EA\u5E26\u6837\u5F0F\uFF08\u7531 \`pactor module init\` \u751F\u6210\uFF09\u3002
1397
+ *
1398
+ * \u672C\u6587\u4EF6\u7531 module/client.ts import\uFF1Aesbuild \u6253\u5305\u65F6\u4F1A\u62BD\u53D6\u4E3A
1399
+ * dist-module/client/index.css \u5E76\u5199\u5165 manifest.styles\uFF0CShell \u636E\u6B64\u81EA\u52A8\u52A0\u8F7D\u3002
1400
+ * Tailwind \u57FA\u7840\u6837\u5F0F\u3001pactor-app \u805A\u5408\u6837\u5F0F\u4E0E\u4E3B\u9898\u53D8\u91CF\u7531 Shell \u7EDF\u4E00\u63D0\u4F9B\uFF0C
1401
+ * \u6A21\u5757\u5185\u4E0D\u8981\u91CD\u590D\u5F15\u5165\uFF0C\u907F\u514D\u4EA7\u751F\u7B2C\u4E8C\u4EFD reset / \u4EE4\u724C\u3002
1402
+ */
1403
+
1404
+ /* \u6A21\u5757\u7EA7\u6837\u5F0F\u5199\u5728\u8FD9\u91CC\uFF1A\u5EFA\u8BAE\u4F7F\u7528\u5E26\u6A21\u5757\u524D\u7F00\u7684\u7C7B\u540D\uFF0C\u907F\u514D\u4E0E Shell \u5168\u5C40\u6837\u5F0F\u51B2\u7A81\u3002 */
1405
+ `;
1406
+ }
1407
+ function renderServerEntry(moduleId) {
1408
+ const prefix = deriveApiPrefix(moduleId);
1409
+ return `// \u7531 \`pactor module init --server\` \u751F\u6210\uFF1A\u6A21\u5757\u670D\u52A1\u7AEF\u5165\u53E3\u3002
1410
+ // \u5BFC\u51FA\u300C\u903B\u8F91\u8DEF\u5F84 \u2192 \u65B9\u6CD5\u5904\u7406\u51FD\u6570\u300D\u6620\u5C04\uFF1A\u8DEF\u5F84\u952E\u4F7F\u7528\u539F\u59CB /api/... \u903B\u8F91\u8DEF\u5F84\uFF0C
1411
+ // Shell \u901A\u8FC7 /api/modules/<moduleId>/* \u7EDF\u4E00\u5206\u53D1\uFF08\u89C1 pactor.module.json \u7684 apiPrefixes\uFF09\u3002
1412
+ // handler \u53EA\u4F9D\u8D56 Web \u6807\u51C6 Request / Response\uFF0Ccontext.url \u4E3A\u903B\u8F91 URL\uFF08\u542B query\uFF09\u3002
1413
+
1414
+ export const handlers = {
1415
+ // '${prefix}/hello': {
1416
+ // GET: () => Response.json({ code: 0, data: { ok: true }, message: 'ok' }),
1417
+ // },
1418
+ };
1419
+ `;
1420
+ }
1421
+ function injectPackageJson(pkg, result, hasServerEntry) {
1127
1422
  const outDir = CONFIG_DEFAULTS.outDir;
1128
1423
  const files = Array.isArray(pkg.files) ? pkg.files : [];
1129
1424
  if (!files.includes(outDir)) {
@@ -1133,7 +1428,8 @@ function injectPackageJson(pkg, result) {
1133
1428
  const wantedExports = {
1134
1429
  "./manifest": `./${outDir}/manifest.json`,
1135
1430
  "./client": `./${outDir}/client/index.js`,
1136
- "./styles.css": `./${outDir}/client/index.css`
1431
+ "./styles.css": `./${outDir}/client/index.css`,
1432
+ ...hasServerEntry ? { "./server": `./${outDir}/server/index.mjs` } : {}
1137
1433
  };
1138
1434
  for (const [key, value] of Object.entries(wantedExports)) {
1139
1435
  if (exportsMap[key] === void 0) {
@@ -1146,7 +1442,8 @@ function injectPackageJson(pkg, result) {
1146
1442
  const scripts = isRecord4(pkg.scripts) ? { ...pkg.scripts } : {};
1147
1443
  const wantedScripts = {
1148
1444
  "build:module": "pactor module build",
1149
- "pack:module": "pactor module pack"
1445
+ "pack:module": "pactor module pack",
1446
+ "publish:module": "pactor module publish"
1150
1447
  };
1151
1448
  for (const [key, value] of Object.entries(wantedScripts)) {
1152
1449
  if (scripts[key] === void 0) {
@@ -1174,21 +1471,72 @@ function injectPackageJson(pkg, result) {
1174
1471
  function isRecord4(value) {
1175
1472
  return value !== null && typeof value === "object" && !Array.isArray(value);
1176
1473
  }
1474
+
1475
+ // src/version.ts
1476
+ var import_node_fs12 = require("fs");
1477
+ var import_node_path12 = require("path");
1478
+ var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?$/;
1479
+ function bumpVersion(current, release) {
1480
+ if (release === "major" || release === "minor" || release === "patch") {
1481
+ const match = SEMVER_RE.exec(current);
1482
+ if (!match) {
1483
+ throw new ConfigError(`package.json \u7248\u672C\u53F7\u975E\u6CD5: ${current}\uFF08\u671F\u671B x.y.z\uFF09`);
1484
+ }
1485
+ const [, major, minor, patch] = match;
1486
+ if (release === "major") return `${Number(major) + 1}.0.0`;
1487
+ if (release === "minor") return `${major}.${Number(minor) + 1}.0`;
1488
+ return `${major}.${minor}.${Number(patch) + 1}`;
1489
+ }
1490
+ if (!SEMVER_RE.test(release)) {
1491
+ throw new ConfigError(
1492
+ `--bump \u53D6\u503C\u975E\u6CD5: ${release}\uFF08\u652F\u6301 patch | minor | major | \u663E\u5F0F\u7248\u672C\u53F7 x.y.z\uFF09`
1493
+ );
1494
+ }
1495
+ return release;
1496
+ }
1497
+ function bumpPackageVersion(options) {
1498
+ const dir = (0, import_node_path12.resolve)(options.dir ?? process.cwd());
1499
+ const pkgFile = (0, import_node_path12.resolve)(dir, "package.json");
1500
+ if (!(0, import_node_fs12.existsSync)(pkgFile)) {
1501
+ throw new ConfigError(`\u672A\u627E\u5230 package.json: ${dir}\uFF08\u8BF7\u5728\u76EE\u6807\u5DE5\u7A0B\u6839\u6267\u884C\uFF09`);
1502
+ }
1503
+ const pkg = JSON.parse((0, import_node_fs12.readFileSync)(pkgFile, "utf8"));
1504
+ const name = typeof pkg.name === "string" ? pkg.name : "(\u672A\u547D\u540D)";
1505
+ if (typeof pkg.version !== "string" || pkg.version === "") {
1506
+ throw new ConfigError(`package.json \u7F3A\u5C11 version \u5B57\u6BB5: ${pkgFile}`);
1507
+ }
1508
+ const from = pkg.version;
1509
+ const to = bumpVersion(from, options.release);
1510
+ pkg.version = to;
1511
+ (0, import_node_fs12.writeFileSync)(pkgFile, `${JSON.stringify(pkg, null, 2)}
1512
+ `, "utf8");
1513
+ return { name, from, to };
1514
+ }
1177
1515
  // Annotate the CommonJS export names for ESM import in node:
1178
1516
  0 && (module.exports = {
1179
1517
  CLIENT_EXTERNALS,
1518
+ CLIENT_STYLES_ENTRY,
1180
1519
  CONFIG_DEFAULTS,
1181
1520
  CONFIG_FILE,
1182
1521
  ConfigError,
1183
1522
  DEFAULT_TARGET,
1184
1523
  INCLUDE_KEY,
1185
1524
  IncludeError,
1525
+ MODULE_ID_PREFIX,
1186
1526
  ModuleBuildError,
1187
1527
  ProfileError,
1528
+ SERVER_BUNDLE_FILE,
1529
+ SERVER_ENTRY,
1530
+ SERVER_EXTERNALS,
1531
+ ServerBundleError,
1188
1532
  buildModule,
1533
+ bumpPackageVersion,
1534
+ bumpVersion,
1189
1535
  bundleClient,
1536
+ bundleServer,
1190
1537
  collectModuleSource,
1191
1538
  compileTailwind,
1539
+ deriveApiPrefix,
1192
1540
  deriveModuleId,
1193
1541
  discoverActions,
1194
1542
  discoverComponents,
@@ -1199,6 +1547,7 @@ function isRecord4(value) {
1199
1547
  initModule,
1200
1548
  innospotsWebShellV1,
1201
1549
  innospotsWebShellV2,
1550
+ innospotsWebShellV3,
1202
1551
  listProfiles,
1203
1552
  loadModuleConfig,
1204
1553
  loadYamlExpanded,
@@ -1207,6 +1556,8 @@ function isRecord4(value) {
1207
1556
  parseYamlFile,
1208
1557
  readProjectVersion,
1209
1558
  renderClientEntry,
1559
+ renderModuleStyles,
1560
+ renderServerEntry,
1210
1561
  resolvePactorVersionRange,
1211
1562
  rewriteDslUrls,
1212
1563
  rewriteNavigationTo,