weaver-work-cli 0.1.33 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/chunks/{archive-FVFY6GZN.js → archive-PDV724YK.js} +5 -4
  2. package/dist/chunks/{archive-oa-NW3OD4UV.js → archive-oa-4XE4MNXQ.js} +4 -3
  3. package/dist/chunks/{asset-7QJKMIDV.js → asset-PDL2QE2N.js} +8 -7
  4. package/dist/chunks/{attachment-content-OSAVA6K3.js → attachment-content-MDDGOE5E.js} +3 -3
  5. package/dist/chunks/{blog-I7SDPNW4.js → blog-UYR3EUXW.js} +5 -4
  6. package/dist/chunks/{caizhilian-O37ZIQNY.js → caizhilian-LG2X5NMF.js} +5 -4
  7. package/dist/chunks/{calendar-7KXE4ED3.js → calendar-FG4BAZHE.js} +4 -3
  8. package/dist/chunks/{chunk-Q6LWB5HX.js → chunk-6FTTSA45.js} +4 -3
  9. package/dist/chunks/{chunk-MQ2I5AA3.js → chunk-6LTFIFLM.js} +3 -2
  10. package/dist/chunks/{chunk-WRRJ4GG2.js → chunk-CORFRD7Q.js} +4 -3
  11. package/dist/chunks/{chunk-WY74UBJ6.js → chunk-DMV2TOMH.js} +2194 -240
  12. package/dist/chunks/{chunk-MEEFGWTM.js → chunk-ELYDWBZJ.js} +135 -10
  13. package/dist/chunks/{chunk-EEWPQE3O.js → chunk-FUWVHMVV.js} +7 -6
  14. package/dist/chunks/{chunk-HEL5XTYI.js → chunk-GGJFMNJM.js} +26 -4
  15. package/dist/chunks/{chunk-KAS45KNR.js → chunk-IZUDA353.js} +1 -1
  16. package/dist/chunks/{chunk-2FLWXFVS.js → chunk-J7USS3ED.js} +4 -4
  17. package/dist/chunks/{chunk-IHUYP6LO.js → chunk-JSMFPO43.js} +1 -1
  18. package/dist/chunks/{chunk-RBGOMK4Y.js → chunk-KKRL3REV.js} +5 -4
  19. package/dist/chunks/{chunk-OCU4RLHC.js → chunk-NI6GIPIM.js} +195 -36
  20. package/dist/chunks/{chunk-PRHJGPMA.js → chunk-NR6RKXPA.js} +2 -2
  21. package/dist/chunks/{chunk-D223PTXU.js → chunk-OJQUJZQF.js} +33 -7
  22. package/dist/chunks/{chunk-ILMBNVSG.js → chunk-UJJD4QWF.js} +4 -3
  23. package/dist/chunks/{chunk-6ATGWRZM.js → chunk-UZZBA6PV.js} +177 -14
  24. package/dist/chunks/{chunk-GFPXQIY2.js → chunk-VRYHGG6O.js} +2 -2
  25. package/dist/chunks/{chunk-NHA62QD7.js → chunk-XJY7G4DD.js} +3 -3
  26. package/dist/chunks/{chunk-VBCFFFGT.js → chunk-Z32KWY6G.js} +4 -1
  27. package/dist/chunks/{conflict-SFNEVJY5.js → conflict-BQZEQ4SP.js} +2 -2
  28. package/dist/chunks/contract-XIRAFTEV.js +9111 -0
  29. package/dist/chunks/{cowork-CKWYHXYB.js → cowork-BLG62BL2.js} +46 -26
  30. package/dist/chunks/{ebuilder-form-KOLJRVZD.js → ebuilder-form-NUKG5QW4.js} +3 -3
  31. package/dist/chunks/{ehr-WFOC3B4D.js → ehr-2STW5ILH.js} +174 -10
  32. package/dist/chunks/{esb-LJZTN663.js → esb-UUDQUNKY.js} +4 -4
  33. package/dist/chunks/{fna-F7QRIIZC.js → fna-6RCY4NU5.js} +15 -9
  34. package/dist/chunks/{host-VQ6JJXGQ.js → host-7RXEDMAH.js} +3 -3
  35. package/dist/chunks/{host-KXPTEWFS.js → host-EJZFROU3.js} +3 -3
  36. package/dist/chunks/{host-BCGUVEWX.js → host-FWDOSRH5.js} +3 -3
  37. package/dist/chunks/{host-DGE2TZD4.js → host-RHM3NPXV.js} +3 -3
  38. package/dist/chunks/{host-BQBRHVR3.js → host-UFF33TWJ.js} +3 -3
  39. package/dist/chunks/{hrm-NI6XAKW5.js → hrm-PKJ6ELSH.js} +3 -3
  40. package/dist/chunks/{im-7TRTF3KT.js → im-YJAXS7CO.js} +3 -3
  41. package/dist/chunks/{invoice-AOXWJKYT.js → invoice-HWVSXGX6.js} +3 -3
  42. package/dist/chunks/{jiuchuanhui-7NQWEZAW.js → jiuchuanhui-L7VKILZB.js} +4 -3
  43. package/dist/chunks/{lazy-dispatch-RNS4EE4S.js → lazy-dispatch-NMYEIHRH.js} +4 -4
  44. package/dist/chunks/{mail-VDHJAB4O.js → mail-B42RRU7G.js} +46 -24
  45. package/dist/chunks/{meeting-GA7XCNNP.js → meeting-CFYVBJSS.js} +77 -12
  46. package/dist/chunks/{okr-TQIRERPQ.js → okr-GCLF6V7W.js} +4 -3
  47. package/dist/chunks/{plan-4RY4LN2P.js → plan-ZVL7GBRI.js} +4 -3
  48. package/dist/chunks/{project-D6XT2OC5.js → project-4YWAAE2K.js} +4 -3
  49. package/dist/chunks/{registry-QKMI43Q6.js → registry-EP4VTHZS.js} +8 -8
  50. package/dist/chunks/{registry-JHRIDQ3A.js → registry-FRJ6H7BT.js} +4 -4
  51. package/dist/chunks/{registry-VOGKFFTR.js → registry-SG2PGVCF.js} +2 -2
  52. package/dist/chunks/{room-recommend-D4EUOOWY.js → room-recommend-R3JVUUAC.js} +4 -4
  53. package/dist/chunks/{schedule-XPFBHPCV.js → schedule-NIJBTYDO.js} +4 -4
  54. package/dist/chunks/{workflow-HLBZRWIY.js → workflow-BB24DFBY.js} +11 -4
  55. package/dist/index.js +31 -26
  56. package/dist/internal/e10/auth-recovery.js +114 -1
  57. package/dist/internal/e10/client.js +16 -2
  58. package/dist/internal/e10/fetch-timing.js +31 -0
  59. package/dist/internal/e10/request-runtime.js +108 -7
  60. package/dist/shortcuts/archive/host.js +3 -2
  61. package/dist/shortcuts/archive-oa/host.js +2 -1
  62. package/dist/shortcuts/asset/host.js +6 -5
  63. package/dist/shortcuts/blog/host.js +3 -2
  64. package/dist/shortcuts/caizhilian/host.js +3 -2
  65. package/dist/shortcuts/calendar/host.js +2 -1
  66. package/dist/shortcuts/contract/host.js +2 -1
  67. package/dist/shortcuts/cowork/host.js +10 -1
  68. package/dist/shortcuts/cowork/operations/types.js +17 -2
  69. package/dist/shortcuts/ebuilder-form/host.js +3 -1
  70. package/dist/shortcuts/ehr/host.js +2 -1
  71. package/dist/shortcuts/ehr/operations/recruit-write.js +35 -0
  72. package/dist/shortcuts/ehr/operations/recruit.js +147 -0
  73. package/dist/shortcuts/esb/host.js +2 -1
  74. package/dist/shortcuts/fna/host.js +2 -1
  75. package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
  76. package/dist/shortcuts/hrm/host.js +2 -1
  77. package/dist/shortcuts/im/host.js +3 -2
  78. package/dist/shortcuts/index.js +5 -0
  79. package/dist/shortcuts/invoice/host.js +5 -4
  80. package/dist/shortcuts/jiuchuanhui/host.js +2 -1
  81. package/dist/shortcuts/mail/host.js +10 -1
  82. package/dist/shortcuts/mail/operations/types.js +17 -2
  83. package/dist/shortcuts/meeting/host.js +3 -2
  84. package/dist/shortcuts/meeting/index.js +79 -1
  85. package/dist/shortcuts/meeting/invitation/text.js +71 -0
  86. package/dist/shortcuts/meeting/manifest.js +10 -0
  87. package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
  88. package/dist/shortcuts/meeting/operations/eb/conflict.js +6 -1
  89. package/dist/shortcuts/meeting/operations/eb/create-flow.js +2105 -169
  90. package/dist/shortcuts/meeting/operations/eb/crm-search.js +478 -0
  91. package/dist/shortcuts/meeting/operations/eb/factory.js +161 -8
  92. package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
  93. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +36 -2
  94. package/dist/shortcuts/meeting/operations/eb-fallback.js +4 -0
  95. package/dist/shortcuts/meeting/operations/env.js +6 -0
  96. package/dist/shortcuts/meeting/operations/invitation.js +200 -28
  97. package/dist/shortcuts/okr/host.js +2 -1
  98. package/dist/shortcuts/plan/host.js +2 -1
  99. package/dist/shortcuts/project/host.js +2 -1
  100. package/dist/shortcuts/workflow/endpoints.js +8 -3
  101. package/dist/shortcuts/workflow/operations/form.js +341 -36
  102. package/dist/shortcuts/workflow/operations.js +23 -1
  103. package/docs/ehr.md +1 -1
  104. package/docs/fna.md +2 -1
  105. package/package.json +1 -1
  106. package/skill-template/business-info.json +18 -0
  107. package/skill-template/domains/cowork.md +14 -0
  108. package/skills/weaver-e10-cowork/SKILL.md +101 -0
  109. package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
  110. package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
  111. package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
  112. package/skills/weaver-e10-jucailin/SKILL.md +21 -3
  113. package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
  114. package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
  115. package/skills/weaver-e10-jucailin/references/salary.md +15 -11
  116. package/skills/weaver-e10-mail/SKILL.md +12 -9
  117. package/skills/weaver-e10-meeting/SKILL.md +499 -300
  118. package/skills/weaver-e10-meeting/references/meeting-eb.md +334 -0
  119. package/skills/weaver-e10-meeting/references/meeting-invitation.md +64 -6
  120. package/skills/weaver-e10-meeting.zip +0 -0
  121. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  122. package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
  123. package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
  124. package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
  125. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
  126. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
