@liujitcn/kratos-taro-app-core 0.0.18 → 0.0.19

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/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  模块必须同时提供运行时定义和 `./build` 导出。构建入口返回模块名称、包根目录与页面清单;runner 根据宿主的静态 `module-manifest.ts` 解析模块顺序,扫描页面并创建事务。
28
28
 
29
- runner 支持命名导入和默认导入的模块,后注册模块可以覆盖相同物理路由。页面私有 `components` 不会成为路由,模块 static 会先合并到宿主再由 Taro 编译。H5 下,runner 根据页面 `navigationStyle` 和 `navigationBar*` 配置生成默认顶部导航栏;微信小程序继续使用原生导航栏。构建失败、正常退出和收到终止信号时都会执行恢复。
29
+ runner 支持命名导入和默认导入的模块,后注册模块可以覆盖相同物理路由。页面私有 `components` 不会成为路由,模块 static 会先合并到宿主再由 Taro 编译。H5 下,runner 根据页面 `navigationStyle` 和 `navigationBar*` 配置生成默认顶部导航栏;微信小程序继续使用原生导航栏。构建失败、正常退出和收到终止信号时都会执行恢复;传入 `--prepare-only` 时只装配页面供类型检查使用,配合 `--cleanup-only` 在检查结束后恢复,不启动 Taro 编译。
30
30
 
31
31
  ## 验证
32
32
 
package/dist/runner.mjs CHANGED
@@ -15,6 +15,9 @@ import { dirname, relative, resolve } from "node:path";
15
15
  import { pathToFileURL } from "node:url";
16
16
  import { spawn } from "node:child_process";
17
17
  import ts from "typescript";
18
+ var sourceVersionCounter = 0;
19
+ var PAGE_ASSEMBLY_WAIT_TIMEOUT_MS = 3e4;
20
+ var PAGE_ASSEMBLY_POLL_INTERVAL_MS = 25;
18
21
  async function main() {
19
22
  const options = parseArguments(process.argv.slice(2));
20
23
  const hostRoot = process.cwd();
@@ -23,6 +26,7 @@ async function main() {
23
26
  const baseConfigFile = resolve(inputDir, "app.config.base.json");
24
27
  const transactionFile = resolve(hostRoot, ".kratos-taro-app-pages-state.json");
25
28
  recoverBuildTransaction(transactionFile, inputDir, appConfigFile);
29
+ if (options.cleanupOnly) return;
26
30
  const originalAppConfig = readFileSync(appConfigFile, "utf8");
27
31
  const manifest = JSON.parse(readFileSync(baseConfigFile, "utf8"));
28
32
  const modules = await loadBuildModules(hostRoot, resolve(inputDir, "module-manifest.ts"));
@@ -38,34 +42,24 @@ async function main() {
38
42
  });
39
43
  });
40
44
  });
41
- const generatedFiles = [...pageMap.values()].flatMap((page) => {
42
- const pageFile = resolve(inputDir, `${page.route}.tsx`);
43
- const configFile = resolve(inputDir, `${page.route}.config.ts`);
44
- return [pageFile, configFile].filter((file) => !existsSync(file));
45
- });
46
- const staticRoot = resolve(inputDir, "static");
47
- const staticFiles = collectModuleStaticFiles(
48
- modules.map((module) => resolve(module.root, "src/static")),
49
- staticRoot
50
- );
51
- const generatedStaticFiles = staticFiles.map(({ target }) => target);
52
- const transaction = {
53
- inputDir,
45
+ const pageAssembly = preparePageAssembly({
54
46
  appConfigFile,
47
+ baseManifest: manifest,
48
+ inputDir,
49
+ moduleStaticRoots: modules.map((module) => resolve(module.root, "src/static")),
55
50
  originalAppConfig,
56
- generatedFiles,
57
- generatedStaticFiles,
58
- ownerPid: process.pid
59
- };
60
- writeFileSync(transactionFile, `${JSON.stringify(transaction, null, 2)}
61
- `, { flag: "wx" });
51
+ pageMap: [...pageMap.values()],
52
+ transactionFile
53
+ });
62
54
  let cleaned = false;
63
55
  const cleanup = () => {
64
56
  if (cleaned) return;
65
57
  cleaned = true;
66
- cleanupTransaction(transaction);
67
- if (existsSync(transactionFile)) unlinkSync(transactionFile);
58
+ releasePageAssembly(transactionFile, pageAssembly.leaseFile);
68
59
  };
60
+ if (options.prepareOnly) {
61
+ return;
62
+ }
69
63
  const handleSignal = (signal) => {
70
64
  child?.kill(signal);
71
65
  };
