share-pages 0.3.0 → 0.4.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.
Files changed (166) hide show
  1. package/README.md +33 -4
  2. package/dist/THIRD_PARTY_NOTICES.txt +5056 -0
  3. package/dist/dist-BQU5lE8l.mjs +50 -0
  4. package/dist/document-C_zFJaJh-DTCGPWet.mjs +1 -0
  5. package/dist/dom-CIOfuHTB-C4-fuyKb.mjs +1 -0
  6. package/dist/epub-BwUDPJ1r-BH6gGWIa.mjs +5 -0
  7. package/dist/escape-BojitKF1.mjs +1 -0
  8. package/dist/esm-2MLJKInY.mjs +19 -0
  9. package/dist/index.mjs +1 -1100
  10. package/dist/latex-DlhobE9G-CtYqyv9n.mjs +1 -0
  11. package/dist/latex-DlhobE9G-DwHHYo7c.mjs +243 -0
  12. package/dist/latex-lLjk9urP-B-Wr1Cpy.mjs +1 -0
  13. package/dist/lib-BuAs9S25.mjs +584 -0
  14. package/dist/markdown-CWaGsmVG-B3CzFhB7.mjs +2 -0
  15. package/dist/markdown-bundle-B49zJqHf-D1jB-1mu.mjs +9 -0
  16. package/dist/mdx-compile-BORJryFt-DZVpZfVh.mjs +147 -0
  17. package/dist/node-BpQDZA_b.mjs +1 -0
  18. package/dist/package-Dtp2swhT.mjs +21 -0
  19. package/dist/papaparse-4MP1mCUd.mjs +17 -0
  20. package/dist/prepare-4aSXVqKK-dkPhrUn5.mjs +1 -0
  21. package/dist/program-DJaWAEf5.mjs +17 -0
  22. package/dist/rolldown-runtime-Csi-cuKc.mjs +1 -0
  23. package/package.json +20 -11
  24. package/dist/dist-LkxVliJx.mjs +0 -5450
  25. package/dist/epub-BXQPqTFk-DV2p5uyW.mjs +0 -4915
  26. package/dist/latex-CybgCSnr-CvP5kdPz.mjs +0 -33421
  27. package/dist/latex-DMo_3IW8-DdNgxe_1.mjs +0 -20
  28. package/dist/markdown-BWlCFeLJ-CCxfGkZu.mjs +0 -68089
  29. package/dist/node-DVMkHtVp.mjs +0 -77
  30. package/dist/papaparse-BJnSo-VR.mjs +0 -1139
  31. package/dist/prepare-C56DezIS-pzIt9WD8.mjs +0 -8563
  32. package/dist/resources/assets/csv-worker-Bilq-sDm.js +0 -17
  33. package/dist/resources/chunks/viewer-Bz6Cwh4W.js +0 -9561
  34. package/dist/resources/csv.js +0 -2444
  35. package/dist/resources/epub.js +0 -16493
  36. package/dist/resources/fonts/KaTeX_AMS-Regular.ttf +0 -0
  37. package/dist/resources/fonts/KaTeX_AMS-Regular.woff +0 -0
  38. package/dist/resources/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  39. package/dist/resources/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  40. package/dist/resources/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  41. package/dist/resources/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  42. package/dist/resources/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  43. package/dist/resources/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  44. package/dist/resources/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  45. package/dist/resources/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  46. package/dist/resources/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  47. package/dist/resources/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  48. package/dist/resources/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  49. package/dist/resources/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  50. package/dist/resources/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  51. package/dist/resources/fonts/KaTeX_Main-Bold.ttf +0 -0
  52. package/dist/resources/fonts/KaTeX_Main-Bold.woff +0 -0
  53. package/dist/resources/fonts/KaTeX_Main-Bold.woff2 +0 -0
  54. package/dist/resources/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  55. package/dist/resources/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  56. package/dist/resources/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  57. package/dist/resources/fonts/KaTeX_Main-Italic.ttf +0 -0
  58. package/dist/resources/fonts/KaTeX_Main-Italic.woff +0 -0
  59. package/dist/resources/fonts/KaTeX_Main-Italic.woff2 +0 -0
  60. package/dist/resources/fonts/KaTeX_Main-Regular.ttf +0 -0
  61. package/dist/resources/fonts/KaTeX_Main-Regular.woff +0 -0
  62. package/dist/resources/fonts/KaTeX_Main-Regular.woff2 +0 -0
  63. package/dist/resources/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  64. package/dist/resources/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  65. package/dist/resources/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  66. package/dist/resources/fonts/KaTeX_Math-Italic.ttf +0 -0
  67. package/dist/resources/fonts/KaTeX_Math-Italic.woff +0 -0
  68. package/dist/resources/fonts/KaTeX_Math-Italic.woff2 +0 -0
  69. package/dist/resources/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  70. package/dist/resources/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  71. package/dist/resources/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  72. package/dist/resources/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  73. package/dist/resources/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  74. package/dist/resources/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  75. package/dist/resources/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  76. package/dist/resources/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  77. package/dist/resources/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  78. package/dist/resources/fonts/KaTeX_Script-Regular.ttf +0 -0
  79. package/dist/resources/fonts/KaTeX_Script-Regular.woff +0 -0
  80. package/dist/resources/fonts/KaTeX_Script-Regular.woff2 +0 -0
  81. package/dist/resources/fonts/KaTeX_Size1-Regular.ttf +0 -0
  82. package/dist/resources/fonts/KaTeX_Size1-Regular.woff +0 -0
  83. package/dist/resources/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  84. package/dist/resources/fonts/KaTeX_Size2-Regular.ttf +0 -0
  85. package/dist/resources/fonts/KaTeX_Size2-Regular.woff +0 -0
  86. package/dist/resources/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  87. package/dist/resources/fonts/KaTeX_Size3-Regular.ttf +0 -0
  88. package/dist/resources/fonts/KaTeX_Size3-Regular.woff +0 -0
  89. package/dist/resources/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  90. package/dist/resources/fonts/KaTeX_Size4-Regular.ttf +0 -0
  91. package/dist/resources/fonts/KaTeX_Size4-Regular.woff +0 -0
  92. package/dist/resources/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  93. package/dist/resources/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  94. package/dist/resources/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  95. package/dist/resources/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  96. package/dist/resources/katex.css +0 -1
  97. package/dist/resources/latex-article.css +0 -33
  98. package/dist/resources/latex-base.css +0 -816
  99. package/dist/resources/latex-book.css +0 -43
  100. package/dist/resources/latex-fonts/KaTeX_AMS-Regular.woff +0 -0
  101. package/dist/resources/latex-fonts/KaTeX_AMS-Regular.woff2 +0 -0
  102. package/dist/resources/latex-fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  103. package/dist/resources/latex-fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  104. package/dist/resources/latex-fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  105. package/dist/resources/latex-fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  106. package/dist/resources/latex-fonts/KaTeX_Fraktur-Bold.woff +0 -0
  107. package/dist/resources/latex-fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  108. package/dist/resources/latex-fonts/KaTeX_Fraktur-Regular.woff +0 -0
  109. package/dist/resources/latex-fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  110. package/dist/resources/latex-fonts/KaTeX_Main-Bold.woff +0 -0
  111. package/dist/resources/latex-fonts/KaTeX_Main-Bold.woff2 +0 -0
  112. package/dist/resources/latex-fonts/KaTeX_Main-BoldItalic.woff +0 -0
  113. package/dist/resources/latex-fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  114. package/dist/resources/latex-fonts/KaTeX_Main-Italic.woff +0 -0
  115. package/dist/resources/latex-fonts/KaTeX_Main-Italic.woff2 +0 -0
  116. package/dist/resources/latex-fonts/KaTeX_Main-Regular.woff +0 -0
  117. package/dist/resources/latex-fonts/KaTeX_Main-Regular.woff2 +0 -0
  118. package/dist/resources/latex-fonts/KaTeX_Math-BoldItalic.woff +0 -0
  119. package/dist/resources/latex-fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  120. package/dist/resources/latex-fonts/KaTeX_Math-Italic.woff +0 -0
  121. package/dist/resources/latex-fonts/KaTeX_Math-Italic.woff2 +0 -0
  122. package/dist/resources/latex-fonts/KaTeX_SansSerif-Bold.woff +0 -0
  123. package/dist/resources/latex-fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  124. package/dist/resources/latex-fonts/KaTeX_SansSerif-Italic.woff +0 -0
  125. package/dist/resources/latex-fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  126. package/dist/resources/latex-fonts/KaTeX_SansSerif-Regular.woff +0 -0
  127. package/dist/resources/latex-fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  128. package/dist/resources/latex-fonts/KaTeX_Script-Regular.woff +0 -0
  129. package/dist/resources/latex-fonts/KaTeX_Script-Regular.woff2 +0 -0
  130. package/dist/resources/latex-fonts/KaTeX_Size1-Regular.woff +0 -0
  131. package/dist/resources/latex-fonts/KaTeX_Size1-Regular.woff2 +0 -0
  132. package/dist/resources/latex-fonts/KaTeX_Size2-Regular.woff +0 -0
  133. package/dist/resources/latex-fonts/KaTeX_Size2-Regular.woff2 +0 -0
  134. package/dist/resources/latex-fonts/KaTeX_Size3-Regular.woff +0 -0
  135. package/dist/resources/latex-fonts/KaTeX_Size3-Regular.woff2 +0 -0
  136. package/dist/resources/latex-fonts/KaTeX_Size4-Regular.woff +0 -0
  137. package/dist/resources/latex-fonts/KaTeX_Size4-Regular.woff2 +0 -0
  138. package/dist/resources/latex-fonts/KaTeX_Typewriter-Regular.woff +0 -0
  139. package/dist/resources/latex-fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  140. package/dist/resources/latex-fonts/OFL.txt +0 -102
  141. package/dist/resources/latex-fonts/Sans/cmun-sans.css +0 -30
  142. package/dist/resources/latex-fonts/Sans/cmunsi.woff +0 -0
  143. package/dist/resources/latex-fonts/Sans/cmunso.woff +0 -0
  144. package/dist/resources/latex-fonts/Sans/cmunss.woff +0 -0
  145. package/dist/resources/latex-fonts/Sans/cmunsx.woff +0 -0
  146. package/dist/resources/latex-fonts/Serif/cmun-serif.css +0 -30
  147. package/dist/resources/latex-fonts/Serif/cmunbi.woff +0 -0
  148. package/dist/resources/latex-fonts/Serif/cmunbx.woff +0 -0
  149. package/dist/resources/latex-fonts/Serif/cmunrm.woff +0 -0
  150. package/dist/resources/latex-fonts/Serif/cmunti.woff +0 -0
  151. package/dist/resources/latex-fonts/Serif Slanted/cmun-serif-slanted.css +0 -14
  152. package/dist/resources/latex-fonts/Serif Slanted/cmunbl.woff +0 -0
  153. package/dist/resources/latex-fonts/Serif Slanted/cmunsl.woff +0 -0
  154. package/dist/resources/latex-fonts/Typewriter/cmun-typewriter.css +0 -30
  155. package/dist/resources/latex-fonts/Typewriter/cmunit.woff +0 -0
  156. package/dist/resources/latex-fonts/Typewriter/cmuntb.woff +0 -0
  157. package/dist/resources/latex-fonts/Typewriter/cmuntt.woff +0 -0
  158. package/dist/resources/latex-fonts/Typewriter/cmuntx.woff +0 -0
  159. package/dist/resources/latex-fonts/Typewriter Slanted/cmun-typewriter-slanted.css +0 -6
  160. package/dist/resources/latex-fonts/Typewriter Slanted/cmunst.woff +0 -0
  161. package/dist/resources/latex-fonts/cmu.css +0 -13
  162. package/dist/resources/latex-katex.css +0 -1079
  163. package/dist/resources/licenses.txt +0 -131
  164. package/dist/resources/reader.css +0 -244
  165. package/dist/resources/viewers.css +0 -3
  166. package/dist/rolldown-runtime-B4iAMlE-.mjs +0 -35