package/dist/index.js CHANGED
@@ -7,12 +7,12 @@ import {
7
7
  firstPositionalToken,
8
8
  registerCommands,
9
9
  toCommandMetadata
10
- } from "./chunks/chunk-GFPXQIY2.js";
10
+ } from "./chunks/chunk-VRYHGG6O.js";
11
11
  import "./chunks/chunk-EG6ZU444.js";
12
12
  import "./chunks/chunk-AJ62BGAW.js";
13
- import "./chunks/chunk-EEWPQE3O.js";
14
- import "./chunks/chunk-6ATGWRZM.js";
15
- import "./chunks/chunk-D223PTXU.js";
13
+ import "./chunks/chunk-FUWVHMVV.js";
14
+ import "./chunks/chunk-UZZBA6PV.js";
15
+ import "./chunks/chunk-OJQUJZQF.js";
16
16
  import "./chunks/chunk-LUSPKZKY.js";
17
17
  import "./chunks/chunk-BUSC6UAE.js";
18
18
 
@@ -29,7 +29,7 @@ function lazyShortcut(definition) {
29
29
  placeholder.allowExcessArguments(true);
30
30
  placeholder.helpOption(false);
31
31
  placeholder.action(async () => {
32
- const { dispatchLazyShortcut } = await import("./chunks/lazy-dispatch-RNS4EE4S.js");
32
+ const { dispatchLazyShortcut } = await import("./chunks/lazy-dispatch-NMYEIHRH.js");
33
33
  await dispatchLazyShortcut(definition, shortcutMetadata());
34
34
  });
35
35
  }