@@ -73,34 +67,14 @@ async function main() {
73
67
  process.once("SIGINT", () => handleSignal("SIGINT"));
74
68
  process.once("SIGTERM", () => handleSignal("SIGTERM"));
75
69
  try {
76
- pageMap.forEach((page) => {
77
- appendPage(manifest, page.route);
78
- const pageFile = resolve(inputDir, `${page.route}.tsx`);
79
- const configFile = resolve(inputDir, `${page.route}.config.ts`);
80
- if (!existsSync(pageFile)) {
81
- mkdirSync(dirname(pageFile), { recursive: true });
82
- writeFileSync(pageFile, createPageWrapper(page));
83
- }
84
- if (!existsSync(configFile)) {
85
- writeFileSync(configFile, createPageConfig(page));
86
- }
87
- });
88
- staticFiles.forEach(({ source, target }) => {
89
- mkdirSync(dirname(target), { recursive: true });
90
- copyFileSync(source, target);
91
- });
92
- writeFileSync(
93
- appConfigFile,
94
- `export default defineAppConfig(${JSON.stringify(manifest, null, 2)})
95
- `
96
- );
97
70
  const args = ["exec", "taro", "build", "--type", options.type, "--mode", options.mode];
98
71
  if (options.watch) args.push("--watch");
99
72
  child = spawn(process.platform === "win32" ? "pnpm.cmd" : "pnpm", args, {
100
73
  cwd: hostRoot,
101
74
  env: {
102
75
  ...process.env,
103
- NODE_ENV: options.mode === "development" ? "development" : "production"
76
+ NODE_ENV: options.mode === "development" ? "development" : "production",
77
+ KRATOS_TARO_OUTPUT_ROOT: process.env.KRATOS_TARO_OUTPUT_ROOT || (options.type === "h5" ? "dist/h5" : "dist/mp-weixin")
104
78
  },
105
79
  stdio: "inherit"
106
80
  });
@@ -123,6 +97,8 @@ function parseArguments(args) {
123
97
  let type;
124
98
  let mode = "production";
125
99
  let watch = false;
100
+ let prepareOnly = false;
101
+ let cleanupOnly = false;
126
102
  for (let index = 0; index < args.length; index += 1) {
127
103
  const argument = args[index];
128
104
  if (argument === "--type") {
@@ -133,12 +109,16 @@ function parseArguments(args) {
133
109
  mode = args[++index] || mode;
134
110
  } else if (argument === "--watch") {
135
111
  watch = true;
112
+ } else if (argument === "--prepare-only") {
113
+ prepareOnly = true;
114
+ } else if (argument === "--cleanup-only") {
115
+ cleanupOnly = true;
136
116
  } else {
137
117
  throw new Error(`\u672A\u77E5\u53C2\u6570\uFF1A${argument}`);
138
118
  }
139
119
  }
140
120
  if (!type) throw new Error("\u7F3A\u5C11 --type h5|weapp");
141
- return { type, mode, watch };
121
+ return { type, mode, watch, prepareOnly, cleanupOnly };
142
122
  }
143
123
  async function loadBuildModules(hostRoot, manifestFile) {
144
124
  const source = readFileSync(manifestFile, "utf8");
@@ -185,26 +165,212 @@ async function loadBuildModules(hostRoot, manifestFile) {
185
165
  );
186
166
  }
187
167
  function recoverBuildTransaction(transactionFile, inputDir, appConfigFile) {
168
+ const lockFile = `${transactionFile}.lock`;
169
+ acquirePageAssemblyLock(lockFile);
170
+ try {
171
+ const transaction = readBuildTransaction(transactionFile, inputDir, appConfigFile);
172
+ if (!transaction || isPageAssemblyActive(transaction, transactionFile)) return;
173
+ restoreBuildTransaction(transaction, transactionFile);
174
+ } finally {
175
+ releasePageAssemblyLock(lockFile);
176
+ }
177
+ }
178
+ function preparePageAssembly(options) {
179
+ const lockFile = `${options.transactionFile}.lock`;
180
+ acquirePageAssemblyLock(lockFile);
181
+ try {
182
+ let transaction = readBuildTransaction(
183
+ options.transactionFile,
184
+ options.inputDir,
185
+ options.appConfigFile
186
+ );
187
+ if (transaction && isPageAssemblyActive(transaction, options.transactionFile)) {
188
+ return {
189
+ transaction,
190
+ leaseFile: createPageAssemblyLease(options.transactionFile)
191
+ };
192
+ }
193
+ let originalAppConfig = options.originalAppConfig;
194
+ if (transaction) {
195
+ originalAppConfig = transaction.originalAppConfig;
196
+ restoreBuildTransaction(transaction, options.transactionFile);
197
+ }
198
+ const generatedFiles = options.pageMap.flatMap((page) => {
199
+ const pageFile = resolve(options.inputDir, `${page.route}.tsx`);
200
+ const configFile = resolve(options.inputDir, `${page.route}.config.ts`);
201
+ return [pageFile, configFile].filter(
202
+ (file) => !existsSync(file) || isGeneratedPageFile(file) || isGeneratedPageConfig(file)
203
+ );
204
+ });
205
+ const staticFiles = collectModuleStaticFiles(
206
+ options.moduleStaticRoots,
207
+ resolve(options.inputDir, "static")
208
+ );
209
+ transaction = {
210
+ inputDir: options.inputDir,
211
+ appConfigFile: options.appConfigFile,
212
+ originalAppConfig,
213
+ generatedFiles,
214
+ generatedStaticFiles: staticFiles.map(({ target }) => target),
215
+ ownerPid: process.pid,
216
+ ready: false
217
+ };
218
+ writeBuildTransaction(options.transactionFile, transaction, "wx");
219
+ const leaseFile = createPageAssemblyLease(options.transactionFile);
220
+ try {
221
+ options.pageMap.forEach((page) => {
222
+ appendPage(options.baseManifest, page.route);
223
+ const pageFile = resolve(options.inputDir, `${page.route}.tsx`);
224
+ const configFile = resolve(options.inputDir, `${page.route}.config.ts`);
225
+ if (!existsSync(pageFile)) {
226
+ mkdirSync(dirname(pageFile), { recursive: true });
227
+ writeFileSync(pageFile, createPageWrapper(page));
228
+ }
229
+ if (!existsSync(configFile)) writeFileSync(configFile, createPageConfig(page));
230
+ });
231
+ staticFiles.forEach(({ source, target }) => {
232
+ mkdirSync(dirname(target), { recursive: true });
233
+ copyFileSync(source, target);
234
+ });
235
+ writeFileSync(
236
+ options.appConfigFile,
237
+ `export default defineAppConfig(${JSON.stringify(options.baseManifest, null, 2)})
238
+ `
239
+ );
240
+ transaction.ready = true;
241
+ writeBuildTransaction(options.transactionFile, transaction);
242
+ return { transaction, leaseFile };
243
+ } catch (error) {
244
+ releasePageAssemblyLease(leaseFile);
245
+ restoreBuildTransaction(transaction, options.transactionFile);
246
+ throw error;
247
+ }
248
+ } finally {
249
+ releasePageAssemblyLock(lockFile);
250
+ }
251
+ }
252
+ function readBuildTransaction(transactionFile, inputDir, appConfigFile) {
188
253
  if (!existsSync(transactionFile)) return;
189
254
  const transaction = JSON.parse(readFileSync(transactionFile, "utf8"));
190
255
  if (transaction.inputDir !== inputDir || transaction.appConfigFile !== appConfigFile) {
191
256
  throw new Error(`Taro \u6784\u5EFA\u4E8B\u52A1\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A${transactionFile}`);
192
257
  }
193
- if (transaction.ownerPid !== process.pid && isProcessRunning(transaction.ownerPid)) {
194
- throw new Error(
195
- `\u9875\u9762\u88C5\u914D\u5DF2\u7531\u8FDB\u7A0B ${transaction.ownerPid} \u4F7F\u7528\uFF0C\u8BF7\u5148\u505C\u6B62\u53E6\u4E00\u4E2A H5 \u6216\u5C0F\u7A0B\u5E8F\u5F00\u53D1\u8FDB\u7A0B`
196
- );
197
- }
198
- cleanupTransaction(transaction);
199
- unlinkSync(transactionFile);
258
+ return transaction;
200
259
  }
201
- function cleanupTransaction(transaction) {
260
+ function writeBuildTransaction(transactionFile, transaction, flag) {
261
+ writeFileSync(
262
+ transactionFile,
263
+ `${JSON.stringify(transaction, null, 2)}
264
+ `,
265
+ flag ? { flag } : void 0
266
+ );
267
+ }
268
+ function restoreBuildTransaction(transaction, transactionFile) {
202
269
  for (const file of [...transaction.generatedFiles].reverse()) {
203
270
  if (existsSync(file)) unlinkSync(file);
204
271
  removeEmptyParents(dirname(file), transaction.inputDir);
205
272
  }
206
- removeGeneratedStaticFiles(transaction.generatedStaticFiles, resolve(transaction.inputDir, "static"));
273
+ removeGeneratedStaticFiles(
274
+ transaction.generatedStaticFiles ?? [],
275
+ resolve(transaction.inputDir, "static")
276
+ );
207
277
  writeFileSync(transaction.appConfigFile, transaction.originalAppConfig);
278
+ if (existsSync(transactionFile)) unlinkSync(transactionFile);
279
+ }
280
+ function releasePageAssembly(transactionFile, leaseFile) {
281
+ releasePageAssemblyLease(leaseFile);
282
+ const lockFile = `${transactionFile}.lock`;
283
+ acquirePageAssemblyLock(lockFile);
284
+ try {
285
+ const transaction = readBuildTransactionFromFile(transactionFile);
286
+ if (!transaction || isPageAssemblyActive(transaction, transactionFile)) return;
287
+ restoreBuildTransaction(transaction, transactionFile);
288
+ } finally {
289
+ releasePageAssemblyLock(lockFile);
290
+ }
291
+ }
292
+ function readBuildTransactionFromFile(transactionFile) {
293
+ if (!existsSync(transactionFile)) return;
294
+ return JSON.parse(readFileSync(transactionFile, "utf8"));
295
+ }
296
+ function createPageAssemblyLease(transactionFile) {
297
+ const leaseDirectory = `${transactionFile}.leases`;
298
+ mkdirSync(leaseDirectory, { recursive: true });
299
+ const leaseFile = resolve(
300
+ leaseDirectory,
301
+ `${process.pid}-${Date.now()}-${++sourceVersionCounter}.lease`
302
+ );
303
+ writeFileSync(leaseFile, `${JSON.stringify({ ownerPid: process.pid })}
304
+ `, { flag: "wx" });
305
+ return leaseFile;
306
+ }
307
+ function releasePageAssemblyLease(leaseFile) {
308
+ if (existsSync(leaseFile)) unlinkSync(leaseFile);
309
+ const leaseDirectory = dirname(leaseFile);
310
+ if (existsSync(leaseDirectory) && !readdirSync(leaseDirectory).length) {
311
+ try {
312
+ rmdirSync(leaseDirectory);
313
+ } catch (error) {
314
+ const code = error.code;
315
+ if (code !== "ENOTEMPTY" && code !== "EEXIST") throw error;
316
+ }
317
+ }
318
+ }
319
+ function isPageAssemblyActive(transaction, transactionFile) {
320
+ if (listActivePageLeases(`${transactionFile}.leases`).length) return true;
321
+ return transaction.ownerPid !== void 0 && transaction.ownerPid !== process.pid && isProcessRunning(transaction.ownerPid);
322
+ }
323
+ function listActivePageLeases(leaseDirectory) {
324
+ if (!existsSync(leaseDirectory)) return [];
325
+ const activePids = [];
326
+ for (const entry of readdirSync(leaseDirectory)) {
327
+ const leaseFile = resolve(leaseDirectory, entry);
328
+ try {
329
+ const lease = JSON.parse(readFileSync(leaseFile, "utf8"));
330
+ if (lease.ownerPid && isProcessRunning(lease.ownerPid)) {
331
+ activePids.push(lease.ownerPid);
332
+ } else {
333
+ unlinkSync(leaseFile);
334
+ }
335
+ } catch {
336
+ unlinkSync(leaseFile);
337
+ }
338
+ }
339
+ return activePids;
340
+ }
341
+ function acquirePageAssemblyLock(lockFile) {
342
+ const deadline = Date.now() + PAGE_ASSEMBLY_WAIT_TIMEOUT_MS;
343
+ while (true) {
344
+ try {
345
+ writeFileSync(lockFile, `${JSON.stringify({ ownerPid: process.pid })}
346
+ `, { flag: "wx" });
347
+ return;
348
+ } catch (error) {
349
+ if (error.code !== "EEXIST") throw error;
350
+ const ownerPid = readPageAssemblyLockOwner(lockFile);
351
+ if (ownerPid !== void 0 && !isProcessRunning(ownerPid)) {
352
+ unlinkSync(lockFile);
353
+ continue;
354
+ }
355
+ if (Date.now() >= deadline) throw new Error(`\u7B49\u5F85 Taro \u9875\u9762\u88C5\u914D\u9501\u8D85\u65F6\uFF1A${lockFile}`);
356
+ waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS);
357
+ }
358
+ }
359
+ }
360
+ function releasePageAssemblyLock(lockFile) {
361
+ if (!existsSync(lockFile)) return;
362
+ if (readPageAssemblyLockOwner(lockFile) === process.pid) unlinkSync(lockFile);
363
+ }
364
+ function readPageAssemblyLockOwner(lockFile) {
365
+ try {
366
+ return JSON.parse(readFileSync(lockFile, "utf8")).ownerPid;
367
+ } catch {
368
+ return;
369
+ }
370
+ }
371
+ function waitForPageAssembly(milliseconds) {
372
+ const buffer = new SharedArrayBuffer(4);
373
+ Atomics.wait(new Int32Array(buffer), 0, 0, milliseconds);
208
374
  }
209
375
  function isProcessRunning(pid) {
210
376
  try {
@@ -272,7 +438,7 @@ function appendPage(manifest, route) {
272
438
  if (!subpackage.pages.includes(subRoute)) subpackage.pages.push(subRoute);
273
439
  }
274
440
  function createPageWrapper(page) {
275
- return `import KratosPage from ${JSON.stringify(page.source)}
441
+ return `import KratosPage from ${JSON.stringify(`${page.source}.tsx`)}
276
442
  import { KratosPageFrame } from '@liujitcn/kratos-taro-app-core/components/KratosPageFrame'
277
443
  import { KratosTabBar } from '@liujitcn/kratos-taro-app-core/components/KratosTabBar'
278
444
 
@@ -298,6 +464,12 @@ function createPageConfig(page) {
298
464
  return `export default definePageConfig(${JSON.stringify(page.style ?? {}, null, 2)})
299
465
  `;
300
466
  }
467
+ function isGeneratedPageFile(file) {
468
+ return existsSync(file) && readFileSync(file, "utf8").includes("\u81EA\u52A8\u751F\u6210\u7684\u6A21\u5757\u9875\u9762\u5305\u88C5\u5668");
469
+ }
470
+ function isGeneratedPageConfig(file) {
471
+ return existsSync(file) && readFileSync(file, "utf8").includes("definePageConfig(");
472
+ }
301
473
  function normalizeRoute(route) {
302
474
  return route.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\.tsx$/, "");
303
475
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git@github.com:liujitcn/kratos-admin.git"
9
9
  },
10
- "version": "0.0.18",
10
+ "version": "0.0.19",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
@@ -18,6 +18,7 @@
18
18
  align-items: center;
19
19
  justify-content: center;
20
20
  flex-direction: column;
21
+ transform: translateY(clamp(1PX, env(safe-area-inset-bottom), 7PX));
21
22
  color: #333;
22
23
  font-size: 10PX;
23
24
  line-height: 12PX;
@@ -1,11 +1,11 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/config.proto
6
6
 
7
7
  /* eslint-disable */
8
- import type { BaseConfigSite } from "../../common/v1/enum";
8
+ import type { BaseConfigSite } from "./enum";
9
9
 
10
10
  /** 获取系统配置条件 */
11
11
  export interface GetConfigRequest {
@@ -1,18 +1,31 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
- // source: common/v1/enum.proto
5
+ // source: base/v1/enum.proto
6
6
 
7
7
  /* eslint-disable */
8
8
 
9
- /** 状态 */
10
- export enum Status {
11
- UNKNOWN = 0,
12
- /** ENABLE - 启用 */
13
- ENABLE = 1,
14
- /** DISABLE - 禁用 */
15
- DISABLE = 2,
9
+ /** AI 助手消息状态 */
10
+ export enum AiMessageStatus {
11
+ /** UNKNOWN_AMS - 未知AI助手消息状态 */
12
+ UNKNOWN_AMS = 0,
13
+ /** GENERATING_AMS - 生成中 */
14
+ GENERATING_AMS = 1,
15
+ /** SUCCESS_AMS - 成功 */
16
+ SUCCESS_AMS = 2,
17
+ /** FAILED_AMS - 失败 */
18
+ FAILED_AMS = 3,
19
+ }
20
+
21
+ /** 终端类型 */
22
+ export enum Terminal {
23
+ /** UNKNOWN_TERMINAL - 未知终端 */
24
+ UNKNOWN_TERMINAL = 0,
25
+ /** TERMINAL_APP - 移动端 */
26
+ TERMINAL_APP = 1,
27
+ /** TERMINAL_ADMIN - 管理端 */
28
+ TERMINAL_ADMIN = 2,
16
29
  }
17
30
 
18
31
  /** 系统配置位置 */
@@ -39,33 +52,3 @@ export enum PasswordCryptoScene {
39
52
  /** UPDATE_USER_PASSWORD - 个人修改密码加密场景 */
40
53
  UPDATE_USER_PASSWORD = 4,
41
54
  }
42
-
43
- /** AI 助手消息状态 */
44
- export enum AiMessageStatus {
45
- /** UNKNOWN_AAMS - 未知AI助手消息状态 */
46
- UNKNOWN_AAMS = 0,
47
- /** GENERATING_AAMS - 生成中 */
48
- GENERATING_AAMS = 1,
49
- /** SUCCESS_AAMS - 成功 */
50
- SUCCESS_AAMS = 2,
51
- /** FAILED_AAMS - 失败 */
52
- FAILED_AAMS = 3,
53
- }
54
-
55
- /** 支付通知资源类型 */
56
- export enum ResourceType {
57
- /** TRANSACTION - 支付 */
58
- TRANSACTION = 0,
59
- /** REFUND - 退款 */
60
- REFUND = 1,
61
- }
62
-
63
- /** 终端类型 */
64
- export enum Terminal {
65
- /** TERMINAL_UNSPECIFIED - 未知终端 */
66
- TERMINAL_UNSPECIFIED = 0,
67
- /** TERMINAL_APP - 移动端 */
68
- TERMINAL_APP = 1,
69
- /** TERMINAL_ADMIN - 管理端 */
70
- TERMINAL_ADMIN = 2,
71
- }
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/file.proto
6
6
 
@@ -1,13 +1,13 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/login.proto
6
6
 
7
7
  /* eslint-disable */
8
- import type { PasswordCryptoScene } from "../../common/v1/enum";
9
8
  import type { PasswordCrypto } from "../../common/v1/types";
10
9
  import type { Empty } from "../../google/protobuf/empty";
10
+ import type { PasswordCryptoScene } from "./enum";
11
11
 
12
12
  /** 验证码获取条件 */
13
13
  export interface CaptchaRequest {
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/mcp.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/oauth.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: base/v1/sse.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: common/v1/common.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: common/v1/types.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: google/protobuf/empty.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: google/protobuf/wrappers.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: system/app/v1/auth.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: system/app/v1/base_area.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: system/app/v1/base_dict.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: system/app/v1/base_menu.proto
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.11.8
4
4
  // protoc unknown
5
5
  // source: system/common/v1/enum.proto
6
6
 
package/src/runner.ts CHANGED
@@ -34,13 +34,25 @@ type BuildTransaction = {
34
34
  originalAppConfig: string
35
35
  generatedFiles: string[]
36
36
  generatedStaticFiles: string[]
37
- ownerPid: number
37
+ ownerPid?: number
38
+ ready?: boolean
38
39
  }
39
40
 
41
+ type PageAssembly = {
42
+ transaction: BuildTransaction
43
+ leaseFile: string
44
+ }
45
+
46
+ let sourceVersionCounter = 0
47
+ const PAGE_ASSEMBLY_WAIT_TIMEOUT_MS = 30_000
48
+ const PAGE_ASSEMBLY_POLL_INTERVAL_MS = 25
49
+
40
50
  type CliOptions = {
41
51
  type: 'h5' | 'weapp'
42
52
  mode: string
43
53
  watch: boolean
54
+ prepareOnly: boolean
55
+ cleanupOnly: boolean
44
56
  }
45
57
 
46
58
  /** 运行 Taro 构建并在进程结束后恢复临时页面。 */
@@ -52,6 +64,7 @@ async function main(): Promise<void> {
52
64
  const baseConfigFile = resolve(inputDir, 'app.config.base.json')
53
65
  const transactionFile = resolve(hostRoot, '.kratos-taro-app-pages-state.json')
54
66
  recoverBuildTransaction(transactionFile, inputDir, appConfigFile)
67
+ if (options.cleanupOnly) return
55
68
 
56
69
  const originalAppConfig = readFileSync(appConfigFile, 'utf8')
57
70
  const manifest = JSON.parse(readFileSync(baseConfigFile, 'utf8')) as AppManifest
@@ -69,33 +82,24 @@ async function main(): Promise<void> {
69
82
  })
70
83
  })
71
84
 
72
- const generatedFiles = [...pageMap.values()].flatMap((page) => {
73
- const pageFile = resolve(inputDir, `${page.route}.tsx`)
74
- const configFile = resolve(inputDir, `${page.route}.config.ts`)
75
- return [pageFile, configFile].filter((file) => !existsSync(file))
76
- })
77
- const staticRoot = resolve(inputDir, 'static')
78
- const staticFiles = collectModuleStaticFiles(
79
- modules.map((module) => resolve(module.root, 'src/static')),
80
- staticRoot,
81
- )
82
- const generatedStaticFiles = staticFiles.map(({ target }) => target)
83
- const transaction: BuildTransaction = {
84
- inputDir,
85
+ const pageAssembly = preparePageAssembly({
85
86
  appConfigFile,
87
+ baseManifest: manifest,
88
+ inputDir,
89
+ moduleStaticRoots: modules.map((module) => resolve(module.root, 'src/static')),
86
90
  originalAppConfig,
87
- generatedFiles,
88
- generatedStaticFiles,
89
- ownerPid: process.pid,
90
- }
91
- writeFileSync(transactionFile, `${JSON.stringify(transaction, null, 2)}\n`, { flag: 'wx' })
91
+ pageMap: [...pageMap.values()],
92
+ transactionFile,
93
+ })
92
94
 
93
95
  let cleaned = false
94
96
  const cleanup = () => {
95
97
  if (cleaned) return
96
98
  cleaned = true
97
- cleanupTransaction(transaction)
98
- if (existsSync(transactionFile)) unlinkSync(transactionFile)
99
+ releasePageAssembly(transactionFile, pageAssembly.leaseFile)
100
+ }
101
+ if (options.prepareOnly) {
102
+ return
99
103
  }
100
104
  const handleSignal = (signal: NodeJS.Signals) => {
101
105
  child?.kill(signal)
@@ -105,27 +109,6 @@ async function main(): Promise<void> {
105
109
  process.once('SIGTERM', () => handleSignal('SIGTERM'))
106
110
 
107
111
  try {
108
- pageMap.forEach((page) => {
109
- appendPage(manifest, page.route)
110
- const pageFile = resolve(inputDir, `${page.route}.tsx`)
111
- const configFile = resolve(inputDir, `${page.route}.config.ts`)
112
- if (!existsSync(pageFile)) {
113
- mkdirSync(dirname(pageFile), { recursive: true })
114
- writeFileSync(pageFile, createPageWrapper(page))
115
- }
116
- if (!existsSync(configFile)) {
117
- writeFileSync(configFile, createPageConfig(page))
118
- }
119
- })
120
- staticFiles.forEach(({ source, target }) => {
121
- mkdirSync(dirname(target), { recursive: true })
122
- copyFileSync(source, target)
123
- })
124
- writeFileSync(
125
- appConfigFile,
126
- `export default defineAppConfig(${JSON.stringify(manifest, null, 2)})\n`,
127
- )
128
-
129
112
  const args = ['exec', 'taro', 'build', '--type', options.type, '--mode', options.mode]
130
113
  if (options.watch) args.push('--watch')
131
114
  child = spawn(process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm', args, {
@@ -133,6 +116,9 @@ async function main(): Promise<void> {
133
116
  env: {
134
117
  ...process.env,
135
118
  NODE_ENV: options.mode === 'development' ? 'development' : 'production',
119
+ KRATOS_TARO_OUTPUT_ROOT:
120
+ process.env.KRATOS_TARO_OUTPUT_ROOT ||
121
+ (options.type === 'h5' ? 'dist/h5' : 'dist/mp-weixin'),
136
122
  },
137
123
  stdio: 'inherit',
138
124
  })
@@ -156,6 +142,8 @@ function parseArguments(args: string[]): CliOptions {
156
142
  let type: CliOptions['type'] | undefined
157
143
  let mode = 'production'
158
144
  let watch = false
145
+ let prepareOnly = false
146
+ let cleanupOnly = false
159
147
  for (let index = 0; index < args.length; index += 1) {
160
148
  const argument = args[index]
161
149
  if (argument === '--type') {
@@ -166,12 +154,16 @@ function parseArguments(args: string[]): CliOptions {
166
154
  mode = args[++index] || mode
167
155
  } else if (argument === '--watch') {
168
156
  watch = true
157
+ } else if (argument === '--prepare-only') {
158
+ prepareOnly = true
159
+ } else if (argument === '--cleanup-only') {
160
+ cleanupOnly = true
169
161
  } else {
170
162
  throw new Error(`未知参数:${argument}`)
171
163
  }
172
164
  }
173
165
  if (!type) throw new Error('缺少 --type h5|weapp')
174
- return { type, mode, watch }
166
+ return { type, mode, watch, prepareOnly, cleanupOnly }
175
167
  }
176
168
 
177
169
  async function loadBuildModules(
@@ -237,27 +229,244 @@ function recoverBuildTransaction(
237
229
  inputDir: string,
238
230
  appConfigFile: string,
239
231
  ): void {
232
+ const lockFile = `${transactionFile}.lock`
233
+ acquirePageAssemblyLock(lockFile)
234
+ try {
235
+ const transaction = readBuildTransaction(transactionFile, inputDir, appConfigFile)
236
+ if (!transaction || isPageAssemblyActive(transaction, transactionFile)) return
237
+ restoreBuildTransaction(transaction, transactionFile)
238
+ } finally {
239
+ releasePageAssemblyLock(lockFile)
240
+ }
241
+ }
242
+
243
+ function preparePageAssembly(options: {
244
+ appConfigFile: string
245
+ baseManifest: AppManifest
246
+ inputDir: string
247
+ moduleStaticRoots: string[]
248
+ originalAppConfig: string
249
+ pageMap: PageEntry[]
250
+ transactionFile: string
251
+ }): PageAssembly {
252
+ const lockFile = `${options.transactionFile}.lock`
253
+ acquirePageAssemblyLock(lockFile)
254
+ try {
255
+ let transaction = readBuildTransaction(
256
+ options.transactionFile,
257
+ options.inputDir,
258
+ options.appConfigFile,
259
+ )
260
+ if (transaction && isPageAssemblyActive(transaction, options.transactionFile)) {
261
+ return {
262
+ transaction,
263
+ leaseFile: createPageAssemblyLease(options.transactionFile),
264
+ }
265
+ }
266
+
267
+ let originalAppConfig = options.originalAppConfig
268
+ if (transaction) {
269
+ originalAppConfig = transaction.originalAppConfig
270
+ restoreBuildTransaction(transaction, options.transactionFile)
271
+ }
272
+
273
+ const generatedFiles = options.pageMap.flatMap((page) => {
274
+ const pageFile = resolve(options.inputDir, `${page.route}.tsx`)
275
+ const configFile = resolve(options.inputDir, `${page.route}.config.ts`)
276
+ return [pageFile, configFile].filter(
277
+ (file) => !existsSync(file) || isGeneratedPageFile(file) || isGeneratedPageConfig(file),
278
+ )
279
+ })
280
+ const staticFiles = collectModuleStaticFiles(
281
+ options.moduleStaticRoots,
282
+ resolve(options.inputDir, 'static'),
283
+ )
284
+ transaction = {
285
+ inputDir: options.inputDir,
286
+ appConfigFile: options.appConfigFile,
287
+ originalAppConfig,
288
+ generatedFiles,
289
+ generatedStaticFiles: staticFiles.map(({ target }) => target),
290
+ ownerPid: process.pid,
291
+ ready: false,
292
+ }
293
+ writeBuildTransaction(options.transactionFile, transaction, 'wx')
294
+ const leaseFile = createPageAssemblyLease(options.transactionFile)
295
+ try {
296
+ options.pageMap.forEach((page) => {
297
+ appendPage(options.baseManifest, page.route)
298
+ const pageFile = resolve(options.inputDir, `${page.route}.tsx`)
299
+ const configFile = resolve(options.inputDir, `${page.route}.config.ts`)
300
+ if (!existsSync(pageFile)) {
301
+ mkdirSync(dirname(pageFile), { recursive: true })
302
+ writeFileSync(pageFile, createPageWrapper(page))
303
+ }
304
+ if (!existsSync(configFile)) writeFileSync(configFile, createPageConfig(page))
305
+ })
306
+ staticFiles.forEach(({ source, target }) => {
307
+ mkdirSync(dirname(target), { recursive: true })
308
+ copyFileSync(source, target)
309
+ })
310
+ writeFileSync(
311
+ options.appConfigFile,
312
+ `export default defineAppConfig(${JSON.stringify(options.baseManifest, null, 2)})\n`,
313
+ )
314
+ transaction.ready = true
315
+ writeBuildTransaction(options.transactionFile, transaction)
316
+ return { transaction, leaseFile }
317
+ } catch (error) {
318
+ releasePageAssemblyLease(leaseFile)
319
+ restoreBuildTransaction(transaction, options.transactionFile)
320
+ throw error
321
+ }
322
+ } finally {
323
+ releasePageAssemblyLock(lockFile)
324
+ }
325
+ }
326
+
327
+ function readBuildTransaction(
328
+ transactionFile: string,
329
+ inputDir: string,
330
+ appConfigFile: string,
331
+ ): BuildTransaction | undefined {
240
332
  if (!existsSync(transactionFile)) return
241
333
  const transaction = JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
242
334
  if (transaction.inputDir !== inputDir || transaction.appConfigFile !== appConfigFile) {
243
335
  throw new Error(`Taro 构建事务目录不匹配:${transactionFile}`)
244
336
  }
245
- if (transaction.ownerPid !== process.pid && isProcessRunning(transaction.ownerPid)) {
246
- throw new Error(
247
- `页面装配已由进程 ${transaction.ownerPid} 使用,请先停止另一个 H5 或小程序开发进程`,
248
- )
249
- }
250
- cleanupTransaction(transaction)
251
- unlinkSync(transactionFile)
337
+ return transaction
252
338
  }
253
339
 
254
- function cleanupTransaction(transaction: BuildTransaction): void {
340
+ function writeBuildTransaction(
341
+ transactionFile: string,
342
+ transaction: BuildTransaction,
343
+ flag?: 'wx',
344
+ ): void {
345
+ writeFileSync(
346
+ transactionFile,
347
+ `${JSON.stringify(transaction, null, 2)}\n`,
348
+ flag ? { flag } : undefined,
349
+ )
350
+ }
351
+
352
+ function restoreBuildTransaction(transaction: BuildTransaction, transactionFile: string): void {
255
353
  for (const file of [...transaction.generatedFiles].reverse()) {
256
354
  if (existsSync(file)) unlinkSync(file)
257
355
  removeEmptyParents(dirname(file), transaction.inputDir)
258
356
  }
259
- removeGeneratedStaticFiles(transaction.generatedStaticFiles, resolve(transaction.inputDir, 'static'))
357
+ removeGeneratedStaticFiles(
358
+ transaction.generatedStaticFiles ?? [],
359
+ resolve(transaction.inputDir, 'static'),
360
+ )
260
361
  writeFileSync(transaction.appConfigFile, transaction.originalAppConfig)
362
+ if (existsSync(transactionFile)) unlinkSync(transactionFile)
363
+ }
364
+
365
+ function releasePageAssembly(transactionFile: string, leaseFile: string): void {
366
+ releasePageAssemblyLease(leaseFile)
367
+ const lockFile = `${transactionFile}.lock`
368
+ acquirePageAssemblyLock(lockFile)
369
+ try {
370
+ const transaction = readBuildTransactionFromFile(transactionFile)
371
+ if (!transaction || isPageAssemblyActive(transaction, transactionFile)) return
372
+ restoreBuildTransaction(transaction, transactionFile)
373
+ } finally {
374
+ releasePageAssemblyLock(lockFile)
375
+ }
376
+ }
377
+
378
+ function readBuildTransactionFromFile(transactionFile: string): BuildTransaction | undefined {
379
+ if (!existsSync(transactionFile)) return
380
+ return JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
381
+ }
382
+
383
+ function createPageAssemblyLease(transactionFile: string): string {
384
+ const leaseDirectory = `${transactionFile}.leases`
385
+ mkdirSync(leaseDirectory, { recursive: true })
386
+ const leaseFile = resolve(
387
+ leaseDirectory,
388
+ `${process.pid}-${Date.now()}-${++sourceVersionCounter}.lease`,
389
+ )
390
+ writeFileSync(leaseFile, `${JSON.stringify({ ownerPid: process.pid })}\n`, { flag: 'wx' })
391
+ return leaseFile
392
+ }
393
+
394
+ function releasePageAssemblyLease(leaseFile: string): void {
395
+ if (existsSync(leaseFile)) unlinkSync(leaseFile)
396
+ const leaseDirectory = dirname(leaseFile)
397
+ if (existsSync(leaseDirectory) && !readdirSync(leaseDirectory).length) {
398
+ try {
399
+ rmdirSync(leaseDirectory)
400
+ } catch (error) {
401
+ const code = (error as NodeJS.ErrnoException).code
402
+ if (code !== 'ENOTEMPTY' && code !== 'EEXIST') throw error
403
+ }
404
+ }
405
+ }
406
+
407
+ function isPageAssemblyActive(transaction: BuildTransaction, transactionFile: string): boolean {
408
+ if (listActivePageLeases(`${transactionFile}.leases`).length) return true
409
+ return (
410
+ transaction.ownerPid !== undefined &&
411
+ transaction.ownerPid !== process.pid &&
412
+ isProcessRunning(transaction.ownerPid)
413
+ )
414
+ }
415
+
416
+ function listActivePageLeases(leaseDirectory: string): number[] {
417
+ if (!existsSync(leaseDirectory)) return []
418
+ const activePids: number[] = []
419
+ for (const entry of readdirSync(leaseDirectory)) {
420
+ const leaseFile = resolve(leaseDirectory, entry)
421
+ try {
422
+ const lease = JSON.parse(readFileSync(leaseFile, 'utf8')) as { ownerPid?: number }
423
+ if (lease.ownerPid && isProcessRunning(lease.ownerPid)) {
424
+ activePids.push(lease.ownerPid)
425
+ } else {
426
+ unlinkSync(leaseFile)
427
+ }
428
+ } catch {
429
+ unlinkSync(leaseFile)
430
+ }
431
+ }
432
+ return activePids
433
+ }
434
+
435
+ function acquirePageAssemblyLock(lockFile: string): void {
436
+ const deadline = Date.now() + PAGE_ASSEMBLY_WAIT_TIMEOUT_MS
437
+ while (true) {
438
+ try {
439
+ writeFileSync(lockFile, `${JSON.stringify({ ownerPid: process.pid })}\n`, { flag: 'wx' })
440
+ return
441
+ } catch (error) {
442
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
443
+ const ownerPid = readPageAssemblyLockOwner(lockFile)
444
+ if (ownerPid !== undefined && !isProcessRunning(ownerPid)) {
445
+ unlinkSync(lockFile)
446
+ continue
447
+ }
448
+ if (Date.now() >= deadline) throw new Error(`等待 Taro 页面装配锁超时:${lockFile}`)
449
+ waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS)
450
+ }
451
+ }
452
+ }
453
+
454
+ function releasePageAssemblyLock(lockFile: string): void {
455
+ if (!existsSync(lockFile)) return
456
+ if (readPageAssemblyLockOwner(lockFile) === process.pid) unlinkSync(lockFile)
457
+ }
458
+
459
+ function readPageAssemblyLockOwner(lockFile: string): number | undefined {
460
+ try {
461
+ return (JSON.parse(readFileSync(lockFile, 'utf8')) as { ownerPid?: number }).ownerPid
462
+ } catch {
463
+ return
464
+ }
465
+ }
466
+
467
+ function waitForPageAssembly(milliseconds: number): void {
468
+ const buffer = new SharedArrayBuffer(4)
469
+ Atomics.wait(new Int32Array(buffer), 0, 0, milliseconds)
261
470
  }
262
471
 
263
472
  function isProcessRunning(pid: number): boolean {
@@ -334,7 +543,7 @@ function appendPage(manifest: AppManifest, route: string): void {
334
543
  }
335
544
 
336
545
  function createPageWrapper(page: PageEntry): string {
337
- return `import KratosPage from ${JSON.stringify(page.source)}
546
+ return `import KratosPage from ${JSON.stringify(`${page.source}.tsx`)}
338
547
  import { KratosPageFrame } from '@liujitcn/kratos-taro-app-core/components/KratosPageFrame'
339
548
  import { KratosTabBar } from '@liujitcn/kratos-taro-app-core/components/KratosTabBar'
340
549
 
@@ -361,6 +570,14 @@ function createPageConfig(page: PageEntry): string {
361
570
  return `export default definePageConfig(${JSON.stringify(page.style ?? {}, null, 2)})\n`
362
571
  }
363
572
 
573
+ function isGeneratedPageFile(file: string): boolean {
574
+ return existsSync(file) && readFileSync(file, 'utf8').includes('自动生成的模块页面包装器')
575
+ }
576
+
577
+ function isGeneratedPageConfig(file: string): boolean {
578
+ return existsSync(file) && readFileSync(file, 'utf8').includes('definePageConfig(')
579
+ }
580
+
364
581
  function normalizeRoute(route: string): string {
365
582
  return route
366
583
  .replace(/\\/g, '/')
@@ -1,6 +1,6 @@
1
1
  import { create } from 'zustand'
2
2
  import { defConfigService } from '../api/base/config'
3
- import { BaseConfigSite } from '../rpc/common/v1/enum'
3
+ import { BaseConfigSite } from '../rpc/base/v1/enum'
4
4
 
5
5
  const REQUIRED_APP_CONFIGS = [
6
6
  { key: 'serviceProtocol', name: '服务条款' },
package/src/utils/http.ts CHANGED
@@ -113,7 +113,7 @@ async function sendRequest<T>(
113
113
  ...(accessToken ? { Authorization: accessToken } : {}),
114
114
  },
115
115
  })
116
- const responseData = response.data as ErrorData
116
+ const responseData = response.data as ErrorData | null | undefined
117
117
  if (response.statusCode >= 200 && response.statusCode < 300 && !isAuthErrorResponse(responseData)) {
118
118
  return response.data as T
119
119
  }
@@ -129,7 +129,7 @@ async function sendRequest<T>(
129
129
  handleAuthExpiredByMode(authMode, requestUrl, responseData)
130
130
  throw response
131
131
  }
132
- await Taro.showToast({ icon: 'none', title: responseData.message || '请求错误' })
132
+ await Taro.showToast({ icon: 'none', title: responseData?.message || '请求错误' })
133
133
  throw response
134
134
  } catch (error) {
135
135
  if (
@@ -243,7 +243,7 @@ async function promptRelogin(): Promise<void> {
243
243
  function handleAuthExpiredByMode(
244
244
  authMode: AuthMode,
245
245
  url: string,
246
- responseData: ErrorData,
246
+ responseData: ErrorData | null | undefined,
247
247
  ): void {
248
248
  if (authMode === 'required' && !AUTH_EXPIRED_EXCLUDED_URL_SET.has(url)) {
249
249
  void promptRelogin()
@@ -251,7 +251,7 @@ function handleAuthExpiredByMode(
251
251
  }
252
252
  silentClearAuthData()
253
253
  if (authMode !== 'optional') {
254
- void Taro.showToast({ icon: 'none', title: responseData.message || '请求错误' })
254
+ void Taro.showToast({ icon: 'none', title: responseData?.message || '请求错误' })
255
255
  }
256
256
  }
257
257
 
@@ -1,7 +1,7 @@
1
1
  import Taro from '@tarojs/taro'
2
2
  import * as miniCrypto from 'asmcrypto.js'
3
3
  import { defLoginService } from '../api/base/login'
4
- import { PasswordCryptoScene } from '../rpc/common/v1/enum'
4
+ import { PasswordCryptoScene } from '../rpc/base/v1/enum'
5
5
  import type { PasswordCrypto } from '../rpc/common/v1/types'
6
6
 
7
7
  type MiniCrypto = typeof import('asmcrypto.js')