package/dist/index.mjs CHANGED
@@ -1,1101 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import { a as defaultLimits, c as formats, d as slugSchema, i as assert, n as CHUNK_SIZE, o as digest, r as accessSchema, t as AppError } from "./dist-LkxVliJx.mjs";
3
- import { Command, CommanderError, Help, Option } from "commander";
4
- import { randomUUID } from "node:crypto";
5
- import { chmod, mkdir, open, readFile, rename, unlink, writeFile } from "node:fs/promises";
6
- import { homedir } from "node:os";
7
- import { join } from "node:path";
8
- import { createInterface } from "node:readline/promises";
9
- import { StringDecoder } from "node:string_decoder";
10
- import { createWriteStream } from "node:fs";
11
- import { Readable } from "node:stream";
12
- import { pipeline } from "node:stream/promises";
13
- //#region src/terminal.ts
14
- const control = /[\x00-\x1f\x7f-\x9f]/g;
15
- function terminalText(value, multiline = false) {
16
- return String(value).replace(control, (character) => multiline && character === "\n" ? "\n" : " ");
17
- }
18
- //#endregion
19
- //#region src/errors.ts
20
- const hints = {
21
- LOGIN_REQUIRED: "先运行 share-pages login --server https://你的实例域名",
22
- SERVER_REQUIRED: "添加 --server https://你的实例域名,或为已有 profile 重新登录",
23
- INVALID_SERVER: "--server 只填写 origin,例如 https://pages.example.com",
24
- INSECURE_SERVER: "远程实例必须使用 HTTPS;只有 localhost 可以使用 HTTP",
25
- TOKEN_REQUIRED: "在后台创建发布 Token,然后重新登录",
26
- INVALID_PAGE_ID: "页面 ID 使用 3–40 位小写字母、数字或连字符,并避开系统保留名称",
27
- INVALID_PROFILE: "例如使用 default、production 或 team_docs",
28
- INVALID_UPLOAD_ID: "复制上传开始时 CLI 输出的完整会话 ID",
29
- INVALID_DATE: "例如使用 2026-09-10",
30
- INVALID_DATE_RANGE: "交换起止日期,确保 --from 不晚于 --to",
31
- INVALID_LIMIT: "将 --limit 设置为 1–100 的整数",
32
- INVALID_TIMEOUT: "将 --timeout 设置为 1–3600 的整数秒数",
33
- ID_REQUIRED: "添加 --id <已有页面 ID>,或去掉 --update 创建新页面",
34
- TYPE_REQUIRED: "stdin 没有文件名;添加 --type markdown、html、latex、epub、csv 或 zip",
35
- INVALID_INDEX_POLICY: "改用 --access public,或移除 --indexable",
36
- INPUT_REQUIRED: "自动化环境请使用 --token-stdin、--password-file 或对应环境变量",
37
- CONFIRMATION_REQUIRED: "确认目标无误后添加 --yes;永久删除无法恢复",
38
- ID_EXISTS: "若要为已有页面创建新版本,请保持相同 --id 并添加 --update",
39
- PAGE_NOT_FOUND: "运行 share-pages pages list 查找可用页面 ID",
40
- VERSION_NOT_FOUND: "运行 share-pages versions list <页面 ID> 查找版本 ID",
41
- RESUME_MISMATCH: "使用创建该会话时相同的文件和实例,或去掉 --resume 开始新上传",
42
- INVALID_RESUME_STATE: "去掉 --resume 开始新上传;损坏状态不会影响服务端已有内容",
43
- NETWORK_ERROR: "检查网络和实例地址后重试;已有上传会话可用 --resume 继续",
44
- REQUEST_TIMEOUT: "可增大 --timeout,或用 --no-wait 后运行 share-pages uploads <上传 ID>",
45
- OUTPUT_EXISTS: "换一个 --output 路径;CLI 不会覆盖已有文件",
46
- INPUT_NOT_FOUND: "检查输入路径、--password-file 或 --resume 的值是否正确",
47
- PERMISSION_DENIED: "检查文件权限以及当前目录是否可读写",
48
- CONFIG_ERROR: "修复或移走配置文件后重新登录;默认位置为 ~/.config/share-pages/config.json",
49
- INSECURE_SECRET_FILE: "秘密文件只能由当前用户读写,建议设置为 chmod 600",
50
- INVALID_PASSWORD: "换用 8–256 位页面密码后重试",
51
- PASSWORD_ACCESS_CONFLICT: "使用 --access password,或移除 --password-file",
52
- EMPTY_PATCH: "运行 share-pages pages edit --help 查看可修改字段",
53
- OUTPUT_CONFLICT: "只选择一种 stdout 输出格式后重试"
54
- };
55
- function systemError(error) {
56
- const path = error.path ? `:${error.path}` : "";
57
- if (error.code === "EEXIST") return new AppError("OUTPUT_EXISTS", `目标文件已存在${path}`);
58
- if (error.code === "ENOENT") return new AppError("INPUT_NOT_FOUND", `找不到文件或目录${path}`);
59
- if (error.code === "EACCES" || error.code === "EPERM") return new AppError("PERMISSION_DENIED", `没有文件访问权限${path}`, 403);
60
- }
61
- function isHelpExit(error) {
62
- return error instanceof CommanderError && (error.exitCode === 0 || ["commander.help", "commander.helpDisplayed"].includes(error.code));
63
- }
64
- function normalizeError(error) {
65
- if (error instanceof CommanderError) return {
66
- code: "CLI_USAGE",
67
- message: error.message.replace(/^error:\s*/i, "").trim().replace(/^unknown command /i, "未知命令 ").replace(/^unknown option /i, "未知选项 ").replace(/^missing required argument /i, "缺少必填参数 ").replace(/^too many arguments\./i, "参数过多。").replace(/\(Did you mean (.+)\?\)/i, "你可能想输入 $1。"),
68
- status: 400,
69
- hint: "运行 share-pages --help,或 share-pages <命令> --help 查看示例"
70
- };
71
- const resolved = (error instanceof AppError ? error : systemError(error)) ?? new AppError("CLI_ERROR", error instanceof Error ? error.message : "命令执行失败;请重试或使用 --help 检查参数");
72
- return {
73
- code: resolved.code,
74
- message: resolved.message,
75
- status: resolved.status,
76
- fields: resolved.fields,
77
- requestId: resolved.requestId,
78
- hint: hints[resolved.code]
79
- };
80
- }
81
- function exitCode(error) {
82
- if (error.status === 401 || error.status === 403) return 3;
83
- if (error.status === 409) return 4;
84
- if (error.status >= 500) return 5;
85
- return 2;
86
- }
87
- function printError(error, json) {
88
- if (json) {
89
- const { status: _, ...result } = error;
90
- process.stdout.write(`${JSON.stringify({ error: result })}\n`);
91
- return;
92
- }
93
- process.stderr.write(`错误 [${terminalText(error.code)}]: ${terminalText(error.message, true)}\n`);
94
- if (error.requestId) process.stderr.write(`请求 ID: ${terminalText(error.requestId)}\n`);
95
- if (error.hint) process.stderr.write(`下一步: ${terminalText(error.hint)}\n`);
96
- }
97
- function wantsJSON(arguments_) {
98
- const separator = arguments_.indexOf("--");
99
- const options = separator === -1 ? arguments_ : arguments_.slice(0, separator);
100
- return options.includes("--json") || options.includes("-j");
101
- }
102
- //#endregion
103
- //#region ../../packages/sdk/dist/index.js
104
- function checkAbort(signal) {
105
- if (signal?.aborted) throw new AppError("ABORTED", "操作已取消,上传会话仍可恢复", 499);
106
- }
107
- function abortScope(parent, timeoutMs) {
108
- const controller = new AbortController();
109
- const abort = () => controller.abort(parent?.reason);
110
- if (parent?.aborted) abort();
111
- else parent?.addEventListener("abort", abort, { once: true });
112
- const timer = timeoutMs === void 0 ? void 0 : setTimeout(() => controller.abort(), timeoutMs);
113
- return {
114
- controller,
115
- signal: controller.signal,
116
- dispose() {
117
- if (timer !== void 0) clearTimeout(timer);
118
- parent?.removeEventListener("abort", abort);
119
- }
120
- };
121
- }
122
- function delay(ms, signal) {
123
- checkAbort(signal);
124
- return new Promise((resolve, reject) => {
125
- const finish = () => {
126
- signal?.removeEventListener("abort", cancel);
127
- resolve();
128
- };
129
- const timer = setTimeout(finish, ms);
130
- const cancel = () => {
131
- clearTimeout(timer);
132
- signal?.removeEventListener("abort", cancel);
133
- reject(new AppError("ABORTED", "操作已取消,上传会话仍可恢复", 499));
134
- };
135
- signal?.addEventListener("abort", cancel, { once: true });
136
- });
137
- }
138
- function result(session) {
139
- assert(session.result, "INVALID_RESPONSE", "已提交会话缺少发布结果", 502);
140
- return session.result;
141
- }
142
- async function waitForUpload(client, id, timeoutMs = 12e4, signal) {
143
- assert(Number.isFinite(timeoutMs) && timeoutMs >= 0, "INVALID_TIMEOUT", "等待时间必须为非负有限数");
144
- const end = Date.now() + timeoutMs;
145
- while (true) {
146
- checkAbort(signal);
147
- const status = await client.request(`/uploads/${encodeURIComponent(id)}`, { signal }, true);
148
- if (status.status === "committed") return result(status);
149
- if ([
150
- "failed",
151
- "cancelled",
152
- "expired"
153
- ].includes(status.status)) throw new AppError(status.error?.code ?? "PUBLISH_FAILED", status.error?.message ?? `发布 ${status.status}`, 409);
154
- if (Date.now() >= end) return status;
155
- await delay(Math.min(500, Math.max(0, end - Date.now())), signal);
156
- }
157
- }
158
- async function publish(client, prepared, options = {}) {
159
- const { idempotencyKey = crypto.randomUUID(), uploadId, wait = true, timeoutMs = 12e4, signal, uploadConcurrency = 3, onProgress, onSession, ...input } = options;
160
- assert(Number.isFinite(timeoutMs) && timeoutMs >= 0, "INVALID_TIMEOUT", "等待时间必须为非负有限数");
161
- assert(Number.isInteger(uploadConcurrency) && uploadConcurrency >= 1 && uploadConcurrency <= 4, "INVALID_CONCURRENCY", "上传并发数必须为 1–4");
162
- checkAbort(signal);
163
- let session = uploadId ? await client.request(`/uploads/${encodeURIComponent(uploadId)}`, { signal }, true) : await client.json("/uploads", "POST", {
164
- ...input,
165
- title: options.title ?? prepared.title,
166
- manifest: prepared.manifest
167
- }, { "Idempotency-Key": idempotencyKey }, true, signal);
168
- assert(session.manifestDigest === await digest(JSON.stringify(prepared.manifest)), "RESUME_MISMATCH", "上传会话与本地内容清单不同");
169
- await onSession?.(session);
170
- if (session.status === "committed") return result(session);
171
- if (session.status === "uploading") {
172
- const files = new Map(prepared.manifest.files.map((file) => [file.id, file]));
173
- const tasks = [];
174
- const total = prepared.manifest.files.reduce((sum, file) => sum + file.size, 0);
175
- let completed = total;
176
- for (const missing of session.missing) {
177
- const file = files.get(missing.fileId);
178
- const data = prepared.files.get(missing.fileId);
179
- assert(file && data, "RESUME_MISMATCH", "断点会话与本地文件不同");
180
- assert(data.byteLength === file.size, "RESUME_MISMATCH", "本地文件大小与清单不同");
181
- assert(new Set(missing.parts).size === missing.parts.length, "INVALID_RESPONSE", "服务端返回重复分片", 502);
182
- for (const part of missing.parts) {
183
- assert(Number.isInteger(part) && part >= 0 && (part === 0 || part * 8388608 < file.size), "INVALID_RESPONSE", "服务端分片编号无效", 502);
184
- const bytes = data.subarray(part * CHUNK_SIZE, (part + 1) * CHUNK_SIZE);
185
- completed -= bytes.byteLength;
186
- tasks.push({
187
- fileId: missing.fileId,
188
- part,
189
- bytes
190
- });
191
- }
192
- }
193
- onProgress?.(completed, total);
194
- const scope = abortScope(signal);
195
- let next = 0;
196
- let failure;
197
- try {
198
- await Promise.all(Array.from({ length: Math.min(uploadConcurrency, tasks.length) }, async () => {
199
- try {
200
- while (next < tasks.length) {
201
- checkAbort(scope.signal);
202
- const task = tasks[next++];
203
- if (!task) break;
204
- await client.request(`/uploads/${session.id}/files/${task.fileId}?part=${task.part}`, {
205
- method: "PUT",
206
- headers: { "X-Chunk-SHA256": await digest(task.bytes) },
207
- body: task.bytes,
208
- signal: scope.signal
209
- }, true);
210
- completed += task.bytes.byteLength;
211
- onProgress?.(completed, total);
212
- }
213
- } catch (error) {
214
- failure ??= error;
215
- scope.controller.abort();
216
- }
217
- }));
218
- if (failure) throw failure;
219
- } finally {
220
- scope.dispose();
221
- }
222
- session = await client.json(`/uploads/${session.id}/complete`, "POST", {}, {}, true, signal);
223
- }
224
- return wait ? waitForUpload(client, session.id, timeoutMs, signal) : session;
225
- }
226
- var HTTPClient = class {
227
- server;
228
- transport;
229
- token;
230
- timeout;
231
- constructor(options) {
232
- this.server = options.server.replace(/\/$/, "");
233
- let url;
234
- try {
235
- url = new URL(this.server);
236
- } catch {
237
- throw new AppError("INVALID_SERVER", "实例地址需要是 HTTP(S) origin");
238
- }
239
- if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname !== "/" || url.search || url.hash) throw new AppError("INVALID_SERVER", "实例地址需要是 HTTP(S) origin");
240
- if (url.protocol !== "https:" && ![
241
- "localhost",
242
- "127.0.0.1",
243
- "[::1]"
244
- ].includes(url.hostname)) throw new AppError("INSECURE_SERVER", "远端实例必须使用 HTTPS");
245
- this.timeout = options.requestTimeoutMs ?? 3e4;
246
- if (!Number.isFinite(this.timeout) || this.timeout <= 0) throw new AppError("INVALID_TIMEOUT", "请求超时必须是有限正数");
247
- this.token = options.token;
248
- this.transport = options.fetch ?? globalThis.fetch.bind(globalThis);
249
- }
250
- async request(path, init = {}, retry = false) {
251
- const headers = new Headers(init.headers);
252
- if (this.token) headers.set("Authorization", `Bearer ${this.token}`);
253
- for (let attempt = 0;; attempt++) {
254
- checkAbort(init.signal);
255
- const scope = abortScope(init.signal, this.timeout);
256
- let retryAfter = 250 * 2 ** attempt;
257
- try {
258
- const response = await this.transport(`${this.server}/api/v1${path}`, {
259
- ...init,
260
- headers,
261
- credentials: "include",
262
- signal: init.signal ? AbortSignal.any([scope.signal, init.signal]) : scope.signal
263
- });
264
- if (retry && [
265
- 429,
266
- 502,
267
- 503,
268
- 504
269
- ].includes(response.status) && attempt < 3) {
270
- const value = response.headers.get("Retry-After");
271
- if (value) retryAfter = Math.min(5e3, Math.max(0, /^\d+$/.test(value) ? Number(value) * 1e3 : Date.parse(value) - Date.now()) || retryAfter);
272
- await response.body?.cancel();
273
- } else {
274
- if (!response.ok) {
275
- let error = {};
276
- try {
277
- const value = await response.json();
278
- if (value && typeof value === "object") error = value;
279
- } catch {}
280
- throw new AppError(typeof error.code === "string" ? error.code : "HTTP_ERROR", typeof error.message === "string" ? error.message : `请求失败 (${response.status})`, response.status, error.fields, error.requestId ?? response.headers.get("X-Request-Id") ?? void 0);
281
- }
282
- if (response.headers.get("Content-Type")?.includes("application/json")) try {
283
- return await response.json();
284
- } catch {
285
- throw new AppError("INVALID_RESPONSE", "服务端返回了无效 JSON", 502);
286
- }
287
- return response;
288
- }
289
- } catch (error) {
290
- checkAbort(init.signal);
291
- if (error instanceof AppError) throw error;
292
- if (!retry || attempt >= 3) throw new AppError(scope.signal.aborted ? "REQUEST_TIMEOUT" : "NETWORK_ERROR", "网络请求失败,可使用相同上传会话继续", 503);
293
- } finally {
294
- scope.dispose();
295
- }
296
- await delay(retryAfter, init.signal);
297
- }
298
- }
299
- json(path, method, body, headers = {}, retry = false, signal) {
300
- return this.request(path, {
301
- method,
302
- headers: {
303
- "Content-Type": "application/json",
304
- ...headers
305
- },
306
- body: JSON.stringify(body),
307
- signal
308
- }, retry);
309
- }
310
- };
311
- var SharePagesClient = class extends HTTPClient {
312
- publish(prepared, options = {}) {
313
- return publish(this, prepared, options);
314
- }
315
- waitForUpload(id, timeoutMs = 12e4, signal) {
316
- return waitForUpload(this, id, timeoutMs, signal);
317
- }
318
- capabilities() {
319
- return this.request("/capabilities", {}, true);
320
- }
321
- listPages(params = {}) {
322
- return this.request(`/pages?${new URLSearchParams(params)}`);
323
- }
324
- getPage(id) {
325
- return this.request(`/pages/${encodeURIComponent(id)}`);
326
- }
327
- listVersions(id, cursor) {
328
- return this.request(`/pages/${encodeURIComponent(id)}/versions` + (cursor ? `?cursor=${encodeURIComponent(cursor)}` : ""));
329
- }
330
- patchPage(id, patch) {
331
- return this.json(`/pages/${encodeURIComponent(id)}`, "PATCH", patch);
332
- }
333
- async rollback(id, versionId, options = {}) {
334
- const s = await this.json(`/pages/${encodeURIComponent(id)}/rollback`, "POST", { versionId }, { "Idempotency-Key": options.idempotencyKey ?? crypto.randomUUID() }, true);
335
- return options.wait === false ? s : this.waitForUpload(s.id, options.timeoutMs);
336
- }
337
- deletePage(id, purge = false) {
338
- return this.request(`/pages/${encodeURIComponent(id)}?purge=${purge}`, { method: "DELETE" });
339
- }
340
- restorePage(id, replaceWith) {
341
- return this.json(`/pages/${encodeURIComponent(id)}/restore`, "POST", { replaceWith });
342
- }
343
- deleteVersion(id, version, options = {}) {
344
- const params = new URLSearchParams(Object.entries(options).filter(([, v]) => v !== void 0).map(([k, v]) => [k, String(v)]));
345
- return this.request(`/pages/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}?${params}`, { method: "DELETE" });
346
- }
347
- restoreVersion(id, version) {
348
- return this.json(`/pages/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}/restore`, "POST", {});
349
- }
350
- download(id, version) {
351
- return this.request(`/pages/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}/download`);
352
- }
353
- stats(params = {}) {
354
- return this.request(`/stats?${new URLSearchParams(params)}`);
355
- }
356
- };
357
- //#endregion
358
- //#region src/config.ts
359
- const configDir = process.env.SHARE_PAGES_CONFIG_DIR ?? join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "share-pages");
360
- const configPath = join(configDir, "config.json");
361
- async function readConfig() {
362
- try {
363
- const value = JSON.parse(await readFile(configPath, "utf8"));
364
- if (!validConfig(value)) throw new Error("Invalid configuration");
365
- return value;
366
- } catch (e) {
367
- if (e.code === "ENOENT") return {
368
- active: "default",
369
- profiles: {}
370
- };
371
- throw new AppError("CONFIG_ERROR", "配置文件读取失败");
372
- }
373
- }
374
- function validConfig(value) {
375
- if (!value || typeof value !== "object" || !("active" in value) || !("profiles" in value)) return false;
376
- if (typeof value.active !== "string" || !value.profiles || typeof value.profiles !== "object" || Array.isArray(value.profiles)) return false;
377
- return Object.values(value.profiles).every((profile) => profile && typeof profile === "object" && typeof profile.server === "string" && typeof profile.token === "string");
378
- }
379
- async function savePrivate(path, data) {
380
- await mkdir(configDir, {
381
- recursive: true,
382
- mode: 448
383
- });
384
- const temp = `${path}.${randomUUID()}.tmp`;
385
- try {
386
- await writeFile(temp, `${JSON.stringify(data, null, 2)}\n`, {
387
- mode: 384,
388
- flag: "wx"
389
- });
390
- await rename(temp, path);
391
- await chmod(path, 384);
392
- } finally {
393
- await unlink(temp).catch((error) => {
394
- if (error.code !== "ENOENT") throw error;
395
- });
396
- }
397
- }
398
- async function writeConfig(config) {
399
- await savePrivate(configPath, config);
400
- }
401
- async function profile(name, server) {
402
- const config = await readConfig(), key = name ?? config.active, p = Object.hasOwn(config.profiles, key) ? config.profiles[key] : void 0;
403
- const value = {
404
- server: server ?? process.env.SHARE_PAGES_SERVER ?? p?.server,
405
- token: process.env.SHARE_PAGES_TOKEN ?? p?.token
406
- };
407
- if (!value.server || !value.token) throw new AppError("LOGIN_REQUIRED", "请先登录,或设置 SHARE_PAGES_SERVER 和 SHARE_PAGES_TOKEN", 401);
408
- return value;
409
- }
410
- function resumePath(id) {
411
- if (!/^[a-z0-9-]+$/i.test(id)) throw new AppError("INVALID_UPLOAD_ID", "非法上传 ID");
412
- return join(configDir, `upload-${id}.json`);
413
- }
414
- async function removeResume(id) {
415
- await unlink(resumePath(id)).catch((error) => {
416
- if (error.code !== "ENOENT") throw error;
417
- });
418
- }
419
- //#endregion
420
- //#region src/help.ts
421
- const headings = /* @__PURE__ */ new Map([
422
- ["Usage:", "用法:"],
423
- ["Arguments:", "参数:"],
424
- ["Options:", "选项:"],
425
- ["Commands:", "命令:"],
426
- ["Global Options:", "全局选项:"]
427
- ]);
428
- function configureHelp(command) {
429
- command.helpOption("-h, --help", "显示命令帮助").helpCommand("help [command]", "显示指定命令的帮助").showSuggestionAfterError().showHelpAfterError(false).configureOutput({ writeErr: (value) => {
430
- if (/^(用法|Usage):|^\n(?:示例|说明):/.test(value)) process.stdout.write(value);
431
- } }).configureHelp({
432
- helpWidth: Math.min(process.stdout.columns || 100, 120),
433
- formatHelp(current, helper) {
434
- return Help.prototype.formatHelp.call(helper, current, helper).replace(/^(Usage:|Arguments:|Options:|Commands:|Global Options:)/gm, (title) => headings.get(title) ?? title).replace(/\(choices: ([^)]+)\)/g, "(可选值: $1)").replace(/\(default: ([^)]+)\)/g, "(默认: $1)");
435
- }
436
- });
437
- }
438
- function examples(command, lines, notes = []) {
439
- command.addHelpText("after", `\n示例:\n${lines.map((line) => ` ${line}`).join("\n")}${notes.length ? `\n\n说明:\n${notes.map((line) => ` ${line}`).join("\n")}` : ""}\n`);
440
- return command;
441
- }
442
- //#endregion
443
- //#region src/input.ts
444
- async function stdinBytes(limit = 100 * 1024 ** 2) {
445
- const chunks = [];
446
- let length = 0;
447
- for await (const chunk of process.stdin) {
448
- const b = Buffer.from(chunk);
449
- length += b.length;
450
- if (length > limit) throw new AppError("INPUT_TOO_LARGE", "stdin 内容超限", 413);
451
- chunks.push(b);
452
- }
453
- return new Uint8Array(Buffer.concat(chunks));
454
- }
455
- async function secret(prompt, interactive = true) {
456
- if (!interactive || !process.stdin.isTTY) throw new AppError("INPUT_REQUIRED", "非交互模式需要通过 stdin 文件或环境变量提供秘密");
457
- process.stderr.write(prompt);
458
- process.stdin.setRawMode(true);
459
- process.stdin.resume();
460
- return new Promise((resolve, reject) => {
461
- let value = "";
462
- const decoder = new StringDecoder("utf8");
463
- const onData = (data) => {
464
- for (const c of decoder.write(data)) {
465
- if (c === "\r" || c === "\n") {
466
- cleanup();
467
- resolve(value);
468
- return;
469
- }
470
- if (c === "" || c === "") {
471
- cleanup();
472
- reject(new AppError("CANCELLED", "操作取消"));
473
- return;
474
- }
475
- if (c === "\b" || c === "") value = value.slice(0, -1);
476
- else if (c >= " ") value += c;
477
- }
478
- };
479
- const onEnd = () => {
480
- cleanup();
481
- reject(new AppError("CANCELLED", "输入已结束,操作取消"));
482
- };
483
- const onError = (error) => {
484
- cleanup();
485
- reject(error);
486
- };
487
- function cleanup() {
488
- process.stdin.off("data", onData);
489
- process.stdin.off("end", onEnd);
490
- process.stdin.off("error", onError);
491
- process.stdin.setRawMode(false);
492
- process.stdin.pause();
493
- process.stderr.write("\n");
494
- }
495
- process.stdin.on("data", onData);
496
- process.stdin.once("end", onEnd);
497
- process.stdin.once("error", onError);
498
- });
499
- }
500
- async function secretFile(path, label = "秘密文件") {
501
- const file = await open(path, "r");
502
- try {
503
- const metadata = await file.stat();
504
- if (!metadata.isFile()) throw new AppError("INVALID_SECRET_FILE", `${label}必须是普通文件`);
505
- if (process.platform !== "win32" && (metadata.mode & 63) !== 0) throw new AppError("INSECURE_SECRET_FILE", `${label}权限过宽;请先运行 chmod 600 ${JSON.stringify(path)}`);
506
- const value = (await file.readFile("utf8")).trimEnd();
507
- if (!value) throw new AppError("EMPTY_SECRET_FILE", `${label}不能为空`);
508
- return value;
509
- } finally {
510
- await file.close();
511
- }
512
- }
513
- async function confirm(message, yes, interactive) {
514
- if (yes) return;
515
- if (!interactive || !process.stdin.isTTY) throw new AppError("CONFIRMATION_REQUIRED", "自动化删除需要显式 --yes");
516
- const rl = createInterface({
517
- input: process.stdin,
518
- output: process.stderr
519
- });
520
- try {
521
- if (await rl.question(`${message} 输入 yes 继续:`) !== "yes") throw new AppError("CANCELLED", "操作取消");
522
- } finally {
523
- rl.close();
524
- }
525
- }
526
- //#endregion
527
- //#region package.json
528
- var version = "0.3.0";
529
- //#endregion
530
- //#region src/shared.ts
531
- function createCommand() {
532
- return new Command().name("share-pages").description("将 HTML、站点目录和文档发布到你自己的 Share Pages 实例").version(version, "-V, --version", "显示 CLI 版本").addOption(new Option("-j, --json", "以单行 JSON 输出结果和错误(适合脚本)")).addOption(new Option("-q, --quiet", "隐藏进度和操作提示")).addOption(new Option("--no-interactive", "禁止密码和删除确认等交互输入")).addOption(new Option("-p, --profile <name>", "使用指定的实例配置")).addOption(new Option("--server <url>", "临时覆盖实例地址")).exitOverride();
533
- }
534
- function options(command) {
535
- const chain = [];
536
- for (let current = command; current; current = current.parent) chain.unshift(current);
537
- const values = {};
538
- for (const current of chain) for (const [key, value] of Object.entries(current.opts())) if (!(key in values) || current.getOptionValueSource(key) !== "default") values[key] = value;
539
- return values;
540
- }
541
- function stringOptions(options, keys) {
542
- const values = {};
543
- for (const key of keys) {
544
- const value = options[key];
545
- if (typeof value === "string") values[key] = value;
546
- }
547
- return values;
548
- }
549
- function output(value, o, human) {
550
- if (o.json) process.stdout.write(`${JSON.stringify(value)}\n`);
551
- else if (human) process.stdout.write(`${terminalText(human, true).trimEnd()}\n`);
552
- else if (typeof value === "object" && value && "url" in value) process.stdout.write(`${terminalText(value.url)}\n`);
553
- else process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
554
- }
555
- function note(message, o) {
556
- if (!o.quiet) process.stderr.write(`${terminalText(message).trimEnd()}\n`);
557
- }
558
- async function client(o) {
559
- return new SharePagesClient(await profile(o.profile, o.server));
560
- }
561
- //#endregion
562
- //#region src/validation.ts
563
- const choices = {
564
- access: accessSchema.options,
565
- format: formats,
566
- pageState: [
567
- "active",
568
- "trash",
569
- "purging",
570
- "purged",
571
- "all"
572
- ]
573
- };
574
- function pageId(value) {
575
- const parsed = slugSchema.safeParse(value);
576
- if (!parsed.success) throw new AppError("INVALID_PAGE_ID", parsed.error.issues[0]?.message ?? "页面 ID 无效");
577
- return parsed.data;
578
- }
579
- function profileName(value) {
580
- if (!/^[a-z0-9][a-z0-9._-]{0,39}$/i.test(value)) throw new AppError("INVALID_PROFILE", "Profile 名称需为 1–40 位字母、数字、点、下划线或连字符");
581
- return value;
582
- }
583
- function uploadId(value) {
584
- if (!/^[a-z0-9-]{1,80}$/i.test(value)) throw new AppError("INVALID_UPLOAD_ID", "上传 ID 只能包含字母、数字和连字符");
585
- return value;
586
- }
587
- function positiveSeconds(value) {
588
- if (!/^\d+$/.test(value)) throw new AppError("INVALID_TIMEOUT", "--timeout 必须是 1–3600 之间的整数秒数");
589
- const seconds = Number(value);
590
- if (seconds < 1 || seconds > 3600) throw new AppError("INVALID_TIMEOUT", "--timeout 必须是 1–3600 之间的整数秒数");
591
- return seconds;
592
- }
593
- function pageLimit(value) {
594
- if (!/^\d+$/.test(value) || Number(value) < 1 || Number(value) > 100) throw new AppError("INVALID_LIMIT", "--limit 必须是 1–100 之间的整数");
595
- return Number(value);
596
- }
597
- function isoDate(value) {
598
- const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
599
- if (!/^\d{4}-\d{2}-\d{2}$/.test(value) || Number.isNaN(parsed.valueOf()) || parsed.toISOString().slice(0, 10) !== value) throw new AppError("INVALID_DATE", "日期必须使用 YYYY-MM-DD 格式");
600
- return value;
601
- }
602
- function requirePatch(patch) {
603
- if (!Object.keys(patch).length) throw new AppError("EMPTY_PATCH", "没有要修改的内容;请指定 --title、--access、--indexable 或 --password-file");
604
- }
605
- //#endregion
606
- //#region src/accounts.ts
607
- function registerAccounts(cli) {
608
- examples(cli.command("login").description("验证并安全保存实例地址和发布 Token").helpGroup("开始使用").option("--token-stdin", "从 stdin 读取 Token(推荐用于自动化)").action(async (_local, command) => {
609
- const o = options(command), config = await readConfig(), name = profileName(o.profile ?? config.active ?? "default"), existing = Object.hasOwn(config.profiles, name) ? config.profiles[name] : void 0, server = o.server ?? process.env.SHARE_PAGES_SERVER ?? existing?.server, token = o.tokenStdin ? new TextDecoder().decode(await stdinBytes(1024)).trim() : process.env.SHARE_PAGES_TOKEN ?? await secret("发布 Token:", o.interactive);
610
- if (!server) throw new AppError("SERVER_REQUIRED", "首次登录需要 --server <url>");
611
- if (!token) throw new AppError("TOKEN_REQUIRED", "发布 Token 不能为空", 401);
612
- const sdk = new SharePagesClient({
613
- server,
614
- token
615
- });
616
- note(`正在验证 ${terminalText(sdk.server)}…`, o);
617
- await sdk.request("/me");
618
- config.profiles = {
619
- ...config.profiles,
620
- [name]: {
621
- server: sdk.server,
622
- token
623
- }
624
- };
625
- config.active = name;
626
- await writeConfig(config);
627
- output({
628
- profile: name,
629
- server: sdk.server,
630
- status: "logged-in"
631
- }, o, `已登录并启用 profile “${name}”\n实例: ${sdk.server}`);
632
- note("下一步: share-pages publish <文件或目录> --id <页面 ID>", o);
633
- }), [
634
- "share-pages login --server https://pages.example.com",
635
- "printf '%s' \"$SHARE_PAGES_TOKEN\" | share-pages login --server \"$SHARE_PAGES_SERVER\" --token-stdin --no-interactive",
636
- "share-pages login --profile production # 更新已有 profile 的 Token"
637
- ]);
638
- const profiles = cli.command("profiles").description("查看和切换本机保存的实例配置(永不显示 Token)").helpGroup("开始使用");
639
- examples(profiles, [
640
- "share-pages profiles list",
641
- "share-pages profiles use production",
642
- "share-pages status --profile production"
643
- ]);
644
- examples(profiles.command("list").description("列出 profile 和当前实例").action(async (_o, command) => {
645
- const o = options(command), c = await readConfig();
646
- const items = Object.entries(c.profiles).map(([name, p]) => ({
647
- name,
648
- server: p.server
649
- }));
650
- output({
651
- active: c.active,
652
- profiles: items
653
- }, o, items.length ? items.map((item) => `${item.name === c.active ? "*" : " "} ${terminalText(item.name)} ${terminalText(item.server)}`).join("\n") : "尚未保存 profile。");
654
- if (!items.length) note("下一步: share-pages login --server https://你的实例域名", o);
655
- }), ["share-pages profiles list", "share-pages profiles list --json"]);
656
- examples(profiles.command("use <name>").description("切换默认 profile").action(async (name, _o, command) => {
657
- const o = options(command), c = await readConfig();
658
- const key = profileName(name);
659
- if (!Object.hasOwn(c.profiles, key)) throw new AppError("PROFILE_NOT_FOUND", "实例配置不存在");
660
- c.active = key;
661
- await writeConfig(c);
662
- output({ active: key }, o, `已启用 profile “${key}”`);
663
- }), ["share-pages profiles use production"]);
664
- examples(cli.command("logout [name]").description("删除本机保存的一个 profile(不会撤销远端 Token)").helpGroup("开始使用").action(async (name, _local, command) => {
665
- const o = options(command), config = await readConfig(), key = profileName(name ?? o.profile ?? config.active);
666
- if (!Object.hasOwn(config.profiles, key)) throw new AppError("PROFILE_NOT_FOUND", "实例配置不存在");
667
- const { [key]: _, ...remaining } = config.profiles;
668
- config.profiles = remaining;
669
- if (config.active === key) config.active = Object.keys(remaining)[0] ?? "default";
670
- await writeConfig(config);
671
- output({
672
- profile: key,
673
- status: "logged-out",
674
- active: config.active
675
- }, o, `已删除 profile “${key}”`);
676
- note("安全提示: 如需让 Token 立即失效,请同时在后台撤销它。", o);
677
- }), ["share-pages logout", "share-pages logout production"]);
678
- examples(cli.command("status").description("检查当前 profile、网络、认证和服务端能力").helpGroup("开始使用").action(async (_local, command) => {
679
- const o = options(command), config = await readConfig(), name = o.profile ?? config.active, sdk = await client(o);
680
- note(`正在检查 ${terminalText(sdk.server)}…`, o);
681
- const [actor, capabilities] = await Promise.all([sdk.request("/me"), sdk.capabilities()]);
682
- const result = {
683
- status: "ok",
684
- profile: Object.hasOwn(config.profiles, name) ? name : null,
685
- server: sdk.server,
686
- actor: actor.kind,
687
- scopes: actor.scopes,
688
- pageIds: actor.pageIds,
689
- prefixes: actor.prefixes,
690
- formats: capabilities.formats,
691
- apiVersion: capabilities.apiVersion,
692
- contractVersion: capabilities.contractVersion
693
- };
694
- output(result, o, [
695
- "连接与认证正常",
696
- `Profile: ${terminalText(result.profile ?? "环境变量 / 临时参数")}`,
697
- `实例: ${terminalText(result.server)}`,
698
- `身份: ${terminalText(result.actor)}`,
699
- `权限: ${terminalText(result.scopes.join(", ") || "无")}`,
700
- `页面范围: ${terminalText(result.pageIds.length || result.prefixes.length ? [...result.pageIds, ...result.prefixes.map((prefix) => `${prefix}*`)].join(", ") : "全部(仍受 scope 限制)")}`,
701
- `格式: ${terminalText(result.formats.join(", "))}`,
702
- `API: v${terminalText(result.apiVersion)} · Contract ${terminalText(result.contractVersion)}`
703
- ].join("\n"));
704
- }), ["share-pages status", "share-pages status --profile production --json"]);
705
- }
706
- //#endregion
707
- //#region src/presentation.ts
708
- const date = (value) => {
709
- if (!value || !Number.isFinite(value)) return "—";
710
- try {
711
- return new Date(value).toISOString();
712
- } catch {
713
- return "—";
714
- }
715
- };
716
- const bytes = (value) => {
717
- if (!Number.isFinite(value) || value < 0) return "—";
718
- if (value < 1024) return `${value} B`;
719
- if (value < 1024 ** 2) return `${(value / 1024).toFixed(1)} KiB`;
720
- return `${(value / 1024 ** 2).toFixed(1)} MiB`;
721
- };
722
- function pagesList(result) {
723
- if (!result.items.length) return "没有符合条件的页面。";
724
- const rows = result.items.map((page) => `${terminalText(page.slug)} ${terminalText(page.title)}\n ${terminalText(page.format)} · ${terminalText(page.access)} · ${terminalText(page.state)} · ${date(page.updated_at)}`);
725
- if (result.nextCursor) rows.push(`\n下一页: --cursor ${terminalText(result.nextCursor)}`);
726
- return rows.join("\n");
727
- }
728
- function pageDetail(page) {
729
- return [
730
- `${terminalText(page.slug)} ${terminalText(page.title)}`,
731
- `格式: ${terminalText(page.format)}`,
732
- `访问: ${terminalText(page.access)}`,
733
- `状态: ${terminalText(page.state)}`,
734
- `收录: ${page.indexable ? "允许" : "禁止"}`,
735
- `当前版本: ${terminalText(page.current_version_id ?? "尚未发布")}`,
736
- `更新时间: ${date(page.updated_at)}`
737
- ].join("\n");
738
- }
739
- function versionsList(result) {
740
- if (!result.items.length) return "该页面还没有版本。";
741
- const rows = result.items.map((version) => `v${version.number} ${terminalText(version.id)}\n ${terminalText(version.state)} · ${bytes(version.bytes)} · ${date(version.created_at)}`);
742
- if (result.nextCursor) rows.push(`\n下一页: --cursor ${terminalText(result.nextCursor)}`);
743
- return rows.join("\n");
744
- }
745
- function statisticsSummary(result) {
746
- const total = result.days.reduce((sum, day) => ({
747
- pv: sum.pv + day.pv,
748
- downloads: sum.downloads + day.downloads,
749
- bytes: sum.bytes + day.bytes,
750
- errors: sum.errors + day.errors
751
- }), {
752
- pv: 0,
753
- downloads: 0,
754
- bytes: 0,
755
- errors: 0
756
- });
757
- const recent = result.days.slice(-7).map((day) => {
758
- const uv = day.uv === null ? "不可用" : `${day.uv}${day.uvStatus === "exact" ? "" : "(估算)"}`;
759
- return ` ${terminalText(day.day)} PV ${day.pv} · UV ${uv} · 下载 ${day.downloads}`;
760
- });
761
- const popular = result.popular.slice(0, 5).map((item) => ` ${terminalText(item.slug ?? item.id ?? item.scope)} PV ${item.pv} · 下载 ${item.downloads}`);
762
- return [
763
- `统计范围: ${terminalText(result.scope)}`,
764
- `UTC 区间: ${terminalText(result.from)} 至 ${terminalText(result.to)}`,
765
- `来源: ${terminalText(result.source)} · ${terminalText(result.cacheStatus)}`,
766
- `汇总: PV ${total.pv} · 下载 ${total.downloads} · 流量 ${bytes(total.bytes)} · 错误 ${total.errors}`,
767
- `访客日: ${result.visitorDays ?? "不可用"}`,
768
- recent.length ? `最近 ${recent.length} 天:\n${recent.join("\n")}` : "该区间没有每日数据。",
769
- popular.length ? `热门内容:\n${popular.join("\n")}` : void 0,
770
- result.days.length > recent.length ? "完整逐日和分布数据请使用 --json 或 --csv。" : void 0
771
- ].filter(Boolean).join("\n");
772
- }
773
- //#endregion
774
- //#region src/pages.ts
775
- function registerPages(cli) {
776
- const pages = cli.command("pages").description("查询、修改、删除和恢复页面").helpGroup("页面管理");
777
- examples(pages, [
778
- "share-pages pages list",
779
- "share-pages pages get handbook",
780
- "share-pages pages edit handbook --title \"团队手册\""
781
- ]);
782
- examples(pages.command("list").description("列出页面;默认显示 active 页面").addOption(new Option("--state <state>", "按页面状态筛选").choices(choices.pageState)).option("--q <text>", "按页面 ID 或标题搜索").addOption(new Option("--format <format>", "按内容格式筛选").choices(choices.format)).addOption(new Option("--access <mode>", "按访问方式筛选").choices(choices.access)).option("--limit <count>", "每页返回 1–100 条", pageLimit, 30).option("--cursor <cursor>", "继续读取服务端返回的下一页").action(async (_local, command) => {
783
- const o = options(command);
784
- const params = stringOptions(o, [
785
- "state",
786
- "q",
787
- "format",
788
- "access",
789
- "cursor"
790
- ]);
791
- if (o.limit) params.limit = String(o.limit);
792
- const result = await (await client(o)).listPages(params);
793
- output(result, o, pagesList(result));
794
- if (!result.items.length) note("提示: 使用 --state all 查看包括回收站在内的所有页面。", o);
795
- }), [
796
- "share-pages pages list",
797
- "share-pages pages list --q handbook --format markdown",
798
- "share-pages pages list --state trash --json"
799
- ]);
800
- examples(pages.command("get").description("查看一个页面的元数据和当前版本").argument("<id>", "页面 ID", pageId).action(async (id, _local, command) => {
801
- const o = options(command);
802
- const result = await (await client(o)).getPage(id);
803
- output(result, o, pageDetail(result));
804
- }), ["share-pages pages get handbook", "share-pages pages get handbook --json"]);
805
- examples(pages.command("edit").description("修改页面标题、访问方式或收录策略").argument("<id>", "页面 ID", pageId).option("--title <title>", "设置新标题").addOption(new Option("--access <mode>", "设置访问方式").choices(choices.access)).addOption(new Option("--indexable <boolean>", "是否允许搜索引擎收录").choices(["true", "false"])).addOption(new Option("--password-file <path>", "从权限为 600 的文件读取新密码").implies({ access: "password" })).action(async (id, _local, command) => {
806
- const o = options(command);
807
- const patch = {};
808
- if (o.passwordFile && o.access !== "password") throw new AppError("PASSWORD_ACCESS_CONFLICT", "--password-file 只能用于 password 访问方式");
809
- if (o.title !== void 0) patch.title = o.title;
810
- if (o.access) patch.access = o.access;
811
- if (o.indexable !== void 0) patch.indexable = o.indexable === "true";
812
- if (o.access === "password") patch.password = o.passwordFile ? await secretFile(o.passwordFile, "页面密码文件") : await secret("页面密码(至少 8 位):", o.interactive);
813
- if (typeof patch.password === "string" && (patch.password.length < 8 || patch.password.length > 256)) throw new AppError("INVALID_PASSWORD", "页面密码长度必须为 8–256 位");
814
- requirePatch(patch);
815
- const result = await (await client(o)).patchPage(id, patch);
816
- output(result, o, pageDetail(result));
817
- note(`已更新页面 ${id}`, o);
818
- }), [
819
- "share-pages pages edit handbook --title \"团队手册\"",
820
- "share-pages pages edit handbook --access admin --indexable false",
821
- "share-pages pages edit handbook --password-file ./private/password.txt"
822
- ]);
823
- examples(pages.command("delete").description("将页面移入回收站,或永久删除").argument("<id>", "页面 ID", pageId).option("--purge", "永久删除页面和全部版本(不可恢复)").option("--yes", "跳过交互确认(自动化环境必需)").action(async (id, _local, command) => {
824
- const o = options(command), sdk = await client(o);
825
- const page = await sdk.getPage(id);
826
- await confirm(`${o.purge ? "永久删除" : "移入回收站"}页面 ${id}(${terminalText(page.title)})及全部版本。`, !!o.yes, !!o.interactive);
827
- output(await sdk.deletePage(id, o.purge), o, o.purge ? `页面 ${id} 已进入永久清理队列。` : `页面 ${id} 已移入回收站。`);
828
- }), ["share-pages pages delete handbook", "share-pages pages delete handbook --purge --yes --no-interactive"]);
829
- examples(pages.command("restore").description("从回收站恢复页面").argument("<id>", "页面 ID", pageId).option("--replace-with <version>", "当前版本不可用时指定接替版本 ID").action(async (id, _local, command) => {
830
- const o = options(command);
831
- output(await (await client(o)).restorePage(id, o.replaceWith), o, `页面 ${id} 已恢复。`);
832
- }), ["share-pages pages restore handbook", "share-pages pages restore handbook --replace-with <版本 UUID>"]);
833
- }
834
- //#endregion
835
- //#region src/publish.ts
836
- function registerPublish(cli) {
837
- examples(cli.command("publish").description("检查、转换并发布文件、ZIP 或目录").helpGroup("发布与传输").argument("<input>", "文件、ZIP、目录,或 -(从 stdin 读取)").option("--id <id>", "设置 3–40 位稳定页面 ID", pageId).option("--update", "更新已有 ID").addOption(new Option("--type <format>", "覆盖自动识别的内容格式").choices(choices.format)).option("--title <title>", "覆盖从内容推导的页面标题").option("--entry <path>", "HTML/站点入口文件", "index.html").option("--spa", "找不到站点路径时回退到入口文件").addOption(new Option("--access <mode>", "访问方式(新页面默认 public)").choices(choices.access)).option("--indexable", "允许公开页面被搜索引擎收录").option("--encoding <encoding>", "Markdown/LaTeX/CSV 文本编码", "utf-8").option("--delimiter <delimiter>", "覆盖 CSV 分隔符自动识别").option("--no-header", "将 CSV 第一行视为数据而非表头").addOption(new Option("--password-file <path>", "从权限为 600 的文件读取页面密码").implies({ access: "password" })).addOption(new Option("--dry-run", "仅在本地转换和校验,不访问服务器").conflicts("resume")).addOption(new Option("--resume <upload-id>", "继续先前中断的上传").conflicts("dryRun")).option("--idempotency-key <key>", "为自动化重试提供稳定幂等键").option("--no-wait", "提交后返回处理中状态").option("--timeout <seconds>", "等待发布完成的秒数(1–3600)", positiveSeconds, 120).action(async (input, _local, command) => {
838
- const o = options(command);
839
- const { prepareNode, prepareBytes, ensureDOM } = await import("./node-DVMkHtVp.mjs");
840
- if (o.update && !o.id) throw new AppError("ID_REQUIRED", "--update 必须同时指定 --id");
841
- if (o.passwordFile && o.access !== "password") throw new AppError("PASSWORD_ACCESS_CONFLICT", "--password-file 只能用于 password 访问方式");
842
- if (o.indexable && o.access && o.access !== "public") throw new AppError("INVALID_INDEX_POLICY", "--indexable 只适用于 public 页面");
843
- if (input === "-" && !o.type) throw new AppError("TYPE_REQUIRED", "stdin 需要显式 --type");
844
- let sdk, limits = defaultLimits;
845
- if (!o.dryRun) {
846
- sdk = await client(o);
847
- note(`正在检查实例限制: ${terminalText(sdk.server)}…`, o);
848
- limits = (await sdk.capabilities()).limits;
849
- }
850
- note(o.dryRun ? "正在本地检查并转换内容…" : "正在检查并转换内容…", o);
851
- const prepareOptions = {
852
- type: o.type,
853
- title: o.title,
854
- entry: o.entry,
855
- spa: o.spa,
856
- encoding: o.encoding,
857
- delimiter: o.delimiter,
858
- header: o.header,
859
- limits
860
- };
861
- let prepared;
862
- if (input === "-") {
863
- if (o.type === "latex") await ensureDOM();
864
- prepared = await prepareBytes(`stdin.${o.type === "markdown" ? "md" : o.type === "latex" ? "tex" : o.type}`, await stdinBytes(limits.inputBytes), prepareOptions);
865
- } else prepared = await prepareNode(input, prepareOptions);
866
- if (o.dryRun) {
867
- const totalBytes = prepared.manifest.files.reduce((sum, file) => sum + file.size, 0);
868
- output({
869
- status: "valid",
870
- title: prepared.title,
871
- manifest: prepared.manifest,
872
- warnings: prepared.warnings
873
- }, o, [
874
- "本地检查通过(未访问服务器)",
875
- `标题: ${terminalText(prepared.title)}`,
876
- `格式: ${prepared.manifest.format}`,
877
- `文件: ${prepared.manifest.files.length}`,
878
- `总大小: ${totalBytes} bytes`,
879
- `警告: ${prepared.warnings.length ? prepared.warnings.join(";") : "无"}`
880
- ].join("\n"));
881
- return;
882
- }
883
- const manifestHash = await digest(JSON.stringify(prepared.manifest));
884
- if (!sdk) throw new AppError("MISSING_CLIENT", "发布客户端尚未初始化");
885
- if (o.resume) {
886
- let saved;
887
- try {
888
- saved = JSON.parse(await readFile(resumePath(o.resume), "utf8"));
889
- } catch (error) {
890
- if (error.code) throw error;
891
- throw new AppError("INVALID_RESUME_STATE", "续传状态文件已损坏,请开始新的上传");
892
- }
893
- if (!saved || typeof saved !== "object" || !("manifestHash" in saved) || !("server" in saved) || saved.manifestHash !== manifestHash || saved.server !== sdk.server) throw new AppError("RESUME_MISMATCH", "文件内容或实例与断点会话不一致");
894
- }
895
- const password = o.access === "password" ? o.passwordFile ? await secretFile(o.passwordFile, "页面密码文件") : await secret("页面密码(至少 8 位):", o.interactive) : void 0;
896
- if (password && (password.length < 8 || password.length > 256)) throw new AppError("INVALID_PASSWORD", "页面密码长度必须为 8–256 位");
897
- let sessionId = o.resume;
898
- note(o.resume ? `正在恢复上传 ${o.resume}…` : "正在创建上传会话…", o);
899
- const result = await sdk.publish(prepared, {
900
- id: o.id,
901
- update: !!o.update,
902
- title: o.title,
903
- access: o.access,
904
- password,
905
- indexable: typeof o.indexable === "boolean" ? o.indexable : void 0,
906
- idempotencyKey: o.idempotencyKey,
907
- uploadId: o.resume,
908
- wait: o.wait,
909
- timeoutMs: (o.timeout ?? 120) * 1e3,
910
- onSession: async (s) => {
911
- sessionId = s.id;
912
- await savePrivate(resumePath(s.id), {
913
- server: sdk?.server,
914
- uploadId: s.id,
915
- manifestHash
916
- });
917
- note(`上传会话: ${s.id}(网络中断后可使用 --resume ${s.id})`, o);
918
- },
919
- onProgress: (done, total) => {
920
- if (!o.quiet && process.stderr.isTTY) process.stderr.write(`\r上传 ${total ? Math.floor(done / total * 100) : 100}%`);
921
- }
922
- });
923
- if (result.status === "ready" && sessionId) await removeResume(sessionId);
924
- if (!o.quiet && process.stderr.isTTY) process.stderr.write("\n");
925
- output(result, o, result.status === "ready" ? terminalText(result.url) : `上传 ${terminalText(result.id)}: ${terminalText(result.status)}`);
926
- if (result.status === "ready") {
927
- note(`已发布 ${terminalText(result.pageId)} · 版本 ${result.versionNumber}`, o);
928
- note(`管理: ${terminalText(result.manageUrl)}`, o);
929
- note(`下一次更新: share-pages publish ${terminalText(input)} --id ${result.pageId} --update`, o);
930
- } else note(`下一步: share-pages uploads ${result.id}`, o);
931
- if (result.status !== "ready") process.exitCode = 6;
932
- }), [
933
- "share-pages publish ./dist --id my-site",
934
- "share-pages publish ./README.md --id project-readme --dry-run",
935
- "share-pages publish ./README.md --id project-readme --update",
936
- "printf '# Hello' | share-pages publish - --type markdown --id hello"
937
- ], [
938
- "支持 html、zip、markdown、latex、epub、csv;目录按静态站点发布。",
939
- "新建已有 ID 会失败;更新必须显式使用 --update,以避免误覆盖。",
940
- "JSON 模式下结果只写 stdout,进度和提示写 stderr;添加 --quiet 可隐藏提示。"
941
- ]);
942
- }
943
- //#endregion
944
- //#region src/stats.ts
945
- function registerStats(cli) {
946
- examples(cli.command("stats").description("查询全站、页面或版本的访问统计").helpGroup("观测与诊断").argument("[id]", "可选的页面 ID", pageId).option("--version <version>", "只查询指定版本 UUID").option("--from <date>", "UTC 起始日期(YYYY-MM-DD)", isoDate).option("--to <date>", "UTC 结束日期(YYYY-MM-DD)", isoDate).option("--csv", "以 CSV 输出到 stdout").action(async (id, _local, command) => {
947
- const o = options(command), params = {};
948
- if (o.csv && o.json) throw new AppError("OUTPUT_CONFLICT", "--csv 和 --json 不能同时使用");
949
- if (o.from && o.to && o.from > o.to) throw new AppError("INVALID_DATE_RANGE", "--from 不能晚于 --to");
950
- if (id) params.page = id;
951
- for (const k of [
952
- "version",
953
- "from",
954
- "to"
955
- ]) if (o[k]) params[k] = o[k];
956
- if (o.csv) params.format = "csv";
957
- const data = await (await client(o)).stats(params);
958
- if (data instanceof Response) {
959
- const csv = await data.text();
960
- process.stdout.write(csv.endsWith("\n") ? csv : `${csv}\n`);
961
- } else output(data, o, statisticsSummary(data));
962
- }), [
963
- "share-pages stats --from 2026-09-01 --to 2026-09-07",
964
- "share-pages stats handbook --json",
965
- "share-pages stats handbook --csv > stats.csv"
966
- ]);
967
- examples(cli.command("uploads").description("查询断点上传或异步发布任务的状态").helpGroup("观测与诊断").argument("<id>", "上传会话 ID", uploadId).action(async (id, _local, command) => {
968
- const o = options(command);
969
- const result = await (await client(o)).request(`/uploads/${encodeURIComponent(id)}`);
970
- output(result, o, [
971
- `上传 ${terminalText(result.id)}: ${terminalText(result.status)}`,
972
- `版本: ${terminalText(result.versionId)}`,
973
- result.result?.url ? `页面: ${terminalText(result.result.url)}` : void 0,
974
- result.error ? `错误: ${terminalText(result.error.code)} · ${terminalText(result.error.message)}` : void 0,
975
- result.missing.length ? `待上传分片文件: ${result.missing.length}` : void 0
976
- ].filter(Boolean).join("\n"));
977
- }), ["share-pages uploads <上传会话 ID>", "share-pages uploads <上传会话 ID> --json"]);
978
- }
979
- //#endregion
980
- //#region src/transfer.ts
981
- function registerTransfer(cli) {
982
- examples(cli.command("download").description("下载页面当前版本或指定版本的原件").helpGroup("发布与传输").argument("<id>", "页面 ID", pageId).option("--version <version>", "下载指定版本 UUID(默认当前版本)").option("-o, --output <file>", "输出文件;使用 - 写入 stdout").action(async (id, _local, command) => {
983
- const o = options(command);
984
- if (o.output === "-" && o.json) throw new AppError("OUTPUT_CONFLICT", "--output - 输出原件字节,不能与 --json 同时使用");
985
- const sdk = await client(o);
986
- note(`正在下载 ${id}${o.version ? ` 的版本 ${terminalText(o.version)}` : ""}…`, o);
987
- const version = o.version ?? (await sdk.getPage(id)).current_version_id;
988
- if (!version) throw new AppError("NO_CURRENT_VERSION", "页面没有当前版");
989
- const response = await sdk.download(id, String(version));
990
- const filename = o.output ?? `${id}-${version}.source`;
991
- if (!response.body) throw new AppError("EMPTY_DOWNLOAD", "下载内容为空");
992
- if (filename === "-") {
993
- note(`正在将 ${id} 的原件写入 stdout…`, o);
994
- await pipeline(Readable.fromWeb(response.body), process.stdout);
995
- return;
996
- }
997
- await pipeline(Readable.fromWeb(response.body), createWriteStream(filename, {
998
- flags: "wx",
999
- mode: 384
1000
- }));
1001
- output({
1002
- file: filename,
1003
- versionId: version
1004
- }, o, `原件已保存: ${terminalText(filename)}\n版本: ${terminalText(version)}`);
1005
- }), [
1006
- "share-pages download handbook --output handbook.md",
1007
- "share-pages download handbook --version <版本 UUID> --output handbook-v1.md",
1008
- "share-pages download handbook --output - > handbook.source"
1009
- ], ["CLI 使用独占创建模式,不会覆盖已有文件。"]);
1010
- }
1011
- //#endregion
1012
- //#region src/versions.ts
1013
- function registerVersions(cli) {
1014
- const versions = cli.command("versions").description("查询、删除和恢复页面历史版本").helpGroup("页面管理");
1015
- examples(versions, ["share-pages versions list handbook", "share-pages rollback handbook --to <版本 UUID>"]);
1016
- examples(versions.command("list").description("按版本号倒序列出历史版本").argument("<id>", "页面 ID", pageId).option("--cursor <cursor>", "继续读取服务端返回的下一页").action(async (id, _local, command) => {
1017
- const o = options(command);
1018
- const result = await (await client(o)).listVersions(id, o.cursor);
1019
- output(result, o, versionsList(result));
1020
- }), ["share-pages versions list handbook", "share-pages versions list handbook --json"]);
1021
- examples(versions.command("delete").description("将历史版本移入回收站,或永久删除").argument("<id>", "页面 ID", pageId).argument("<version>", "版本 UUID").option("--replace-with <version>", "删除当前版时指定接替版本 UUID").option("--unpublish", "删除当前版且不指定接替版本时下线页面").option("--purge", "永久删除版本(不可恢复)").option("--yes", "跳过交互确认(自动化环境必需)").action(async (id, version, _local, command) => {
1022
- const o = options(command), sdk = await client(o);
1023
- await sdk.getPage(id);
1024
- await confirm(`${o.purge ? "永久删除" : "移入回收站"} ${id} 的版本 ${version}。`, !!o.yes, !!o.interactive);
1025
- output(await sdk.deleteVersion(id, version, {
1026
- replaceWith: o.replaceWith,
1027
- unpublish: o.unpublish,
1028
- purge: o.purge
1029
- }), o, o.purge ? `版本 ${version} 已进入永久清理队列。` : `版本 ${version} 已移入回收站。`);
1030
- }), ["share-pages versions delete handbook <版本 UUID>", "share-pages versions delete handbook <版本 UUID> --purge --yes --no-interactive"]);
1031
- examples(versions.command("restore").description("恢复回收站中的历史版本(不切换当前版本)").argument("<id>", "页面 ID", pageId).argument("<version>", "版本 UUID").action(async (id, version, _local, command) => {
1032
- const o = options(command);
1033
- output(await (await client(o)).restoreVersion(id, version), o, `版本 ${version} 已恢复。`);
1034
- }), ["share-pages versions restore handbook <版本 UUID>"]);
1035
- examples(cli.command("rollback").description("以历史版本内容创建一个新的当前版本").helpGroup("页面管理").argument("<id>", "页面 ID", pageId).requiredOption("--to <version>", "要回滚到的版本 UUID").option("--idempotency-key <key>", "为自动化重试提供稳定幂等键").option("--no-wait", "提交后返回处理中状态").option("--timeout <seconds>", "等待完成的秒数(1–3600)", positiveSeconds, 120).action(async (id, _local, command) => {
1036
- const o = options(command), result = await (await client(o)).rollback(id, o.to ?? "", {
1037
- wait: o.wait,
1038
- idempotencyKey: o.idempotencyKey,
1039
- timeoutMs: (o.timeout ?? 120) * 1e3
1040
- });
1041
- output(result, o, result.status === "ready" ? result.url : `上传 ${result.id}: ${result.status}`);
1042
- if (result.status === "ready") note(`已创建版本 ${result.versionNumber},当前页面已切换。`, o);
1043
- else note(`下一步: share-pages uploads ${result.id}`, o);
1044
- if (result.status !== "ready") process.exitCode = 6;
1045
- }), [
1046
- "share-pages versions list handbook",
1047
- "share-pages rollback handbook --to <版本 UUID>",
1048
- "share-pages rollback handbook --to <版本 UUID> --no-wait --json"
1049
- ]);
1050
- }
1051
- //#endregion
1052
- //#region src/program.ts
1053
- function buildCLI() {
1054
- const cli = createCommand();
1055
- configureHelp(cli);
1056
- registerAccounts(cli);
1057
- registerPublish(cli);
1058
- registerPages(cli);
1059
- registerVersions(cli);
1060
- registerTransfer(cli);
1061
- registerStats(cli);
1062
- examples(cli, [
1063
- "share-pages login --server https://pages.example.com",
1064
- "share-pages publish ./dist --id my-site",
1065
- "share-pages pages list",
1066
- "share-pages status"
1067
- ], [
1068
- "全局选项可以写在子命令前后。自动化环境建议添加 --json --no-interactive。",
1069
- "环境变量:SHARE_PAGES_SERVER、SHARE_PAGES_TOKEN、SHARE_PAGES_CONFIG_DIR。",
1070
- "完整说明:https://www.npmjs.com/package/share-pages,或运行 share-pages help <命令>。"
1071
- ]);
1072
- const configure = (command) => {
1073
- command.enablePositionalOptions();
1074
- for (const option of cli.options) {
1075
- if (option.long === "--version" || command.options.some((local) => local.long === option.long)) continue;
1076
- command.addOption(new Option(option.flags, option.description).helpGroup("全局选项"));
1077
- }
1078
- for (const child of command.commands) configure(child);
1079
- };
1080
- configure(cli);
1081
- return cli;
1082
- }
1083
- //#endregion
1084
- //#region src/index.ts
1085
- process.stdout.on("error", (error) => {
1086
- if (error.code === "EPIPE") process.exitCode = 0;
1087
- else throw error;
1088
- });
1089
- const cli = buildCLI();
1090
- try {
1091
- await cli.parseAsync();
1092
- } catch (error) {
1093
- if (isHelpExit(error)) process.exitCode = 0;
1094
- else {
1095
- const resolved = normalizeError(error);
1096
- printError(resolved, wantsJSON(process.argv.slice(2)));
1097
- process.exitCode = exitCode(resolved);
1098
- }
1099
- }
1100
- //#endregion
1101
- export {};
2
+ import{i as e,t}from"./rolldown-runtime-Csi-cuKc.mjs";import{t as n}from"./dist-BQU5lE8l.mjs";import{i as r,n as i,t as a}from"./package-Dtp2swhT.mjs";import{spawn as o}from"node:child_process";import{delimiter as s,dirname as c,join as l}from"node:path";import{createHash as u,randomUUID as d}from"node:crypto";import{access as f,mkdir as p,mkdtemp as m,readFile as h,readdir as g,rename as _,rm as v,writeFile as y}from"node:fs/promises";import{homedir as b,tmpdir as x}from"node:os";const S={UPDATE_CHECK_FAILED:`检查网络、npm registry 和认证配置后重试;所有命令都必须先完成更新检查`,UPDATE_INSTALL_FAILED:`检查网络、npm 配置与用户缓存目录权限后重试`,UPDATE_EXEC_FAILED:`检查 Node.js 和用户缓存目录权限后重试`,LOGIN_REQUIRED:`先运行 share-pages login --server https://你的实例域名`,SERVER_REQUIRED:`添加 --server https://你的实例域名,或为已有 profile 重新登录`,INVALID_SERVER:`--server 只填写 origin,例如 https://pages.example.com`,INSECURE_SERVER:`远程实例必须使用 HTTPS;只有 localhost 可以使用 HTTP`,TOKEN_REQUIRED:`在后台创建发布 Token,然后重新登录`,INVALID_PAGE_ID:`页面 ID 使用 3–40 位小写字母、数字或连字符,并避开系统保留名称`,INVALID_PROFILE:`例如使用 default、production 或 team_docs`,INVALID_UPLOAD_ID:`复制上传开始时 CLI 输出的完整会话 ID`,INVALID_DATE:`例如使用 2026-09-10`,INVALID_DATE_RANGE:`交换起止日期,确保 --from 不晚于 --to`,INVALID_LIMIT:`将 --limit 设置为 1–100 的整数`,INVALID_TIMEOUT:`将 --timeout 设置为 1–3600 的整数秒数`,ID_REQUIRED:`添加 --id <已有页面 ID>,或去掉 --update 创建新页面`,TYPE_REQUIRED:`stdin 没有文件名;添加 --type markdown、html、latex、epub、csv 或 zip`,INVALID_INDEX_POLICY:`改用 --access public,或移除 --indexable`,INPUT_REQUIRED:`自动化环境请使用 --token-stdin、--password-file 或对应环境变量`,CONFIRMATION_REQUIRED:`确认目标无误后添加 --yes;永久删除无法恢复`,ID_EXISTS:`若要为已有页面创建新版本,请保持相同 --id 并添加 --update`,PAGE_NOT_FOUND:`运行 share-pages pages list 查找可用页面 ID`,VERSION_NOT_FOUND:`运行 share-pages versions list <页面 ID> 查找版本 ID`,RESUME_MISMATCH:`使用创建该会话时相同的文件和实例,或去掉 --resume 开始新上传`,INVALID_RESUME_STATE:`去掉 --resume 开始新上传;损坏状态不会影响服务端已有内容`,NETWORK_ERROR:`检查网络和实例地址后重试;已有上传会话可用 --resume 继续`,REQUEST_TIMEOUT:`可增大 --timeout,或用 --no-wait 后运行 share-pages uploads <上传 ID>`,OUTPUT_EXISTS:`换一个 --output 路径;CLI 不会覆盖已有文件`,INPUT_NOT_FOUND:`检查输入路径、--password-file 或 --resume 的值是否正确`,PERMISSION_DENIED:`检查文件权限以及当前目录是否可读写`,CONFIG_ERROR:`修复或移走配置文件后重新登录;默认位置为 ~/.config/share-pages/config.json`,INSECURE_SECRET_FILE:`秘密文件只能由当前用户读写,建议设置为 chmod 600`,INVALID_PASSWORD:`换用 8–256 位页面密码后重试`,PASSWORD_ACCESS_CONFLICT:`使用 --access password,或移除 --password-file`,EMPTY_PATCH:`运行 share-pages pages edit --help 查看可修改字段`,OUTPUT_CONFLICT:`只选择一种 stdout 输出格式后重试`};function C(e){let t=e.path?`:${e.path}`:``;if(e.code===`EEXIST`)return new n(`OUTPUT_EXISTS`,`目标文件已存在${t}`);if(e.code===`ENOENT`)return new n(`INPUT_NOT_FOUND`,`找不到文件或目录${t}`);if(e.code===`EACCES`||e.code===`EPERM`)return new n(`PERMISSION_DENIED`,`没有文件访问权限${t}`,403)}function w(e){return e instanceof r&&(e.exitCode===0||[`commander.help`,`commander.helpDisplayed`].includes(e.code))}function T(e){if(e instanceof r)return{code:`CLI_USAGE`,message:e.message.replace(/^error:\s*/i,``).trim().replace(/^unknown command /i,`未知命令 `).replace(/^unknown option /i,`未知选项 `).replace(/^missing required argument /i,`缺少必填参数 `).replace(/^too many arguments\./i,`参数过多。`).replace(/\(Did you mean (.+)\?\)/i,`你可能想输入 $1。`),status:400,hint:`运行 share-pages --help,或 share-pages <命令> --help 查看示例`};let t=(e instanceof n?e:C(e))??new n(`CLI_ERROR`,e instanceof Error?e.message:`命令执行失败;请重试或使用 --help 检查参数`);return{code:t.code,message:t.message,status:t.status,fields:t.fields,requestId:t.requestId,hint:S[t.code]}}function E(e){return e.code===`UPDATE_INTERRUPTED`?130:e.status===401||e.status===403?3:e.status===409?4:e.status>=500?5:2}function D(e,t){if(t){let{status:t,...n}=e;process.stdout.write(`${JSON.stringify({error:n})}\n`);return}process.stderr.write(`错误 [${i(e.code)}]: ${i(e.message,!0)}\n`),e.requestId&&process.stderr.write(`请求 ID: ${i(e.requestId)}\n`),e.hint&&process.stderr.write(`下一步: ${i(e.hint)}\n`)}function O(e){let t=e.indexOf(`--`),n=t===-1?e:e.slice(0,t);return n.includes(`--json`)||n.includes(`-j`)}var k=t(((e,t)=>{t.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:16,MAX_SAFE_BUILD_LENGTH:250,MAX_SAFE_INTEGER:2**53-1||9007199254740991,RELEASE_TYPES:[`major`,`premajor`,`minor`,`preminor`,`patch`,`prepatch`,`prerelease`],SEMVER_SPEC_VERSION:`2.0.0`,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}})),A=t(((e,t)=>{t.exports=typeof process==`object`&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...e)=>console.error(`SEMVER`,...e):()=>{}})),j=t(((e,t)=>{let{MAX_SAFE_COMPONENT_LENGTH:n,MAX_SAFE_BUILD_LENGTH:r,MAX_LENGTH:i}=k(),a=A();e=t.exports={};let o=e.re=[],s=e.safeRe=[],c=e.src=[],l=e.safeSrc=[],u=e.t={},d=0,f=`[a-zA-Z0-9-]`,p=[[`\\s`,1],[`\\d`,i],[f,r]],m=e=>{for(let[t,n]of p)e=e.split(`${t}*`).join(`${t}{0,${n}}`).split(`${t}+`).join(`${t}{1,${n}}`);return e},h=(e,t,n)=>{let r=m(t),i=d++;a(e,i,t),u[e]=i,c[i]=t,l[i]=r,o[i]=new RegExp(t,n?`g`:void 0),s[i]=new RegExp(r,n?`g`:void 0)};h(`NUMERICIDENTIFIER`,`0|[1-9]\\d*`),h(`NUMERICIDENTIFIERLOOSE`,`\\d+`),h(`NONNUMERICIDENTIFIER`,`\\d*[a-zA-Z-]${f}*`),h(`MAINVERSION`,`(${c[u.NUMERICIDENTIFIER]})\\.(${c[u.NUMERICIDENTIFIER]})\\.(${c[u.NUMERICIDENTIFIER]})`),h(`MAINVERSIONLOOSE`,`(${c[u.NUMERICIDENTIFIERLOOSE]})\\.(${c[u.NUMERICIDENTIFIERLOOSE]})\\.(${c[u.NUMERICIDENTIFIERLOOSE]})`),h(`PRERELEASEIDENTIFIER`,`(?:${c[u.NONNUMERICIDENTIFIER]}|${c[u.NUMERICIDENTIFIER]})`),h(`PRERELEASEIDENTIFIERLOOSE`,`(?:${c[u.NONNUMERICIDENTIFIER]}|${c[u.NUMERICIDENTIFIERLOOSE]})`),h(`PRERELEASE`,`(?:-(${c[u.PRERELEASEIDENTIFIER]}(?:\\.${c[u.PRERELEASEIDENTIFIER]})*))`),h(`PRERELEASELOOSE`,`(?:-?(${c[u.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${c[u.PRERELEASEIDENTIFIERLOOSE]})*))`),h(`BUILDIDENTIFIER`,`${f}+`),h(`BUILD`,`(?:\\+(${c[u.BUILDIDENTIFIER]}(?:\\.${c[u.BUILDIDENTIFIER]})*))`),h(`FULLPLAIN`,`v?${c[u.MAINVERSION]}${c[u.PRERELEASE]}?${c[u.BUILD]}?`),h(`FULL`,`^${c[u.FULLPLAIN]}$`),h(`LOOSEPLAIN`,`[v=\\s]*${c[u.MAINVERSIONLOOSE]}${c[u.PRERELEASELOOSE]}?${c[u.BUILD]}?`),h(`LOOSE`,`^${c[u.LOOSEPLAIN]}$`),h(`GTLT`,`((?:<|>)?=?)`),h(`XRANGEIDENTIFIERLOOSE`,`${c[u.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`),h(`XRANGEIDENTIFIER`,`${c[u.NUMERICIDENTIFIER]}|x|X|\\*`),h(`XRANGEPLAIN`,`[v=\\s]*(${c[u.XRANGEIDENTIFIER]})(?:\\.(${c[u.XRANGEIDENTIFIER]})(?:\\.(${c[u.XRANGEIDENTIFIER]})(?:${c[u.PRERELEASE]})?${c[u.BUILD]}?)?)?`),h(`XRANGEPLAINLOOSE`,`[v=\\s]*(${c[u.XRANGEIDENTIFIERLOOSE]})(?:\\.(${c[u.XRANGEIDENTIFIERLOOSE]})(?:\\.(${c[u.XRANGEIDENTIFIERLOOSE]})(?:${c[u.PRERELEASELOOSE]})?${c[u.BUILD]}?)?)?`),h(`XRANGE`,`^${c[u.GTLT]}\\s*${c[u.XRANGEPLAIN]}$`),h(`XRANGELOOSE`,`^${c[u.GTLT]}\\s*${c[u.XRANGEPLAINLOOSE]}$`),h(`COERCEPLAIN`,`(^|[^\\d])(\\d{1,${n}})(?:\\.(\\d{1,${n}}))?(?:\\.(\\d{1,${n}}))?`),h(`COERCE`,`${c[u.COERCEPLAIN]}(?:$|[^\\d])`),h(`COERCEFULL`,c[u.COERCEPLAIN]+`(?:${c[u.PRERELEASE]})?(?:${c[u.BUILD]})?(?:$|[^\\d])`),h(`COERCERTL`,c[u.COERCE],!0),h(`COERCERTLFULL`,c[u.COERCEFULL],!0),h(`LONETILDE`,`(?:~>?)`),h(`TILDETRIM`,`(\\s*)${c[u.LONETILDE]}\\s+`,!0),e.tildeTrimReplace=`$1~`,h(`TILDE`,`^${c[u.LONETILDE]}${c[u.XRANGEPLAIN]}$`),h(`TILDELOOSE`,`^${c[u.LONETILDE]}${c[u.XRANGEPLAINLOOSE]}$`),h(`LONECARET`,`(?:\\^)`),h(`CARETTRIM`,`(\\s*)${c[u.LONECARET]}\\s+`,!0),e.caretTrimReplace=`$1^`,h(`CARET`,`^${c[u.LONECARET]}${c[u.XRANGEPLAIN]}$`),h(`CARETLOOSE`,`^${c[u.LONECARET]}${c[u.XRANGEPLAINLOOSE]}$`),h(`COMPARATORLOOSE`,`^${c[u.GTLT]}\\s*(${c[u.LOOSEPLAIN]})$|^$`),h(`COMPARATOR`,`^${c[u.GTLT]}\\s*(${c[u.FULLPLAIN]})$|^$`),h(`COMPARATORTRIM`,`(\\s*)${c[u.GTLT]}\\s*(${c[u.LOOSEPLAIN]}|${c[u.XRANGEPLAIN]})`,!0),e.comparatorTrimReplace=`$1$2$3`,h(`HYPHENRANGE`,`^\\s*(${c[u.XRANGEPLAIN]})\\s+-\\s+(${c[u.XRANGEPLAIN]})\\s*$`),h(`HYPHENRANGELOOSE`,`^\\s*(${c[u.XRANGEPLAINLOOSE]})\\s+-\\s+(${c[u.XRANGEPLAINLOOSE]})\\s*$`),h(`STAR`,`(<|>)?=?\\s*\\*`),h(`GTE0`,`^\\s*>=\\s*0\\.0\\.0\\s*$`),h(`GTE0PRE`,`^\\s*>=\\s*0\\.0\\.0-0\\s*$`)})),M=t(((e,t)=>{let n=Object.freeze({loose:!0}),r=Object.freeze({});t.exports=e=>e?typeof e==`object`?e:n:r})),N=t(((e,t)=>{let n=/^[0-9]+$/,r=(e,t)=>{if(typeof e==`number`&&typeof t==`number`)return e===t?0:e<t?-1:1;let r=n.test(e),i=n.test(t);return r&&i&&(e=+e,t=+t),e===t?0:r&&!i?-1:i&&!r?1:e<t?-1:1};t.exports={compareIdentifiers:r,rcompareIdentifiers:(e,t)=>r(t,e)}})),P=t(((e,t)=>{let n=A(),{MAX_LENGTH:r,MAX_SAFE_INTEGER:i}=k(),{safeRe:a,t:o}=j(),s=M(),{compareIdentifiers:c}=N(),l=(e,t)=>{let n=t.split(`.`);if(n.length>e.length)return!1;for(let t=0;t<n.length;t++)if(c(e[t],n[t])!==0)return!1;return!0};t.exports=class e{constructor(t,c){if(c=s(c),t instanceof e){if(t.loose===!!c.loose&&t.includePrerelease===!!c.includePrerelease)return t;t=t.version}else if(typeof t!=`string`)throw TypeError(`Invalid version. Must be a string. Got type "${typeof t}".`);if(t.length>r)throw TypeError(`version is longer than ${r} characters`);n(`SemVer`,t,c),this.options=c,this.loose=!!c.loose,this.includePrerelease=!!c.includePrerelease;let l=t.trim().match(c.loose?a[o.LOOSE]:a[o.FULL]);if(!l)throw TypeError(`Invalid Version: ${t}`);if(this.raw=t,this.major=+l[1],this.minor=+l[2],this.patch=+l[3],this.major>i||this.major<0)throw TypeError(`Invalid major version`);if(this.minor>i||this.minor<0)throw TypeError(`Invalid minor version`);if(this.patch>i||this.patch<0)throw TypeError(`Invalid patch version`);this.prerelease=l[4]?l[4].split(`.`).map(e=>{if(/^[0-9]+$/.test(e)){let t=+e;if(t>=0&&t<i)return t}return e}):[],this.build=l[5]?l[5].split(`.`):[],this.format()}format(){return this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length&&(this.version+=`-${this.prerelease.join(`.`)}`),this.version}toString(){return this.version}compare(t){if(n(`SemVer.compare`,this.version,this.options,t),!(t instanceof e)){if(typeof t==`string`&&t===this.version)return 0;t=new e(t,this.options)}return t.version===this.version?0:this.compareMain(t)||this.comparePre(t)}compareMain(t){return t instanceof e||(t=new e(t,this.options)),this.major<t.major?-1:this.major>t.major?1:this.minor<t.minor?-1:this.minor>t.minor?1:this.patch<t.patch?-1:+(this.patch>t.patch)}comparePre(t){if(t instanceof e||(t=new e(t,this.options)),this.prerelease.length&&!t.prerelease.length)return-1;if(!this.prerelease.length&&t.prerelease.length)return 1;if(!this.prerelease.length&&!t.prerelease.length)return 0;let r=0;do{let e=this.prerelease[r],i=t.prerelease[r];if(n(`prerelease compare`,r,e,i),e===void 0&&i===void 0)return 0;if(i===void 0)return 1;if(e===void 0)return-1;if(e!==i)return c(e,i)}while(++r)}compareBuild(t){t instanceof e||(t=new e(t,this.options));let r=0;do{let e=this.build[r],i=t.build[r];if(n(`build compare`,r,e,i),e===void 0&&i===void 0)return 0;if(i===void 0)return 1;if(e===void 0)return-1;if(e!==i)return c(e,i)}while(++r)}inc(e,t,n){if(e.startsWith(`pre`)){if(!t&&n===!1)throw Error(`invalid increment argument: identifier is empty`);if(t){let e=`-${t}`.match(this.options.loose?a[o.PRERELEASELOOSE]:a[o.PRERELEASE]);if(!e||e[1]!==t)throw Error(`invalid identifier: ${t}`)}}switch(e){case`premajor`:this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc(`pre`,t,n);break;case`preminor`:this.prerelease.length=0,this.patch=0,this.minor++,this.inc(`pre`,t,n);break;case`prepatch`:this.prerelease.length=0,this.inc(`patch`,t,n),this.inc(`pre`,t,n);break;case`prerelease`:this.prerelease.length===0&&this.inc(`patch`,t,n),this.inc(`pre`,t,n);break;case`release`:if(this.prerelease.length===0)throw Error(`version ${this.raw} is not a prerelease`);this.prerelease.length=0;break;case`major`:(this.minor!==0||this.patch!==0||this.prerelease.length===0)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case`minor`:(this.patch!==0||this.prerelease.length===0)&&this.minor++,this.patch=0,this.prerelease=[];break;case`patch`:this.prerelease.length===0&&this.patch++,this.prerelease=[];break;case`pre`:{let e=+!!Number(n);if(this.prerelease.length===0)this.prerelease=[e];else{let r=this.prerelease.length;for(;--r>=0;)typeof this.prerelease[r]==`number`&&(this.prerelease[r]++,r=-2);if(r===-1){if(t===this.prerelease.join(`.`)&&n===!1)throw Error(`invalid increment argument: identifier already exists`);this.prerelease.push(e)}}if(t){let r=[t,e];if(n===!1&&(r=[t]),l(this.prerelease,t)){let e=this.prerelease[t.split(`.`).length];isNaN(e)&&(this.prerelease=r)}else this.prerelease=r}break}default:throw Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(`.`)}`),this}}})),F=t(((e,t)=>{let n=P();t.exports=(e,t,r=!1)=>{if(e instanceof n)return e;try{return new n(e,t)}catch(e){if(!r)return null;throw e}}})),I=t(((e,t)=>{let n=F();t.exports=(e,t)=>{let r=n(e,t);return r?r.version:null}})),L=t(((e,t)=>{let n=F();t.exports=(e,t)=>{let r=n(e.trim().replace(/^[=v]+/,``),t);return r?r.version:null}})),ee=t(((e,t)=>{let n=P();t.exports=(e,t,r,i,a)=>{typeof r==`string`&&(a=i,i=r,r=void 0);try{return new n(e instanceof n?e.version:e,r).inc(t,i,a).version}catch{return null}}})),te=t(((e,t)=>{let n=F();t.exports=(e,t)=>{let r=n(e,null,!0),i=n(t,null,!0),a=r.compare(i);if(a===0)return null;let o=a>0,s=o?r:i,c=o?i:r,l=!!s.prerelease.length;if(c.prerelease.length&&!l){if(!c.patch&&!c.minor)return`major`;if(c.compareMain(s)===0)return c.minor&&!c.patch?`minor`:`patch`}let u=l?`pre`:``;return r.major===i.major?r.minor===i.minor?r.patch===i.patch?`prerelease`:u+`patch`:u+`minor`:u+`major`}})),ne=t(((e,t)=>{let n=P();t.exports=(e,t)=>new n(e,t).major})),re=t(((e,t)=>{let n=P();t.exports=(e,t)=>new n(e,t).minor})),ie=t(((e,t)=>{let n=P();t.exports=(e,t)=>new n(e,t).patch})),ae=t(((e,t)=>{let n=F();t.exports=(e,t)=>{let r=n(e,t);return r&&r.prerelease.length?r.prerelease:null}})),R=t(((e,t)=>{let n=P();t.exports=(e,t,r)=>new n(e,r).compare(new n(t,r))})),oe=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(t,e,r)})),se=t(((e,t)=>{let n=R();t.exports=(e,t)=>n(e,t,!0)})),z=t(((e,t)=>{let n=P();t.exports=(e,t,r)=>{let i=new n(e,r),a=new n(t,r);return i.compare(a)||i.compareBuild(a)}})),ce=t(((e,t)=>{let n=z();t.exports=(e,t)=>e.sort((e,r)=>n(e,r,t))})),le=t(((e,t)=>{let n=z();t.exports=(e,t)=>e.sort((e,r)=>n(r,e,t))})),B=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)>0})),V=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)<0})),H=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)===0})),U=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)!==0})),W=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)>=0})),G=t(((e,t)=>{let n=R();t.exports=(e,t,r)=>n(e,t,r)<=0})),K=t(((e,t)=>{let n=H(),r=U(),i=B(),a=W(),o=V(),s=G();t.exports=(e,t,c,l)=>{switch(t){case`===`:return typeof e==`object`&&(e=e.version),typeof c==`object`&&(c=c.version),e===c;case`!==`:return typeof e==`object`&&(e=e.version),typeof c==`object`&&(c=c.version),e!==c;case``:case`=`:case`==`:return n(e,c,l);case`!=`:return r(e,c,l);case`>`:return i(e,c,l);case`>=`:return a(e,c,l);case`<`:return o(e,c,l);case`<=`:return s(e,c,l);default:throw TypeError(`Invalid operator: ${t}`)}}})),ue=t(((e,t)=>{let n=P(),r=F(),{safeRe:i,t:a}=j();t.exports=(e,t)=>{if(e instanceof n)return e;if(typeof e==`number`&&(e=String(e)),typeof e!=`string`)return null;t||={};let o=null;if(!t.rtl)o=e.match(t.includePrerelease?i[a.COERCEFULL]:i[a.COERCE]);else{let n=t.includePrerelease?i[a.COERCERTLFULL]:i[a.COERCERTL],r;for(;(r=n.exec(e))&&(!o||o.index+o[0].length!==e.length);)(!o||r.index+r[0].length!==o.index+o[0].length)&&(o=r),n.lastIndex=r.index+r[1].length+r[2].length;n.lastIndex=-1}if(o===null)return null;let s=o[2],c=o[3]||`0`,l=o[4]||`0`,u=t.includePrerelease&&o[5]?`-${o[5]}`:``,d=t.includePrerelease&&o[6]?`+${o[6]}`:``;return r(`${s}.${c}.${l}${u}${d}`,t)}})),de=t(((e,t)=>{let n=F(),r=k(),i=P(),a=(e,t,n)=>{if(!r.RELEASE_TYPES.includes(t))return null;let i=o(e,n);return i&&s(i,t)},o=(e,t)=>{let r=e instanceof i?e.version:e;return n(r,t)},s=(e,t)=>{if(c(t))return e.version;switch(e.prerelease=[],t){case`major`:e.minor=0,e.patch=0;break;case`minor`:e.patch=0}return e.format()},c=e=>e.startsWith(`pre`);t.exports=a})),fe=t(((e,t)=>{t.exports=class{constructor(){this.max=1e3,this.map=new Map}get(e){let t=this.map.get(e);if(t!==void 0)return this.map.delete(e),this.map.set(e,t),t}delete(e){return this.map.delete(e)}set(e,t){if(!this.delete(e)&&t!==void 0){if(this.map.size>=this.max){let e=this.map.keys().next().value;this.delete(e)}this.map.set(e,t)}return this}}})),q=t(((e,t)=>{let n=/\s+/g;t.exports=class e{constructor(t,r){if(r=i(r),t instanceof e)return t.loose===!!r.loose&&t.includePrerelease===!!r.includePrerelease?t:new e(t.raw,r);if(t instanceof a)return this.raw=t.value,this.set=[[t]],this.formatted=void 0,this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=t.trim().replace(n,` `),this.set=this.raw.split(`||`).map(e=>this.parseRange(e.trim())).filter(e=>e.length),!this.set.length)throw TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let e=this.set[0];if(this.set=this.set.filter(e=>!_(e[0])),this.set.length===0)this.set=[e];else if(this.set.length>1){for(let e of this.set)if(e.length===1&&v(e[0])){this.set=[e];break}}}this.formatted=void 0}get range(){if(this.formatted===void 0){this.formatted=``;for(let e=0;e<this.set.length;e++){e>0&&(this.formatted+=`||`);let t=this.set[e];for(let e=0;e<t.length;e++)e>0&&(this.formatted+=` `),this.formatted+=t[e].toString().trim()}}return this.formatted}format(){return this.range}toString(){return this.range}parseRange(e){e=e.replace(g,``);let t=((this.options.includePrerelease&&m)|(this.options.loose&&h))+`:`+e,n=r.get(t);if(n)return n;let i=this.options.loose,s=i?c[u.HYPHENRANGELOOSE]:c[u.HYPHENRANGE];e=e.replace(s,I(this.options.includePrerelease)),o(`hyphen replace`,e),e=e.replace(c[u.COMPARATORTRIM],d),o(`comparator trim`,e),e=e.replace(c[u.TILDETRIM],f),o(`tilde trim`,e),e=e.replace(c[u.CARETTRIM],p),o(`caret trim`,e);let l=e.split(` `).map(e=>b(e,this.options)).join(` `).split(/\s+/).map(e=>F(e,this.options));i&&(l=l.filter(e=>(o(`loose invalid filter`,e,this.options),!!e.match(c[u.COMPARATORLOOSE])))),o(`range list`,l);let v=new Map,y=l.map(e=>new a(e,this.options));for(let e of y){if(_(e))return[e];v.set(e.value,e)}v.size>1&&v.has(``)&&v.delete(``);let x=[...v.values()];return r.set(t,x),x}intersects(t,n){if(!(t instanceof e))throw TypeError(`a Range is required`);return this.set.some(e=>y(e,n)&&t.set.some(t=>y(t,n)&&e.every(e=>t.every(t=>e.intersects(t,n)))))}test(e){if(!e)return!1;if(typeof e==`string`)try{e=new s(e,this.options)}catch{return!1}for(let t=0;t<this.set.length;t++)if(L(this.set[t],e,this.options))return!0;return!1}};let r=new(fe()),i=M(),a=J(),o=A(),s=P(),{safeRe:c,src:l,t:u,comparatorTrimReplace:d,tildeTrimReplace:f,caretTrimReplace:p}=j(),{FLAG_INCLUDE_PRERELEASE:m,FLAG_LOOSE:h}=k(),g=new RegExp(l[u.BUILD],`g`),_=e=>e.value===`<0.0.0-0`,v=e=>e.value===``,y=(e,t)=>{let n=!0,r=e.slice(),i=r.pop();for(;n&&r.length;)n=r.every(e=>i.intersects(e,t)),i=r.pop();return n},b=(e,t)=>(e=e.replace(c[u.BUILD],``),o(`comp`,e,t),e=T(e,t),o(`caret`,e),e=C(e,t),o(`tildes`,e),e=D(e,t),o(`xrange`,e),e=N(e,t),o(`stars`,e),e),x=e=>!e||e.toLowerCase()===`x`||e===`*`,S=(e,t,n)=>x(e)&&!x(t)||x(t)&&n&&!x(n),C=(e,t)=>e.trim().split(/\s+/).map(e=>w(e,t)).join(` `),w=(e,t)=>{let n=t.loose?c[u.TILDELOOSE]:c[u.TILDE],r=t.includePrerelease?`-0`:``;return e.replace(n,(t,n,i,a,s)=>{o(`tilde`,e,t,n,i,a,s);let c;return x(n)?c=``:x(i)?c=`>=${n}.0.0${r} <${+n+1}.0.0-0`:x(a)?c=`>=${n}.${i}.0${r} <${n}.${+i+1}.0-0`:s?(o(`replaceTilde pr`,s),c=`>=${n}.${i}.${a}-${s} <${n}.${+i+1}.0-0`):c=`>=${n}.${i}.${a} <${n}.${+i+1}.0-0`,o(`tilde return`,c),c})},T=(e,t)=>e.trim().split(/\s+/).map(e=>E(e,t)).join(` `),E=(e,t)=>{o(`caret`,e,t);let n=t.loose?c[u.CARETLOOSE]:c[u.CARET],r=t.includePrerelease?`-0`:``;return e.replace(n,(t,n,i,a,s)=>{o(`caret`,e,t,n,i,a,s);let c;return x(n)?c=``:x(i)?c=`>=${n}.0.0${r} <${+n+1}.0.0-0`:x(a)?c=n===`0`?`>=${n}.${i}.0${r} <${n}.${+i+1}.0-0`:`>=${n}.${i}.0${r} <${+n+1}.0.0-0`:s?(o(`replaceCaret pr`,s),c=n===`0`?i===`0`?`>=${n}.${i}.${a}-${s} <${n}.${i}.${+a+1}-0`:`>=${n}.${i}.${a}-${s} <${n}.${+i+1}.0-0`:`>=${n}.${i}.${a}-${s} <${+n+1}.0.0-0`):(o(`no pr`),c=n===`0`?i===`0`?`>=${n}.${i}.${a} <${n}.${i}.${+a+1}-0`:`>=${n}.${i}.${a} <${n}.${+i+1}.0-0`:`>=${n}.${i}.${a} <${+n+1}.0.0-0`),o(`caret return`,c),c})},D=(e,t)=>(o(`replaceXRanges`,e,t),e.split(/\s+/).map(e=>O(e,t)).join(` `)),O=(e,t)=>{e=e.trim();let n=t.loose?c[u.XRANGELOOSE]:c[u.XRANGE];return e.replace(n,(n,r,i,a,s,c)=>{if(o(`xRange`,e,n,r,i,a,s,c),S(i,a,s))return e;let l=x(i),u=l||x(a),d=u||x(s),f=d;return r===`=`&&f&&(r=``),c=t.includePrerelease?`-0`:``,l?n=r===`>`||r===`<`?`<0.0.0-0`:`*`:r&&f?(u&&(a=0),s=0,r===`>`?(r=`>=`,u?(i=+i+1,a=0,s=0):(a=+a+1,s=0)):r===`<=`&&(r=`<`,u?i=+i+1:a=+a+1),r===`<`&&(c=`-0`),n=`${r+i}.${a}.${s}${c}`):u?n=`>=${i}.0.0${c} <${+i+1}.0.0-0`:d&&(n=`>=${i}.${a}.0${c} <${i}.${+a+1}.0-0`),o(`xRange return`,n),n})},N=(e,t)=>(o(`replaceStars`,e,t),e.trim().replace(c[u.STAR],``)),F=(e,t)=>(o(`replaceGTE0`,e,t),e.trim().replace(c[t.includePrerelease?u.GTE0PRE:u.GTE0],``)),I=e=>(t,n,r,i,a,o,s,c,l,u,d,f)=>(n=x(r)?``:x(i)?`>=${r}.0.0${e?`-0`:``}`:x(a)?`>=${r}.${i}.0${e?`-0`:``}`:o?`>=${n}`:`>=${n}${e?`-0`:``}`,c=x(l)?``:x(u)?`<${+l+1}.0.0-0`:x(d)?`<${l}.${+u+1}.0-0`:f?`<=${l}.${u}.${d}-${f}`:e?`<${l}.${u}.${+d+1}-0`:`<=${c}`,`${n} ${c}`.trim()),L=(e,t,n)=>{for(let n=0;n<e.length;n++)if(!e[n].test(t))return!1;if(t.prerelease.length&&!n.includePrerelease){for(let n=0;n<e.length;n++)if(o(e[n].semver),e[n].semver!==a.ANY&&e[n].semver.prerelease.length>0){let r=e[n].semver;if(r.major===t.major&&r.minor===t.minor&&r.patch===t.patch)return!0}return!1}return!0}})),J=t(((e,t)=>{let n=Symbol(`SemVer ANY`);t.exports=class e{static get ANY(){return n}constructor(t,i){if(i=r(i),t instanceof e){if(t.loose===!!i.loose)return t;t=t.value}t=t.trim().split(/\s+/).join(` `),s(`comparator`,t,i),this.options=i,this.loose=!!i.loose,this.parse(t),this.value=this.semver===n?``:this.operator+this.semver.version,s(`comp`,this)}parse(e){let t=this.options.loose?i[a.COMPARATORLOOSE]:i[a.COMPARATOR],r=e.match(t);if(!r)throw TypeError(`Invalid comparator: ${e}`);this.operator=r[1]===void 0?``:r[1],this.operator===`=`&&(this.operator=``),this.semver=r[2]?new c(r[2],this.options.loose):n}toString(){return this.value}test(e){if(s(`Comparator.test`,e,this.options.loose),this.semver===n||e===n)return!0;if(typeof e==`string`)try{e=new c(e,this.options)}catch{return!1}return o(e,this.operator,this.semver,this.options)}intersects(t,n){if(!(t instanceof e))throw TypeError(`a Comparator is required`);return this.operator===``?this.value===``||new l(t.value,n).test(this.value):t.operator===``?t.value===``||new l(this.value,n).test(t.semver):(n=r(n),n.includePrerelease&&(this.value===`<0.0.0-0`||t.value===`<0.0.0-0`)||!n.includePrerelease&&(this.value.startsWith(`<0.0.0`)||t.value.startsWith(`<0.0.0`))?!1:!!(this.operator.startsWith(`>`)&&t.operator.startsWith(`>`)||this.operator.startsWith(`<`)&&t.operator.startsWith(`<`)||this.semver.version===t.semver.version&&this.operator.includes(`=`)&&t.operator.includes(`=`)||o(this.semver,`<`,t.semver,n)&&this.operator.startsWith(`>`)&&t.operator.startsWith(`<`)||o(this.semver,`>`,t.semver,n)&&this.operator.startsWith(`<`)&&t.operator.startsWith(`>`)))}};let r=M(),{safeRe:i,t:a}=j(),o=K(),s=A(),c=P(),l=q()})),Y=t(((e,t)=>{let n=q();t.exports=(e,t,r)=>{try{t=new n(t,r)}catch{return!1}return t.test(e)}})),pe=t(((e,t)=>{let n=q();t.exports=(e,t)=>new n(e,t).set.map(e=>e.map(e=>e.value).join(` `).trim().split(` `))})),me=t(((e,t)=>{let n=P(),r=q();t.exports=(e,t,i)=>{let a=null,o=null,s=null;try{s=new r(t,i)}catch{return null}return e.forEach(e=>{s.test(e)&&(!a||o.compare(e)===-1)&&(a=e,o=new n(a,i))}),a}})),he=t(((e,t)=>{let n=P(),r=q();t.exports=(e,t,i)=>{let a=null,o=null,s=null;try{s=new r(t,i)}catch{return null}return e.forEach(e=>{s.test(e)&&(!a||o.compare(e)===1)&&(a=e,o=new n(a,i))}),a}})),ge=t(((e,t)=>{let n=P(),r=q(),i=B();t.exports=(e,t)=>{e=new r(e,t);let a=new n(`0.0.0`);if(e.test(a)||(a=new n(`0.0.0-0`),e.test(a)))return a;a=null;for(let t=0;t<e.set.length;++t){let r=e.set[t],o=null;r.forEach(e=>{let t=new n(e.semver.version);switch(e.operator){case`>`:t.prerelease.length===0?t.patch++:t.prerelease.push(0),t.raw=t.format();case``:case`>=`:(!o||i(t,o))&&(o=t);break;case`<`:case`<=`:break;default:throw Error(`Unexpected operation: ${e.operator}`)}}),o&&(!a||i(a,o))&&(a=o)}return a&&e.test(a)?a:null}})),_e=t(((e,t)=>{let n=q();t.exports=(e,t)=>{try{return new n(e,t).range||`*`}catch{return null}}})),X=t(((e,t)=>{let n=P(),r=J(),{ANY:i}=r,a=q(),o=Y(),s=B(),c=V(),l=G(),u=W();t.exports=(e,t,d,f)=>{e=new n(e,f),t=new a(t,f);let p,m,h,g,_;switch(d){case`>`:p=s,m=l,h=c,g=`>`,_=`>=`;break;case`<`:p=c,m=u,h=s,g=`<`,_=`<=`;break;default:throw TypeError(`Must provide a hilo val of "<" or ">"`)}if(o(e,t,f))return!1;for(let n=0;n<t.set.length;++n){let a=t.set[n],o=null,s=null;if(a.forEach(e=>{e.semver===i&&(e=new r(`>=0.0.0`)),o||=e,s||=e,p(e.semver,o.semver,f)?o=e:h(e.semver,s.semver,f)&&(s=e)}),o.operator===g||o.operator===_||(!s.operator||s.operator===g)&&m(e,s.semver)||s.operator===_&&h(e,s.semver))return!1}return!0}})),ve=t(((e,t)=>{let n=X();t.exports=(e,t,r)=>n(e,t,`>`,r)})),ye=t(((e,t)=>{let n=X();t.exports=(e,t,r)=>n(e,t,`<`,r)})),be=t(((e,t)=>{let n=q();t.exports=(e,t,r)=>(e=new n(e,r),t=new n(t,r),e.intersects(t,r))})),xe=t(((e,t)=>{let n=Y(),r=R();t.exports=(e,t,i)=>{let a=[],o=null,s=null,c=e.sort((e,t)=>r(e,t,i));for(let e of c)n(e,t,i)?(s=e,o||=e):(s&&a.push([o,s]),s=null,o=null);o&&a.push([o,null]);let l=[];for(let[e,t]of a)e===t?l.push(e):!t&&e===c[0]?l.push(`*`):t?e===c[0]?l.push(`<=${t}`):l.push(`${e} - ${t}`):l.push(`>=${e}`);let u=l.join(` || `),d=typeof t.raw==`string`?t.raw:String(t);return u.length<d.length?u:t}})),Se=t(((e,t)=>{let n=q(),r=J(),{ANY:i}=r,a=Y(),o=R(),s=(e,t,r={})=>{if(e===t)return!0;e=new n(e,r),t=new n(t,r);let i=!1;OUTER:for(let n of e.set){for(let e of t.set){let t=u(n,e,r);if(i||=t!==null,t)continue OUTER}if(i)return!1}return!0},c=[new r(`>=0.0.0-0`)],l=[new r(`>=0.0.0`)],u=(e,t,n)=>{if(e===t)return!0;if(e.length===1&&e[0].semver===i){if(t.length===1&&t[0].semver===i)return!0;e=n.includePrerelease?c:l}if(t.length===1&&t[0].semver===i){if(n.includePrerelease)return!0;t=l}let r=new Set,s,u;for(let t of e)t.operator===`>`||t.operator===`>=`?s=d(s,t,n):t.operator===`<`||t.operator===`<=`?u=f(u,t,n):r.add(t.semver);if(r.size>1)return null;let p;if(s&&u&&(p=o(s.semver,u.semver,n),p>0||p===0&&(s.operator!==`>=`||u.operator!==`<=`)))return null;for(let e of r){if(s&&!a(e,String(s),n)||u&&!a(e,String(u),n))return null;for(let r of t)if(!a(e,String(r),n))return!1;return!0}let m,h,g,_,v=u&&!n.includePrerelease&&u.semver.prerelease.length?u.semver:!1,y=s&&!n.includePrerelease&&s.semver.prerelease.length?s.semver:!1;v&&v.prerelease.length===1&&u.operator===`<`&&v.prerelease[0]===0&&(v=!1);for(let e of t){if(_=_||e.operator===`>`||e.operator===`>=`,g=g||e.operator===`<`||e.operator===`<=`,s){if(y&&e.semver.prerelease&&e.semver.prerelease.length&&e.semver.major===y.major&&e.semver.minor===y.minor&&e.semver.patch===y.patch&&(y=!1),e.operator===`>`||e.operator===`>=`){if(m=d(s,e,n),m===e&&m!==s)return!1}else if(s.operator===`>=`&&!e.test(s.semver))return!1}if(u){if(v&&e.semver.prerelease&&e.semver.prerelease.length&&e.semver.major===v.major&&e.semver.minor===v.minor&&e.semver.patch===v.patch&&(v=!1),e.operator===`<`||e.operator===`<=`){if(h=f(u,e,n),h===e&&h!==u)return!1}else if(u.operator===`<=`&&!e.test(u.semver))return!1}if(!e.operator&&(u||s)&&p!==0)return!1}return!(s&&g&&!u&&p!==0||u&&_&&!s&&p!==0||y||v)},d=(e,t,n)=>{if(!e)return t;let r=o(e.semver,t.semver,n);return r>0?e:r<0||t.operator===`>`&&e.operator===`>=`?t:e},f=(e,t,n)=>{if(!e)return t;let r=o(e.semver,t.semver,n);return r<0?e:r>0||t.operator===`<`&&e.operator===`<=`?t:e};t.exports=s})),Z=e(t(((e,t)=>{let n=j(),r=k(),i=P(),a=N();t.exports={parse:F(),valid:I(),clean:L(),inc:ee(),diff:te(),major:ne(),minor:re(),patch:ie(),prerelease:ae(),compare:R(),rcompare:oe(),compareLoose:se(),compareBuild:z(),sort:ce(),rsort:le(),gt:B(),lt:V(),eq:H(),neq:U(),gte:W(),lte:G(),cmp:K(),coerce:ue(),truncate:de(),Comparator:J(),Range:q(),satisfies:Y(),toComparators:pe(),maxSatisfying:me(),minSatisfying:he(),minVersion:ge(),validRange:_e(),outside:X(),gtr:ve(),ltr:ye(),intersects:be(),simplifyRange:xe(),subset:Se(),SemVer:i,re:n.re,src:n.src,tokens:n.t,SEMVER_SPEC_VERSION:r.SEMVER_SPEC_VERSION,RELEASE_TYPES:r.RELEASE_TYPES,compareIdentifiers:a.compareIdentifiers,rcompareIdentifiers:a.rcompareIdentifiers}}))(),1);async function Ce(){let e=[process.env.npm_execpath,l(c(process.execPath),`node_modules/npm/bin/npm-cli.js`),l(c(process.execPath),`../lib/node_modules/npm/bin/npm-cli.js`),...(process.env.PATH??``).split(s).map(e=>l(e,`node_modules/npm/bin/npm-cli.js`))];for(let t of e)if(t?.endsWith(`npm-cli.js`))try{return await f(t),{command:process.execPath,prefix:[t]}}catch{}if(process.platform!==`win32`)return{command:`npm`,prefix:[]};throw new n(`UPDATE_NPM_REQUIRED`,`强制更新需要 npm;请重新安装包含 npm 的 Node.js。`,503)}async function Q(e,t=3e4){let{command:r,prefix:i}=await Ce();return new Promise((a,s)=>{let c=o(r,[...i,...e],{stdio:[`ignore`,`pipe`,`pipe`],windowsHide:!0}),l=``,u=!1,d=!1,f=!1,p=()=>{f=!0,c.kill(`SIGTERM`)};process.once(`SIGINT`,p),process.once(`SIGTERM`,p);let m=setTimeout(()=>{d=!0,c.kill(`SIGKILL`)},t);c.stdout.setEncoding(`utf8`),c.stdout.on(`data`,e=>{l+=e,l.length>2097152&&(u=!0,c.kill(`SIGKILL`))}),c.stderr.resume();let h=()=>{clearTimeout(m),process.removeListener(`SIGINT`,p),process.removeListener(`SIGTERM`,p)};c.on(`error`,()=>{h(),s(new n(`UPDATE_NPM_REQUIRED`,`无法启动 npm,强制更新检查未完成。`,503))}),c.on(`close`,e=>{h(),f?s(new n(`UPDATE_INTERRUPTED`,`强制更新已中断,原命令未执行。`,503)):d||u||e!==0?s(new n(`UPDATE_NPM_FAILED`,`npm 请求失败或超时,原命令未执行。`,503)):a(l.trim())})})}const $=[`--offline=false`,`--prefer-offline=false`,`--prefer-online`,`--fetch-retries=0`,`--fetch-timeout=10000`];async function we(e){let t=await m(l(x(),`share-pages-update-check-`));try{return await Q([`view`,`share-pages@latest`,`--json`,`--registry`,e,`--workspaces=false`,`--cache`,t,...$])}finally{await v(t,{recursive:!0,force:!0})}}async function Te(e,t,r){return new Promise((i,a)=>{let s=o(process.execPath,[e,...t],{stdio:`inherit`,env:{...process.env,SHARE_PAGES_UPDATE_HANDOFF_VERSION:r}}),c=()=>s.kill(`SIGINT`),l=()=>s.kill(`SIGTERM`);process.on(`SIGINT`,c),process.on(`SIGTERM`,l);let u=()=>{process.removeListener(`SIGINT`,c),process.removeListener(`SIGTERM`,l)};s.on(`error`,()=>{u(),a(new n(`UPDATE_EXEC_FAILED`,`新版 CLI 启动失败,原命令未执行。`,503))}),s.on(`close`,(e,t)=>{u(),i(e??(t===`SIGINT`?130:t===`SIGTERM`?143:5))})})}async function Ee(e,t){try{let n=l(e,`node_modules/share-pages`),r=JSON.parse(await h(l(n,`package.json`),`utf8`));if(r.name!==`share-pages`||r.version!==t||r.bin?.[`share-pages`]!==`dist/index.mjs`)return;let i=l(n,`dist/index.mjs`);return(await h(i)).length?i:void 0}catch{return}}function De(e,t){let n=process.env.XDG_CACHE_HOME??(process.platform===`win32`?process.env.LOCALAPPDATA:void 0)??l(b(),`.cache`),r=u(`sha256`).update(e).digest(`hex`).slice(0,24);return l(n,`share-pages`,`cli`,r,t)}async function Oe(e,t){try{for(let n of await g(e)){if(!/^ready-[a-f0-9-]+$/.test(n))continue;let r=await Ee(l(e,n),t);if(r)return r}}catch(e){if(e.code!==`ENOENT`)throw e}}async function ke(e,t){let r=De(e,t),i;try{let n=await Oe(r,t);if(n)return n;if(await p(r,{recursive:!0,mode:448}),i=await m(l(r,`install-`)),await y(l(i,`package.json`),JSON.stringify({private:!0}),{mode:384}),await Q([`install`,`share-pages@${t}`,`--prefix`,i,`--registry`,e,`--global=false`,`--workspaces=false`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--save-exact`,`--package-lock=true`,`--engine-strict`,...$],12e4),!await Ee(i,t))throw Error(`Invalid installed package`);let a=l(r,`ready-${d()}`);return await _(i,a),l(a,`node_modules/share-pages/dist/index.mjs`)}catch(e){throw e instanceof n&&e.code===`UPDATE_INTERRUPTED`?e:new n(`UPDATE_INSTALL_FAILED`,`新版 CLI 安装失败,原命令未执行。`,503)}finally{i&&await v(i,{recursive:!0,force:!0})}}async function Ae(e=process.argv.slice(2),t=a,r={npm:Q,latest:we,install:ke,execute:Te,note:e=>process.stderr.write(`${e}\n`)},i){let o,s,c;try{o=(await r.npm([`config`,`get`,`registry`,`--workspaces=false`])).trim();let e=new URL(o);if(![`https:`,`http:`].includes(e.protocol))throw Error(`Invalid registry`);if(c=JSON.parse(await r.latest(o)),c.name!==`share-pages`||!c.version||!Z.default.valid(c.version))throw Error(`Invalid registry response`);if(c.engines?.node&&(typeof c.engines.node!=`string`||!Z.default.validRange(c.engines.node)))throw Error(`Invalid Node engine range`);s=c.version}catch(e){throw e instanceof n&&e.code===`UPDATE_INTERRUPTED`?e:new n(`UPDATE_CHECK_FAILED`,`无法检查 CLI 最新版本,原命令未执行。`,503)}if(i&&t!==i)throw new n(`UPDATE_VERSION_MISMATCH`,`新版 CLI 的实际版本与安装版本不一致,原命令未执行。`,503);if(c.engines?.node&&!Z.default.satisfies(process.versions.node,c.engines.node))throw new n(`UPDATE_NODE_REQUIRED`,`最新 CLI ${s} 要求 Node.js ${c.engines.node};请先升级 Node.js。`,503);if(!Z.default.gt(s,t))return;let l=e.indexOf(`--`),u=l<0?e:e.slice(0,l);!u.includes(`--quiet`)&&!u.includes(`-q`)&&r.note(`正在强制更新 share-pages:${t} → ${s}`);let d=await r.install(o,s);return r.execute(d,e,s)}process.stdout.on(`error`,e=>{if(e.code===`EPIPE`)process.exitCode=0;else throw e});try{let e=process.env.SHARE_PAGES_UPDATE_HANDOFF_VERSION;delete process.env.SHARE_PAGES_UPDATE_HANDOFF_VERSION;let t=await Ae(void 0,void 0,void 0,e);if(t!==void 0)process.exitCode=t;else{let{buildCLI:e}=await import(`./program-DJaWAEf5.mjs`);await e().parseAsync()}}catch(e){if(w(e))process.exitCode=0;else{let t=T(e);D(t,O(process.argv.slice(2))),process.exitCode=E(t)}}export{};