@@ -39,107 +39,112 @@ var builtinShortcuts = [
39
39
  lazyShortcut({
40
40
  name: "invoice",
41
41
  description: "E10 \u4E1A\u7968\u901A\u53D1\u7968\u7BA1\u7406 CLI",
42
- load: async () => (await import("./chunks/invoice-AOXWJKYT.js")).invoiceShortcut
42
+ load: async () => (await import("./chunks/invoice-HWVSXGX6.js")).invoiceShortcut
43
43
  }),
44
44
  lazyShortcut({
45
45
  name: "ehr",
46
46
  description: "\u6CDB\u5FAEE10\u805A\u624D\u6797\uFF08\u4EBA\u4E8B/\u51FA\u52E4/\u85AA\u916C\uFF09CLI",
47
- load: async () => (await import("./chunks/ehr-WFOC3B4D.js")).ehrShortcut
47
+ load: async () => (await import("./chunks/ehr-2STW5ILH.js")).ehrShortcut
48
48
  }),
49
49
  lazyShortcut({
50
50
  name: "cowork",
51
51
  description: "\u6CDB\u5FAEE10\u534F\u4F5C\u533A\uFF08\u534F\u4F5C\u4E8B\u9879/\u8BA8\u8BBA/\u5BA1\u6279/\u5171\u4EAB\u6743\u9650\uFF09CLI",
52
- load: async () => (await import("./chunks/cowork-CKWYHXYB.js")).coworkShortcut
52
+ load: async () => (await import("./chunks/cowork-BLG62BL2.js")).coworkShortcut
53
53
  }),
54
54
  lazyShortcut({
55
55
  name: "archive",
56
56
  description: "E10 \u6587\u4E66\u5B9A\u6863\u6848\u7BA1\u7406 CLI",
57
- load: async () => (await import("./chunks/archive-FVFY6GZN.js")).archiveShortcut
57
+ load: async () => (await import("./chunks/archive-PDV724YK.js")).archiveShortcut
58
58
  }),
59
59
  lazyShortcut({
60
60
  name: "archive-oa",
61
61
  description: "E10 \u6863\u6848\u5B9A\u4F4D\u4E0E OA \u5546\u52A1\u5408\u540C\u501F\u9605 CLI",
62
- load: async () => (await import("./chunks/archive-oa-NW3OD4UV.js")).archiveOaShortcut
62
+ load: async () => (await import("./chunks/archive-oa-4XE4MNXQ.js")).archiveOaShortcut
63
63
  }),
64
64
  lazyShortcut({
65
65
  name: "calendar",
66
66
  description: "\u6CDB\u5FAEE10\u65E5\u7A0B\u7BA1\u7406 CLI\uFF08\u521B\u5EFA/\u67E5\u8BE2/\u66F4\u65B0/\u5220\u9664/\u5B57\u5178\uFF09",
67
- load: async () => (await import("./chunks/calendar-7KXE4ED3.js")).calendarShortcut
67
+ load: async () => (await import("./chunks/calendar-FG4BAZHE.js")).calendarShortcut
68
68
  }),
69
69
  lazyShortcut({
70
70
  name: "fna",
71
71
  description: "\u6CDB\u5FAEE10\u9F50\u4E1A\u6210\u8D39\u63A7\u4E2D\u5FC3\uFF08\u9884\u7B97/\u8D39\u7528\u4E2D\u5FC3/\u501F\u6B3E\u7BA1\u7406/\u53D1\u7968\u6838\u9500\uFF09CLI",
72
- load: async () => (await import("./chunks/fna-F7QRIIZC.js")).fnaShortcut
72
+ load: async () => (await import("./chunks/fna-6RCY4NU5.js")).fnaShortcut
73
73
  }),
74
74
  lazyShortcut({
75
75
  name: "hrm",
76
76
  description: "\u6CDB\u5FAEE10\u7EC4\u7EC7\u7BA1\u7406\uFF08\u5458\u5DE5/\u7EC4\u7EC7/\u5C97\u4F4D\u67E5\u8BE2\uFF09CLI",
77
- load: async () => (await import("./chunks/hrm-NI6XAKW5.js")).hrmShortcut
77
+ load: async () => (await import("./chunks/hrm-PKJ6ELSH.js")).hrmShortcut
78
78
  }),
79
79
  lazyShortcut({
80
80
  name: "mail",
81
81
  description: "\u6CDB\u5FAEE10\u90AE\u4EF6\u7BA1\u7406 CLI",
82
- load: async () => (await import("./chunks/mail-VDHJAB4O.js")).mailShortcut
82
+ load: async () => (await import("./chunks/mail-B42RRU7G.js")).mailShortcut
83
83
  }),
84
84
  lazyShortcut({
85
85
  name: "meeting",
86
86
  description: "\u6CDB\u5FAEE10\u4F1A\u8BAE\u7BA1\u7406 CLI\uFF08\u6807\u51C6\u7248\uFF1A\u67E5\u8BE2/\u51B2\u7A81/\u9884\u7EA6/\u56DE\u6267/\u7B7E\u5230\uFF09",
87
- load: async () => (await import("./chunks/meeting-GA7XCNNP.js")).meetingShortcut
87
+ load: async () => (await import("./chunks/meeting-CFYVBJSS.js")).meetingShortcut
88
88
  }),
89
89
  lazyShortcut({
90
90
  name: "okr",
91
91
  description: "\u6CDB\u5FAEE10 OKR \u76EE\u6807\u7BA1\u7406 CLI\uFF08\u76EE\u6807\u67E5\u8BE2/\u65B0\u5EFA/\u7F16\u8F91\u3001\u5173\u952E\u6210\u679C\u3001\u76EE\u6807\u5BF9\u9F50\u3001\u8BC4\u8BBA\uFF09",
92
- load: async () => (await import("./chunks/okr-TQIRERPQ.js")).okrShortcut
92
+ load: async () => (await import("./chunks/okr-GCLF6V7W.js")).okrShortcut
93
93
  }),
94
94
  lazyShortcut({
95
95
  name: "plan",
96
96
  description: "\u6CDB\u5FAEE10\u8BA1\u5212\u62A5\u544A CLI\uFF08\u67E5\u8BE2/\u65B0\u5EFA/\u4FEE\u6539/\u53D1\u5E03/\u64A4\u56DE/\u63D0\u4EA4\u63D0\u9192/\u8BC4\u8BBA\uFF09",
97
- load: async () => (await import("./chunks/plan-4RY4LN2P.js")).planShortcut
97
+ load: async () => (await import("./chunks/plan-ZVL7GBRI.js")).planShortcut
98
98
  }),
99
99
  lazyShortcut({
100
100
  name: "esb",
101
101
  description: "\u6CDB\u5FAEE10 ESB \u4E2D\u5FC3\u81EA\u5B9A\u4E49\u89E6\u53D1\u52A8\u4F5C\u6D41 CLI",
102
- load: async () => (await import("./chunks/esb-LJZTN663.js")).esbShortcut
102
+ load: async () => (await import("./chunks/esb-UUDQUNKY.js")).esbShortcut
103
103
  }),
104
104
  lazyShortcut({
105
105
  name: "ebuilder-form",
106
106
  description: "\u6CDB\u5FAEE10 eBuilder \u8868\u5355\u83DC\u5355\u3001\u5217\u8868\u548C\u8868\u5355\u6570\u636E CLI",
107
- load: async () => (await import("./chunks/ebuilder-form-KOLJRVZD.js")).ebuilderFormShortcut
107
+ load: async () => (await import("./chunks/ebuilder-form-NUKG5QW4.js")).ebuilderFormShortcut
108
108
  }),
109
109
  lazyShortcut({
110
110
  name: "jiuchuanhui",
111
111
  description: "\u6CDB\u5FAEE10\u4E5D\u6C1A\u6C47\u8425\u9500\u7BA1\u7406 CLI\uFF08\u5BA2\u6237/\u8054\u7CFB\u4EBA/\u5546\u673A/\u7EBF\u7D22/\u8054\u7CFB\u8BA1\u5212/\u516C\u6D77\uFF09",
112
- load: async () => (await import("./chunks/jiuchuanhui-7NQWEZAW.js")).jiuchuanhuiShortcut
112
+ load: async () => (await import("./chunks/jiuchuanhui-L7VKILZB.js")).jiuchuanhuiShortcut
113
113
  }),
114
114
  lazyShortcut({
115
115
  name: "asset",
116
116
  description: "E10 \u8D44\u4EA7\u7BA1\u7406\uFF08\u8D44\u7BA1\u5BB6\uFF09CLI",
117
- load: async () => (await import("./chunks/asset-7QJKMIDV.js")).assetShortcut
117
+ load: async () => (await import("./chunks/asset-PDL2QE2N.js")).assetShortcut
118
118
  }),
119
119
  lazyShortcut({
120
120
  name: "im",
121
121
  description: "\u6CDB\u5FAEE10\u6613\u79D2\u529E\uFF08\u5373\u65F6\u901A\u8BAF\uFF09CLI",
122
- load: async () => (await import("./chunks/im-7TRTF3KT.js")).imShortcut
122
+ load: async () => (await import("./chunks/im-YJAXS7CO.js")).imShortcut
123
123
  }),
124
124
  lazyShortcut({
125
125
  name: "project",
126
126
  description: "\u6CDB\u5FAEE10\u4E8B\u4E95\u7136\u9879\u76EE\u7BA1\u7406 CLI\uFF08\u9879\u76EE/\u4EFB\u52A1\u67E5\u8BE2\u4E0E\u786E\u8BA4\u5199\u5165\uFF09",
127
- load: async () => (await import("./chunks/project-D6XT2OC5.js")).projectShortcut
127
+ load: async () => (await import("./chunks/project-4YWAAE2K.js")).projectShortcut
128
128
  }),
129
129
  lazyShortcut({
130
130
  name: "workflow",
131
131
  description: "\u6CDB\u5FAEE10\u6D41\u7A0B\u667A\u80FD\u52A9\u624B CLI\uFF08\u67E5\u8BE2/\u67E5\u770B/\u64CD\u4F5C/\u6279\u91CF/\u53D1\u8D77/\u4FEE\u6539\uFF09",
132
- load: async () => (await import("./chunks/workflow-HLBZRWIY.js")).workflowShortcut
132
+ load: async () => (await import("./chunks/workflow-BB24DFBY.js")).workflowShortcut
133
133
  }),
134
134
  lazyShortcut({
135
135
  name: "blog",
136
136
  description: "\u6CDB\u5FAEE10\u5DE5\u4F5C\u65E5\u62A5 CLI\uFF08\u67E5\u8BE2/\u53D1\u5E03/\u7F16\u8F91/\u8BC4\u8BBA/\u70B9\u8D5E/\u63D0\u9192/\u5BFC\u51FA\uFF09",
137
- load: async () => (await import("./chunks/blog-I7SDPNW4.js")).blogShortcut
137
+ load: async () => (await import("./chunks/blog-UYR3EUXW.js")).blogShortcut
138
138
  }),
139
139
  lazyShortcut({
140
140
  name: "caizhilian",
141
141
  description: "\u6CDB\u5FAEE10\u91C7\u77E5\u8FDE\uFF08\u6587\u6863\u4E2D\u5FC3\uFF09CLI",
142
- load: async () => (await import("./chunks/caizhilian-O37ZIQNY.js")).caizhilianShortcut
142
+ load: async () => (await import("./chunks/caizhilian-LG2X5NMF.js")).caizhilianShortcut
143
+ }),
144
+ lazyShortcut({
145
+ name: "contract",
146
+ description: "\u6CDB\u5FAEE10\u4ECA\u627F\u8FBE\u5408\u540C\u7BA1\u7406 CLI",
147
+ load: async () => (await import("./chunks/contract-XIRAFTEV.js")).contractShortcut
143
148
  })
144
149
  ];
145
150
  function shortcutMetadata() {
@@ -23,6 +23,116 @@ const AUTH_REQUIRED_MARKERS = [
23
23
  'not logged in',
24
24
  'not login',
25
25
  ];
26
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
27
+ /** Location 命中这些特征即为登录类跳转。 */
28
+ const LOGIN_REDIRECT_MARKERS = [
29
+ 'login',
30
+ 'passport',
31
+ 'sso',
32
+ 'oauth',
33
+ 'signin',
34
+ 'sign-in',
35
+ 'authorize',
36
+ 'authn',
37
+ 'atrust',
38
+ 'checkticket',
39
+ ];
40
+ /** Location 命中这些特征即为文件服务/对象存储交接。 */
41
+ const FILE_REDIRECT_MARKERS = [
42
+ 'fileservice',
43
+ '/file/download',
44
+ '/file/remotedownload',
45
+ '/remotedownload/',
46
+ '/api/file/',
47
+ '/download/',
48
+ 'aliyuncs.com',
49
+ 'myqcloud.com',
50
+ 'qiniucdn.com',
51
+ 'qbox.me',
52
+ 'jdcloud.com',
53
+ 'amazonaws.com',
54
+ 'blob.core.windows.net',
55
+ 'ctyunapi.cn',
56
+ 'hiclouds.com',
57
+ 'minio',
58
+ 's3.',
59
+ 'obs.',
60
+ 'ks3',
61
+ ];
62
+ /** 这些请求路径本身就是取文件:其 3xx 只要不是登录页,就是文件服务交接。 */
63
+ const FILE_REQUEST_PATH_MARKERS = [
64
+ '/api/file/',
65
+ '/file/download',
66
+ '/remotedownload/',
67
+ '/fileservice',
68
+ '/download',
69
+ ];
70
+ /** 跳转目标是前端页面骨架(如 wui/index.html#/main),不是文件直链。 */
71
+ const APP_SHELL_REDIRECT = /(?:\.html?(?:[?#]|$)|#\/|wui\/)/u;
72
+ export function isE10RedirectStatus(status) {
73
+ return REDIRECT_STATUSES.has(status);
74
+ }
75
+ /**
76
+ * 取跳转目标里「有语义」的部分:主机名 + 路径 + hash,**丢掉 query**。
77
+ * 对象存储的签名 query 是长随机串,拿去匹配关键词容易误伤(例如签名里恰好
78
+ * 出现 `sso`),所以只在主机与路径上判定。
79
+ */
80
+ function redirectTarget(location) {
81
+ const raw = location.trim().toLowerCase();
82
+ if (!raw)
83
+ return '';
84
+ try {
85
+ const url = new URL(raw, 'https://e10.invalid');
86
+ return `${url.hostname}${url.pathname}${url.hash}`.toLowerCase();
87
+ }
88
+ catch {
89
+ return raw.split('?')[0];
90
+ }
91
+ }
92
+ /**
93
+ * 识别 3xx 的真实语义。登录跳转优先判定,避免对象存储地址里的参数误伤;
94
+ * 若是下载类请求且目标不像登录页,则认为是文件服务交接(对象存储的签名地址
95
+ * 不一定带 `fileservice` 之类的特征,只能靠请求路径反推)。
96
+ */
97
+ export function classifyE10Redirect(response) {
98
+ if (!isE10RedirectStatus(response.status))
99
+ return 'other';
100
+ const target = redirectTarget(response.headers?.get('location') || '');
101
+ if (!target)
102
+ return 'other';
103
+ if (LOGIN_REDIRECT_MARKERS.some((marker) => target.includes(marker)))
104
+ return 'login';
105
+ if (FILE_REDIRECT_MARKERS.some((marker) => target.includes(marker)))
106
+ return 'file';
107
+ const requestPath = (response.requestPath || '').toLowerCase();
108
+ if (requestPath
109
+ && FILE_REQUEST_PATH_MARKERS.some((marker) => requestPath.includes(marker))
110
+ // 跳到前端页面骨架说明不是文件直链,继续按「无法判定」保守处理。
111
+ && !APP_SHELL_REDIRECT.test(target)) {
112
+ return 'file';
113
+ }
114
+ return 'other';
115
+ }
116
+ /** 3xx 指向文件服务:属于下载直传,登录态有效,不得触发重新登录。 */
117
+ export function isE10FileRedirect(response) {
118
+ return classifyE10Redirect(response) === 'file';
119
+ }
120
+ /** 3xx 指向登录页:登录态确实失效。 */
121
+ export function isE10LoginRedirect(response) {
122
+ return classifyE10Redirect(response) === 'login';
123
+ }
124
+ /**
125
+ * 业务层统一的「HTTP 层登录态失效」判定:401,或 3xx 且不是文件服务交接。
126
+ * 各 shortcut 用它替代原来的 `status === 401 || status === 302`,避免把下载
127
+ * 直传的 302 误报成登录失效。
128
+ */
129
+ export function isE10SessionExpiredResponse(response) {
130
+ if (response.status === 401)
131
+ return true;
132
+ if (isE10RedirectStatus(response.status))
133
+ return !isE10FileRedirect(response);
134
+ return false;
135
+ }
26
136
  const recoveryInFlight = new Map();
27
137
  function asRecord(value) {
28
138
  return value && typeof value === 'object' && !Array.isArray(value)
@@ -77,9 +187,12 @@ function responseText(response) {
77
187
  * Detect only explicit authentication rejection signals. A bare HTTP 403 is
78
188
  * deliberately excluded because E10 also uses it for ordinary permission
79
189
  * denials, which must never trigger a credential refresh.
190
+ *
191
+ * 3xx 只在「跳到登录页」或「无法判定」时才算认证失败:下载接口把文件交接给
192
+ * 文件服务时同样返回 302,那不是登录失效,重新登录既无用也会白白换一次票据。
80
193
  */
81
194
  export function isE10AuthenticationRequired(response) {
82
- if (response.status === 401 || response.status === 302)
195
+ if (isE10SessionExpiredResponse(response))
83
196
  return true;
84
197
  if (responseCodes(response.value).some((code) => AUTH_REQUIRED_CODES.has(code)))
85
198
  return true;
@@ -1,4 +1,4 @@
1
- import { isE10AuthenticationRequired, sameE10SessionIdentity, } from './auth-recovery.js';
1
+ import { isE10AuthenticationRequired, isE10LoginRedirect, isE10RedirectStatus, sameE10SessionIdentity, } from './auth-recovery.js';
2
2
  class E10AuthenticationContextChangedError extends Error {
3
3
  }
4
4
  export class E10ApiClient {
@@ -78,6 +78,7 @@ export class E10ApiClient {
78
78
  if (!authenticationRecoveryAttempted && isE10AuthenticationRequired({
79
79
  status: resp.status,
80
80
  headers: resp.headers,
81
+ requestPath: safePathname(url),
81
82
  text,
82
83
  value,
83
84
  })) {
@@ -94,7 +95,12 @@ export class E10ApiClient {
94
95
  }
95
96
  }
96
97
  // Preserve the legacy password-based refresh for non-XiaoE callers.
97
- if (resp.status === 302) {
98
+ // 只有真的跳到登录页才刷新;3xx 交给文件服务(下载直传)时登录态仍有效。
99
+ if (isE10LoginRedirect({
100
+ status: resp.status,
101
+ headers: resp.headers,
102
+ requestPath: safePathname(url),
103
+ }) || (isE10RedirectStatus(resp.status) && !resp.headers.get('location'))) {
98
104
  const ok = await this.auth.ensureValid();
99
105
  if (!ok)
100
106
  throw new Error('E10 session expired; please login again');
@@ -134,3 +140,11 @@ function refreshAuthenticationHeaders(init, session) {
134
140
  headers['user-agent'] = session.uaHeader();
135
141
  init.headers = headers;
136
142
  }
143
+ function safePathname(rawUrl) {
144
+ try {
145
+ return new URL(rawUrl).pathname;
146
+ }
147
+ catch {
148
+ return rawUrl.startsWith('/') ? rawUrl.split('?')[0] : '';
149
+ }
150
+ }
@@ -0,0 +1,31 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ const storage = new AsyncLocalStorage();
3
+ export function createFetchTimingSink() {
4
+ return { fetchMs: 0, fetchCount: 0, fetchStart: null, fetchEnd: null };
5
+ }
6
+ /** 在 `sink` 的上下文里执行 `fn`:期间发生的 fetch 都会记到它上面。 */
7
+ export function runWithFetchTiming(sink, fn) {
8
+ return storage.run(sink, fn);
9
+ }
10
+ /**
11
+ * fetch 前调一次,拿到的结束函数在 fetch 落定(成功或失败)时调一次。
12
+ * 返回 `null` 表示当前没有 sink(非计时路径)⇒ 调用方跳过全部计时动作。
13
+ */
14
+ export function startFetchTiming() {
15
+ const sink = storage.getStore();
16
+ if (!sink)
17
+ return null;
18
+ const startedAt = Date.now();
19
+ let finished = false;
20
+ return () => {
21
+ if (finished)
22
+ return;
23
+ finished = true;
24
+ const endedAt = Date.now();
25
+ sink.fetchMs += Math.max(0, endedAt - startedAt);
26
+ sink.fetchCount += 1;
27
+ // 重试会有多次 fetch:起点取最早、终点取最晚,中间的空档(如换票据)不计入 fetchCost。
28
+ sink.fetchStart = sink.fetchStart === null ? startedAt : Math.min(sink.fetchStart, startedAt);
29
+ sink.fetchEnd = sink.fetchEnd === null ? endedAt : Math.max(sink.fetchEnd, endedAt);
30
+ };
31
+ }
@@ -1,7 +1,10 @@
1
1
  import { CliError, ExitCode } from '../../core/errors.js';
2
- import { isE10AuthenticationRequired, recoverXiaoEAuthSession, sameE10SessionIdentity, } from './auth-recovery.js';
2
+ import { classifyE10Redirect, isE10AuthenticationRequired, recoverXiaoEAuthSession, sameE10SessionIdentity, } from './auth-recovery.js';
3
+ import { startFetchTiming } from './fetch-timing.js';
3
4
  const DEFAULT_TIMEOUT_MS = 30_000;
4
5
  const DEFAULT_BIG_INT_STRINGS = true;
6
+ /** 下载直传最多跟几跳:E10 -> 对象存储通常 1 跳,留一点余量但不允许成环。 */
7
+ const MAX_DOWNLOAD_REDIRECTS = 3;
5
8
  const RESERVED_HEADERS = [
6
9
  'authorization',
7
10
  'cookie',
@@ -62,16 +65,18 @@ export class E10RequestRuntime {
62
65
  }
63
66
  stripReservedHeaders(mutable.headers);
64
67
  const requestEteamsId = this.session.eteamsId;
65
- let parsed = await this.executeRequest(mutable, request.trustedHeaders);
68
+ let attempt = await this.executeRequest(mutable, request.trustedHeaders);
66
69
  if (!mutable.streamBody
67
- && isE10AuthenticationRequired(parsed)
70
+ // 已交接给文件服务的响应不是 E10 的接口回答,登录态不该由它判定。
71
+ && !attempt.fromFileRedirect
72
+ && isE10AuthenticationRequired(authenticationProbe(mutable, attempt.parsed))
68
73
  && await this.recoverExpiredSession(requestEteamsId)) {
69
74
  // Authentication rejection is a definitive pre-business failure. Retry
70
75
  // exactly once with the new session; never retry transport/partial errors.
71
- parsed = await this.executeRequest(mutable, request.trustedHeaders);
76
+ attempt = await this.executeRequest(mutable, request.trustedHeaders);
72
77
  }
73
- await this.runAfterResponse(mutable, this.sessionContext(), parsed);
74
- return parsed;
78
+ await this.runAfterResponse(mutable, this.sessionContext(), attempt.parsed);
79
+ return attempt.parsed;
75
80
  }
76
81
  catch (error) {
77
82
  await this.runOnError(mutable, this.sessionContext(), error);
@@ -83,7 +88,74 @@ export class E10RequestRuntime {
83
88
  const headers = this.composeHeaders(request, trustedHeaders);
84
89
  const init = this.buildFetchInit(request, headers);
85
90
  const response = await this.fetchWithTimeout(url, init, request.timeoutMs);
86
- return this.readResponse(response, request.responseType, request.bigIntStrings, request.maxResponseBytes, request.timeoutMs);
91
+ // 二进制下载:E10 常以 302 把文件交接给文件服务/对象存储。这里直接跟过去
92
+ // 取字节,既不会把「文件流」当成登录失效,也不会触发无谓的重新登录。
93
+ const followed = request.responseType === 'binary'
94
+ ? await this.followDownloadRedirect(response, request, url)
95
+ : { response, followed: false };
96
+ if (followed.followed && (followed.response.status === 401 || followed.response.status === 403)) {
97
+ // 这是文件服务对直链的回答(签名过期/无权限),与 E10 登录态无关:
98
+ // 报清楚,别让调用方误以为要重新登录。
99
+ throw new E10ApiError('network', 'download_file_service_denied', `文件服务拒绝下载(HTTP ${followed.response.status}),直链可能已过期,请重试下载`, {
100
+ retryable: true,
101
+ exitCode: ExitCode.NetworkError,
102
+ details: { status: followed.response.status },
103
+ });
104
+ }
105
+ return {
106
+ parsed: await this.readResponse(followed.response, request.responseType, request.bigIntStrings, request.maxResponseBytes, request.timeoutMs),
107
+ fromFileRedirect: followed.followed,
108
+ };
109
+ }
110
+ /**
111
+ * 跟随下载直传的 3xx。仅当跳转目标是文件服务(非登录页)时才跟随,最多
112
+ * `MAX_DOWNLOAD_REDIRECTS` 跳;登录类跳转原样返回,交给上层认证恢复处理。
113
+ * 凭证规则:同源才继续带 Cookie/eteamsid,跨域(对象存储)不带任何鉴权头。
114
+ */
115
+ async followDownloadRedirect(response, request, requestUrl) {
116
+ const baseOrigin = safeOrigin(this.session.getBaseUrl());
117
+ let current = response;
118
+ let currentUrl = requestUrl;
119
+ let followed = false;
120
+ for (let hop = 0; hop < MAX_DOWNLOAD_REDIRECTS; hop += 1) {
121
+ const kind = classifyE10Redirect({
122
+ status: current.status,
123
+ headers: current.headers,
124
+ requestPath: request.path,
125
+ });
126
+ if (kind !== 'file')
127
+ return { response: current, followed };
128
+ const location = current.headers.get('location');
129
+ if (!location)
130
+ return { response: current, followed };
131
+ let next;
132
+ try {
133
+ next = new URL(location, currentUrl);
134
+ }
135
+ catch {
136
+ return { response: current, followed };
137
+ }
138
+ if (!/^https?:$/u.test(next.protocol))
139
+ return { response: current, followed };
140
+ const sameOrigin = baseOrigin !== '' && safeOrigin(next.toString()) === baseOrigin;
141
+ current = await this.fetchWithTimeout(next, this.buildDownloadRedirectInit(sameOrigin), request.timeoutMs);
142
+ currentUrl = next;
143
+ followed = true;
144
+ }
145
+ return { response: current, followed };
146
+ }
147
+ buildDownloadRedirectInit(sameOrigin) {
148
+ const headers = {
149
+ Accept: 'application/octet-stream, */*',
150
+ 'User-Agent': this.session.uaHeader(),
151
+ };
152
+ if (sameOrigin) {
153
+ headers.Cookie = this.attachSessionTicket
154
+ ? this.session.cookieHeaderWithSessionTicket()
155
+ : this.session.cookieHeader();
156
+ headers.eteamsid = this.session.eteamsId;
157
+ }
158
+ return { method: 'GET', headers, redirect: 'manual' };
87
159
  }
88
160
  async recoverExpiredSession(requestEteamsId) {
89
161
  // Another concurrent request may already have refreshed the shared session
@@ -220,6 +292,9 @@ export class E10RequestRuntime {
220
292
  async fetchWithTimeout(url, init, timeoutMs) {
221
293
  const controller = new AbortController();
222
294
  const timer = setTimeout(() => controller.abort(), timeoutMs);
295
+ // 「纯 fetch」= 发出请求 → 收到响应头(`fetch` 落定那一刻,不含读响应体/解析)。没有计时上下文
296
+ // (`startFetchTiming()` 返回 `null`)时它什么都不做,非计时路径零开销。
297
+ const stopFetchTiming = startFetchTiming();
223
298
  try {
224
299
  return await this.fetchFn(url, { ...init, signal: controller.signal });
225
300
  }
@@ -238,6 +313,7 @@ export class E10RequestRuntime {
238
313
  }
239
314
  finally {
240
315
  clearTimeout(timer);
316
+ stopFetchTiming?.();
241
317
  }
242
318
  }
243
319
  async readResponse(response, responseType, bigIntStrings = DEFAULT_BIG_INT_STRINGS, maxResponseBytes, timeoutMs = DEFAULT_TIMEOUT_MS) {
@@ -271,6 +347,31 @@ export class E10RequestRuntime {
271
347
  export function parseJsonPreservingBigInts(text) {
272
348
  return JSON.parse(quoteLargeJsonIntegers(text));
273
349
  }
350
+ /**
351
+ * 组装认证探测入参。二进制响应不能把文件字节交给关键词扫描(乱码里出现
352
+ * 「login」会误判成登录失效),只保留状态码与跳转目标;同时带上请求路径,
353
+ * 让「下载接口 -> 文件服务」的 3xx 能被识别为交接而不是失效。
354
+ */
355
+ function authenticationProbe(request, response) {
356
+ if ('content' in response) {
357
+ return { status: response.status, headers: response.headers, requestPath: request.path };
358
+ }
359
+ return {
360
+ status: response.status,
361
+ headers: response.headers,
362
+ requestPath: request.path,
363
+ text: response.text,
364
+ value: response.value,
365
+ };
366
+ }
367
+ function safeOrigin(rawUrl) {
368
+ try {
369
+ return new URL(rawUrl).origin.toLowerCase();
370
+ }
371
+ catch {
372
+ return '';
373
+ }
374
+ }
274
375
  const LONG_INTEGER_MIN_DIGITS = 16;
275
376
  // 一趟扫描把 JSON 拆成「字符串字面量」与「数字」两类 token:字符串整体跳过,
276
377
  // 数字只在它是纯整数且位数够长时补引号。逐字符拼串在 MB 级响应上要 100 ms 以上,
@@ -2,6 +2,7 @@ import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js
2
2
  import { requireE10Session } from '../../internal/e10/context.js';
3
3
  import { getActiveProfile } from '../../internal/e10/auth/session.js';
4
4
  import { E10ApiError, createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
5
+ import { isE10SessionExpiredResponse } from '../../internal/e10/auth-recovery.js';
5
6
  import { ArchiveCliError, archiveAuthError, archiveNetworkError, archiveValidationError, } from './errors.js';
6
7
  function inferProfile(ctx) {
7
8
  const options = ctx.getGlobalOptions();
@@ -151,7 +152,7 @@ export function createArchiveHost(ctx, dependencies = {}) {
151
152
  }
152
153
  async function request(request) {
153
154
  const response = await doRequest(request, false).catch((error) => mapRuntimeNetworkError(error));
154
- if (response.status === 401 || response.status === 302) {
155
+ if (isE10SessionExpiredResponse(response)) {
155
156
  throw archiveAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
156
157
  }
157
158
  if (response.parseError) {
@@ -182,7 +183,7 @@ export function createArchiveHost(ctx, dependencies = {}) {
182
183
  }
183
184
  async function requestBinary(request) {
184
185
  const response = await doRequest(request, true).catch((error) => mapRuntimeNetworkError(error));
185
- if (response.status === 401 || response.status === 302) {
186
+ if (isE10SessionExpiredResponse(response)) {
186
187
  throw archiveAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
187
188
  }
188
189
  if (response.status < 200 || response.status >= 300) {
@@ -2,6 +2,7 @@ import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js
2
2
  import { requireE10Session } from '../../internal/e10/context.js';
3
3
  import { getActiveProfile } from '../../internal/e10/auth/session.js';
4
4
  import { E10ApiError, createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
5
+ import { isE10SessionExpiredResponse } from '../../internal/e10/auth-recovery.js';
5
6
  import { ArchiveOaCliError, archiveOaAuthError, archiveOaNetworkError, archiveOaValidationError, } from './errors.js';
6
7
  /** 本模块允许调用的路径前缀:ebuilder 业务接口与 OpenESB 开放服务。 */
7
8
  const ALLOWED_PATH_PREFIXES = ['/api/', '/openserver/'];
@@ -122,7 +123,7 @@ export function createArchiveOaHost(ctx, dependencies = {}) {
122
123
  headers: { 'X-Requested-With': 'XMLHttpRequest', ...extraHeaders },
123
124
  timeoutMs,
124
125
  }).catch((error) => mapRuntimeNetworkError(error));
125
- if (response.status === 401 || response.status === 302) {
126
+ if (isE10SessionExpiredResponse(response)) {
126
127
  throw archiveOaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
127
128
  }
128
129
  if (response.parseError) {
@@ -2,6 +2,7 @@ import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js
2
2
  import { requireE10Session } from '../../internal/e10/context.js';
3
3
  import { getActiveProfile } from '../../internal/e10/auth/session.js';
4
4
  import { createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
5
+ import { isE10SessionExpiredResponse } from '../../internal/e10/auth-recovery.js';
5
6
  import { ziguanjiaAuthError, ziguanjiaBusinessError, ziguanjiaNetworkError, ziguanjiaValidationError, } from './errors.js';
6
7
  const EBUILDER_PREFIX = process.env.WEAVER_EBUILDER_PREFIX || '/api/ebuilder';
7
8
  const ESB_TRIGGER_PATH = '/api/esb/server/event/triggerActionFlow';
@@ -176,7 +177,7 @@ export function createZiguanjiaHost(ctx) {
176
177
  query,
177
178
  bigIntStrings: true,
178
179
  });
179
- if (response.status === 401 || response.status === 302) {
180
+ if (isE10SessionExpiredResponse(response)) {
180
181
  throw ziguanjiaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
181
182
  }
182
183
  if (response.parseError) {
@@ -242,7 +243,7 @@ export function createZiguanjiaHost(ctx) {
242
243
  formData: fd,
243
244
  bigIntStrings: false,
244
245
  });
245
- if (response.status === 401 || response.status === 302) {
246
+ if (isE10SessionExpiredResponse(response)) {
246
247
  throw ziguanjiaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
247
248
  }
248
249
  if (response.parseError) {
@@ -315,7 +316,7 @@ export function createZiguanjiaHost(ctx) {
315
316
  },
316
317
  bigIntStrings: true,
317
318
  });
318
- if (response.status === 401 || response.status === 302) {
319
+ if (isE10SessionExpiredResponse(response)) {
319
320
  throw ziguanjiaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
320
321
  }
321
322
  if (response.parseError) {
@@ -363,7 +364,7 @@ export function createZiguanjiaHost(ctx) {
363
364
  body: fullBody,
364
365
  bigIntStrings: true,
365
366
  });
366
- if (response.status === 401 || response.status === 302) {
367
+ if (isE10SessionExpiredResponse(response)) {
367
368
  throw ziguanjiaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
368
369
  }
369
370
  if (response.parseError) {
@@ -393,7 +394,7 @@ export function createZiguanjiaHost(ctx) {
393
394
  body: payload,
394
395
  bigIntStrings: true,
395
396
  });
396
- if (response.status === 401 || response.status === 302) {
397
+ if (isE10SessionExpiredResponse(response)) {
397
398
  throw ziguanjiaAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
398
399
  }
399
400
  if (response.parseError) {
@@ -3,6 +3,7 @@ import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js
3
3
  import { requireE10Session } from '../../internal/e10/context.js';
4
4
  import { getActiveProfile } from '../../internal/e10/auth/session.js';
5
5
  import { createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
6
+ import { isE10SessionExpiredResponse } from '../../internal/e10/auth-recovery.js';
6
7
  import { BlogCliError, blogAuthError, blogNetworkError, blogValidationError, } from './errors.js';
7
8
  const MAX_EXPORT_BYTES = 50 * 1024 * 1024;
8
9
  /** E10 登录失效在业务响应体里的 code(实测 -2 既可能是数字也可能是字符串) */
@@ -91,7 +92,7 @@ export function createBlogHost(ctx, dependencies = {}) {
91
92
  body,
92
93
  timeoutMs,
93
94
  });
94
- if (response.status === 401 || response.status === 302) {
95
+ if (isE10SessionExpiredResponse(response)) {
95
96
  throw blogAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
96
97
  }
97
98
  if (response.parseError) {
@@ -134,7 +135,7 @@ export function createBlogHost(ctx, dependencies = {}) {
134
135
  timeoutMs,
135
136
  headers: { Accept: 'application/octet-stream, */*' },
136
137
  });
137
- if (response.status === 401 || response.status === 302) {
138
+ if (isE10SessionExpiredResponse(response)) {
138
139
  throw blogAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
139
140
  }
140
141
  const contentType = response.contentType;