@sfmc-bds/bds-tools 0.2.0-beta.8 → 0.2.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 (114) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +1 -1
  3. package/dist/bds-manager.d.ts +16 -6
  4. package/dist/bds-manager.d.ts.map +1 -1
  5. package/dist/bds-manager.js +59 -66
  6. package/dist/bds-manager.js.map +2 -2
  7. package/dist/changelog.d.ts +11 -7
  8. package/dist/changelog.d.ts.map +1 -1
  9. package/dist/changelog.js +60 -34
  10. package/dist/changelog.js.map +2 -2
  11. package/dist/check-update.d.ts.map +1 -1
  12. package/dist/check-update.js +59 -23
  13. package/dist/check-update.js.map +2 -2
  14. package/dist/cli-pack-manager.js +11 -1
  15. package/dist/cli-pack-manager.js.map +2 -2
  16. package/dist/dependency-negotiator.d.ts +73 -0
  17. package/dist/dependency-negotiator.d.ts.map +1 -0
  18. package/dist/dependency-negotiator.js +151 -0
  19. package/dist/dependency-negotiator.js.map +7 -0
  20. package/dist/fsx.d.ts +17 -14
  21. package/dist/fsx.d.ts.map +1 -1
  22. package/dist/fsx.js +67 -19
  23. package/dist/fsx.js.map +2 -2
  24. package/dist/host-platform.d.ts +25 -0
  25. package/dist/host-platform.d.ts.map +1 -0
  26. package/dist/host-platform.js +50 -0
  27. package/dist/host-platform.js.map +7 -0
  28. package/dist/http.d.ts +49 -11
  29. package/dist/http.d.ts.map +1 -1
  30. package/dist/http.js.map +2 -2
  31. package/dist/level-dat.d.ts +105 -0
  32. package/dist/level-dat.d.ts.map +1 -0
  33. package/dist/level-dat.js +490 -0
  34. package/dist/level-dat.js.map +7 -0
  35. package/dist/pack-manager.d.ts +41 -34
  36. package/dist/pack-manager.d.ts.map +1 -1
  37. package/dist/pack-manager.js +79 -25
  38. package/dist/pack-manager.js.map +2 -2
  39. package/dist/pack-update/bindings.d.ts +16 -0
  40. package/dist/pack-update/bindings.d.ts.map +1 -0
  41. package/dist/pack-update/bindings.js +69 -0
  42. package/dist/pack-update/bindings.js.map +7 -0
  43. package/dist/pack-update/config.d.ts +16 -0
  44. package/dist/pack-update/config.d.ts.map +1 -0
  45. package/dist/pack-update/config.js +146 -0
  46. package/dist/pack-update/config.js.map +7 -0
  47. package/dist/pack-update/deps.d.ts +28 -0
  48. package/dist/pack-update/deps.d.ts.map +1 -0
  49. package/dist/pack-update/deps.js +20 -0
  50. package/dist/pack-update/deps.js.map +7 -0
  51. package/dist/pack-update/index.d.ts +55 -0
  52. package/dist/pack-update/index.d.ts.map +1 -0
  53. package/dist/pack-update/index.js +72 -0
  54. package/dist/pack-update/index.js.map +7 -0
  55. package/dist/pack-update/providers/curseforge.d.ts +23 -0
  56. package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
  57. package/dist/pack-update/providers/curseforge.js +229 -0
  58. package/dist/pack-update/providers/curseforge.js.map +7 -0
  59. package/dist/pack-update/providers/index.d.ts +16 -0
  60. package/dist/pack-update/providers/index.d.ts.map +1 -0
  61. package/dist/pack-update/providers/index.js +37 -0
  62. package/dist/pack-update/providers/index.js.map +7 -0
  63. package/dist/pack-update/service.d.ts +28 -0
  64. package/dist/pack-update/service.d.ts.map +1 -0
  65. package/dist/pack-update/service.js +570 -0
  66. package/dist/pack-update/service.js.map +7 -0
  67. package/dist/pack-update/types.d.ts +126 -0
  68. package/dist/pack-update/types.d.ts.map +1 -0
  69. package/dist/pack-update/types.js +8 -0
  70. package/dist/pack-update/types.js.map +7 -0
  71. package/dist/pack-update/version-policy.d.ts +81 -0
  72. package/dist/pack-update/version-policy.d.ts.map +1 -0
  73. package/dist/pack-update/version-policy.js +210 -0
  74. package/dist/pack-update/version-policy.js.map +7 -0
  75. package/dist/paths.d.ts +1 -1
  76. package/dist/paths.d.ts.map +1 -1
  77. package/dist/paths.js +3 -5
  78. package/dist/paths.js.map +2 -2
  79. package/dist/process-probe.d.ts +34 -0
  80. package/dist/process-probe.d.ts.map +1 -0
  81. package/dist/process-probe.js +152 -0
  82. package/dist/process-probe.js.map +7 -0
  83. package/dist/qq-events-notify.d.ts +16 -0
  84. package/dist/qq-events-notify.d.ts.map +1 -0
  85. package/dist/qq-events-notify.js +70 -0
  86. package/dist/qq-events-notify.js.map +7 -0
  87. package/dist/qqutil.d.ts +10 -5
  88. package/dist/qqutil.d.ts.map +1 -1
  89. package/dist/qqutil.js +53 -10
  90. package/dist/qqutil.js.map +2 -2
  91. package/dist/rollback.d.ts.map +1 -1
  92. package/dist/rollback.js +2 -2
  93. package/dist/rollback.js.map +2 -2
  94. package/dist/server-properties-i18n.d.ts +17 -0
  95. package/dist/server-properties-i18n.d.ts.map +1 -0
  96. package/dist/server-properties-i18n.js +201 -0
  97. package/dist/server-properties-i18n.js.map +7 -0
  98. package/dist/server-properties.d.ts +25 -0
  99. package/dist/server-properties.d.ts.map +1 -1
  100. package/dist/server-properties.js +141 -1
  101. package/dist/server-properties.js.map +2 -2
  102. package/dist/types.d.ts +1 -0
  103. package/dist/types.d.ts.map +1 -1
  104. package/dist/upstream.d.ts +18 -9
  105. package/dist/upstream.d.ts.map +1 -1
  106. package/dist/upstream.js +8 -7
  107. package/dist/upstream.js.map +2 -2
  108. package/dist/version.js +2 -2
  109. package/dist/version.js.map +2 -2
  110. package/dist/world-packs.d.ts +108 -8
  111. package/dist/world-packs.d.ts.map +1 -1
  112. package/dist/world-packs.js +245 -12
  113. package/dist/world-packs.js.map +3 -3
  114. package/package.json +24 -17
@@ -0,0 +1,151 @@
1
+ const NATIVE_BEDROCK_SCRIPT_MODULES = /* @__PURE__ */ new Set([
2
+ "@minecraft/server",
3
+ "@minecraft/server-ui",
4
+ "@minecraft/server-net",
5
+ "@minecraft/server-admin",
6
+ "@minecraft/server-gametest",
7
+ "@minecraft/server-editor",
8
+ "@minecraft/server-graphics",
9
+ "@minecraft/diagnostics",
10
+ "@minecraft/debug-utilities",
11
+ "@minecraft/common"
12
+ ]);
13
+ const BASELINE_BEDROCK_DEPENDENCIES = [
14
+ { module_name: "@minecraft/server", version: "1.18.0" },
15
+ { module_name: "@minecraft/server-net", version: "1.0.0-beta" },
16
+ { module_name: "@minecraft/server-ui", version: "1.3.0" },
17
+ { module_name: "@minecraft/server-admin", version: "1.0.0-beta" },
18
+ { module_name: "@minecraft/diagnostics", version: "1.0.0-beta" }
19
+ ];
20
+ function cleanBedrockVersion(raw) {
21
+ if (Array.isArray(raw)) return raw.join(".");
22
+ if (!raw || typeof raw !== "string") return "1.0.0";
23
+ let v = raw.trim();
24
+ if (v.toLowerCase() === "beta") return "beta";
25
+ v = v.replace(/^[>=~^<v\s]+/, "");
26
+ const spaceIdx = v.indexOf(" ");
27
+ if (spaceIdx > 0) v = v.slice(0, spaceIdx);
28
+ v = v.replace(/(-beta)\..*$/i, "$1");
29
+ return v || "1.0.0";
30
+ }
31
+ function parseBedrockVersion(raw) {
32
+ const cleaned = cleanBedrockVersion(raw);
33
+ const match = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?/.exec(cleaned);
34
+ if (!match) {
35
+ return { major: 1, minor: 0, patch: 0, prerelease: null };
36
+ }
37
+ return {
38
+ major: Number(match[1] || 0),
39
+ minor: Number(match[2] || 0),
40
+ patch: Number(match[3] || 0),
41
+ prerelease: match[4] ?? null
42
+ };
43
+ }
44
+ function compareBedrockVersion(a, b) {
45
+ const normA = cleanBedrockVersion(a);
46
+ const normB = cleanBedrockVersion(b);
47
+ const isBetaA = normA.toLowerCase() === "beta";
48
+ const isBetaB = normB.toLowerCase() === "beta";
49
+ if (isBetaA && isBetaB) return 0;
50
+ if (isBetaA) return 1;
51
+ if (isBetaB) return -1;
52
+ const pa = parseBedrockVersion(a);
53
+ const pb = parseBedrockVersion(b);
54
+ if (pa.major !== pb.major) return pa.major - pb.major;
55
+ if (pa.minor !== pb.minor) return pa.minor - pb.minor;
56
+ if (pa.patch !== pb.patch) return pa.patch - pb.patch;
57
+ if (pa.prerelease === null && pb.prerelease === null) return 0;
58
+ if (pa.prerelease === null && pb.prerelease !== null) return 1;
59
+ if (pa.prerelease !== null && pb.prerelease === null) return -1;
60
+ return (pa.prerelease ?? "").localeCompare(pb.prerelease ?? "");
61
+ }
62
+ function isGametestBetaRequired(dep) {
63
+ const mod = dep.module_name ?? "";
64
+ const ver = cleanBedrockVersion(dep.version).toLowerCase();
65
+ if (mod === "@minecraft/server-gametest" || mod === "@minecraft/server-editor") return true;
66
+ if (mod === "@minecraft/server-net" || mod === "@minecraft/server-admin") return false;
67
+ if ((mod === "@minecraft/server" || mod === "@minecraft/server-ui") && ver.includes("beta")) {
68
+ return true;
69
+ }
70
+ return false;
71
+ }
72
+ function negotiateBedrockDependencies(baseline = BASELINE_BEDROCK_DEPENDENCIES, moduleRequirements = []) {
73
+ const order = [];
74
+ const map = /* @__PURE__ */ new Map();
75
+ for (const b of baseline) {
76
+ if (!b.module_name) continue;
77
+ order.push(b.module_name);
78
+ map.set(b.module_name, {
79
+ version: cleanBedrockVersion(b.version),
80
+ uuid: b.uuid,
81
+ requestedBy: ["__sfmc_baseline__"]
82
+ });
83
+ }
84
+ for (const mod of moduleRequirements) {
85
+ for (const dep of mod.dependencies) {
86
+ if (!dep.module_name) continue;
87
+ const modName = dep.module_name;
88
+ const reqVer = cleanBedrockVersion(dep.version);
89
+ if (!map.has(modName)) {
90
+ order.push(modName);
91
+ map.set(modName, {
92
+ version: reqVer,
93
+ uuid: dep.uuid,
94
+ requestedBy: [mod.folderId],
95
+ promotedFrom: void 0
96
+ });
97
+ continue;
98
+ }
99
+ const existing = map.get(modName);
100
+ if (compareBedrockVersion(reqVer, existing.version) > 0) {
101
+ map.set(modName, {
102
+ version: reqVer,
103
+ uuid: dep.uuid ?? existing.uuid,
104
+ requestedBy: [mod.folderId],
105
+ promotedFrom: existing.promotedFrom ?? existing.version
106
+ });
107
+ } else if (compareBedrockVersion(reqVer, existing.version) === 0) {
108
+ if (!existing.requestedBy.includes(mod.folderId)) {
109
+ existing.requestedBy.push(mod.folderId);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ const promotions = [];
115
+ const finalDeps = [];
116
+ let hasBetaApis = false;
117
+ for (const name of order) {
118
+ const entry = map.get(name);
119
+ const dep = {
120
+ module_name: name,
121
+ version: entry.version,
122
+ ...entry.uuid ? { uuid: entry.uuid } : {}
123
+ };
124
+ finalDeps.push(dep);
125
+ if (entry.promotedFrom && entry.promotedFrom !== entry.version) {
126
+ promotions.push({
127
+ moduleName: name,
128
+ from: entry.promotedFrom,
129
+ to: entry.version,
130
+ requestedBy: entry.requestedBy.filter((x) => x !== "__sfmc_baseline__")
131
+ });
132
+ }
133
+ if (isGametestBetaRequired(dep)) {
134
+ hasBetaApis = true;
135
+ }
136
+ }
137
+ return {
138
+ dependencies: finalDeps,
139
+ promotions,
140
+ hasBetaApis
141
+ };
142
+ }
143
+ export {
144
+ BASELINE_BEDROCK_DEPENDENCIES,
145
+ NATIVE_BEDROCK_SCRIPT_MODULES,
146
+ cleanBedrockVersion,
147
+ compareBedrockVersion,
148
+ isGametestBetaRequired,
149
+ negotiateBedrockDependencies
150
+ };
151
+ //# sourceMappingURL=dependency-negotiator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dependency-negotiator.ts"],
4
+ "sourcesContent": ["/**\n * dependency-negotiator.ts \u2014 Bedrock \u539F\u751F\u6A21\u5757\u4F9D\u8D56\u7248\u672C\u89E3\u6790\u4E0E\u52A8\u6001\u534F\u5546\u5668\n *\n * \u804C\u8D23\uFF1A\n * 1. Bedrock \u539F\u751F\u6A21\u5757\u7248\u672C\uFF08SemVer / Beta / Preview\uFF09\u5BF9\u6BD4\u7B97\u6CD5\uFF1B\n * 2. \u805A\u5408\u5E73\u53F0\u9ED8\u8BA4\u57FA\u51C6\u4F9D\u8D56\u4E0E\u5404\u4E1A\u52A1\u6A21\u5757\u58F0\u660E\u7684 Minecraft \u4F9D\u8D56\u9700\u6C42\uFF1B\n * 3. \u52A8\u6001\u63D0\u5347\u805A\u5408\u884C\u4E3A\u5305 manifest.json \u4E2D\u7684 dependencies\uFF1B\n * 4. \u5224\u5B9A\u534F\u5546\u540E\u662F\u5426\u5305\u542B\u9700\u8981\u5B58\u6863\u5F00\u542F\u6D4B\u8BD5\u7248\u73A9\u6CD5\uFF08Beta APIs / gametest\uFF09\u7684\u6A21\u5757\u3002\n */\n\nexport interface PackManifestDependency {\n module_name?: string | undefined;\n version?: string | number[] | undefined;\n uuid?: string | undefined;\n}\n\nexport interface ModuleDeclaredDependencies {\n folderId: string;\n dependencies: PackManifestDependency[];\n}\n\nexport interface DependencyPromotion {\n moduleName: string;\n from: string;\n to: string;\n requestedBy: string[];\n}\n\nexport interface NegotiatedDependenciesResult {\n /** \u534F\u5546\u5B8C\u6210\u540E\u7684\u6700\u7EC8 dependencies \u5217\u8868 */\n dependencies: PackManifestDependency[];\n /** \u672C\u6B21\u534F\u5546\u53D1\u751F\u7684\u7248\u672C\u63D0\u5347\u8BB0\u5F55\uFF08\u4FBF\u4E8E\u65E5\u5FD7\u5C55\u793A\uFF09 */\n promotions: DependencyPromotion[];\n /** \u662F\u5426\u5F15\u5165\u4E86\u9700\u8981 level.dat \u5F00\u542F Beta APIs (gametest = 1b) \u7684\u6A21\u5757 */\n hasBetaApis: boolean;\n}\n\n/** Bedrock \u5F15\u64CE\u539F\u751F\u5185\u7F6E\u7684 Script API \u6A21\u5757\u96C6\u5408\uFF08\u6392\u9664\u7EAF npm \u7C7B\u578B/\u6570\u636E\u5305\u5982 vanilla-data, math\uFF09 */\nexport const NATIVE_BEDROCK_SCRIPT_MODULES = new Set<string>([\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-net\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-editor\",\n \"@minecraft/server-graphics\",\n \"@minecraft/diagnostics\",\n \"@minecraft/debug-utilities\",\n \"@minecraft/common\",\n]);\n\n/** SFMC \u5E73\u53F0\u5408\u6210 BP \u7684\u9ED8\u8BA4\u57FA\u51C6\u4F9D\u8D56\uFF08\u7A33\u5B9A\u4FDD\u5E95\uFF09 */\nexport const BASELINE_BEDROCK_DEPENDENCIES: PackManifestDependency[] = [\n { module_name: \"@minecraft/server\", version: \"1.18.0\" },\n { module_name: \"@minecraft/server-net\", version: \"1.0.0-beta\" },\n { module_name: \"@minecraft/server-ui\", version: \"1.3.0\" },\n { module_name: \"@minecraft/server-admin\", version: \"1.0.0-beta\" },\n { module_name: \"@minecraft/diagnostics\", version: \"1.0.0-beta\" },\n];\n\n/**\n * \u6E05\u7406\u5E76\u89C4\u8303\u5316\u7248\u672C\u53F7\u5B57\u7B26\u4E32\uFF08\u53BB\u9664 npm range \u524D\u7F00\uFF0C\u5982 `^2.0.0-beta` \u2192 `2.0.0-beta`\uFF09\u3002\n */\nexport function cleanBedrockVersion(raw: string | number[] | undefined): string {\n if (Array.isArray(raw)) return raw.join(\".\");\n if (!raw || typeof raw !== \"string\") return \"1.0.0\";\n let v = raw.trim();\n if (v.toLowerCase() === \"beta\") return \"beta\";\n // \u53BB\u9664 >=, <=, ^, ~, >, <, =, v\n v = v.replace(/^[>=~^<v\\s]+/, \"\");\n // \u82E5\u5305\u542B\u7A7A\u683C\u5206\u9694\u7684\u533A\u95F4\uFF08\u5982 \">=1.0.0 <2.0.0\"\uFF09\uFF0C\u53D6\u524D\u7F00\n const spaceIdx = v.indexOf(\" \");\n if (spaceIdx > 0) v = v.slice(0, spaceIdx);\n // \u82E5\u5305\u542B npm preview \u6269\u5C55\u53D1\u5E03\u540E\u7F00\uFF08\u5982 2.10.0-beta.1.26.40-preview.30\uFF09\uFF0C\u89C4\u6574\u4E3A\u6807\u51C6 SemVer prerelease\uFF08\u5982 2.10.0-beta\uFF09\n v = v.replace(/(-beta)\\..*$/i, \"$1\");\n return v || \"1.0.0\";\n}\n\ninterface ParsedBedrockVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease: string | null;\n}\n\nfunction parseBedrockVersion(raw: string): ParsedBedrockVersion {\n const cleaned = cleanBedrockVersion(raw);\n const match = /^(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-([0-9A-Za-z.-]+))?/.exec(cleaned);\n if (!match) {\n return { major: 1, minor: 0, patch: 0, prerelease: null };\n }\n return {\n major: Number(match[1] || 0),\n minor: Number(match[2] || 0),\n patch: Number(match[3] || 0),\n prerelease: match[4] ?? null,\n };\n}\n\n/**\n * \u6BD4\u8F83\u4E24\u4E2A Bedrock \u7248\u672C\u53F7\uFF1A\n * a > b \u8FD4\u56DE\u6B63\u6570\uFF1Ba < b \u8FD4\u56DE\u8D1F\u6570\uFF1Ba === b \u8FD4\u56DE 0\u3002\n *\n * \u6838\u5FC3\u89C4\u5219\uFF1A\n * 1. \"beta\" \u4E3A\u9884\u89C8/\u6D4B\u8BD5\u8F68\u9876\u7EA7\uFF0C\u9AD8\u4E8E\u4EFB\u4F55\u7EAF\u6570\u5B57\u7A33\u5B9A\u7248\uFF1B\n * 2. \u4F18\u5148\u6BD4\u8F83 major, minor, patch \u6570\u5B57\uFF1B\n * 3. \u5728\u540C\u4E00\u5927\u7248\u672C\u6216\u4F4E\u7248\u672C\u4E0B\uFF1A\n * - \u82E5 majorA > majorB\uFF08\u4F8B\u5982 2.0.0 vs 1.3.0\uFF09\uFF0Cmajor \u9AD8\u8005\u80DC\u51FA\uFF1B\n * - \u82E5 major/minor/patch \u5747\u76F8\u540C\uFF0C\u6B63\u5F0F\u7248\u4F18\u5148\u4E8E prerelease\uFF1B\n * - \u82E5\u4E24\u8005\u5747\u4E3A prerelease\uFF0C\u6309\u5B57\u5178\u5E8F\u6BD4\u8F83\u3002\n */\nexport function compareBedrockVersion(a: string, b: string): number {\n const normA = cleanBedrockVersion(a);\n const normB = cleanBedrockVersion(b);\n const isBetaA = normA.toLowerCase() === \"beta\";\n const isBetaB = normB.toLowerCase() === \"beta\";\n if (isBetaA && isBetaB) return 0;\n if (isBetaA) return 1;\n if (isBetaB) return -1;\n\n const pa = parseBedrockVersion(a);\n const pb = parseBedrockVersion(b);\n\n if (pa.major !== pb.major) return pa.major - pb.major;\n if (pa.minor !== pb.minor) return pa.minor - pb.minor;\n if (pa.patch !== pb.patch) return pa.patch - pb.patch;\n\n if (pa.prerelease === null && pb.prerelease === null) return 0;\n // \u76F8\u540C version \u9AA8\u67B6\u4E0B\uFF1A\u6B63\u5F0F\u7248\uFF08null\uFF09 > \u6D4B\u8BD5\u7248\uFF08prerelease\uFF09\n if (pa.prerelease === null && pb.prerelease !== null) return 1;\n if (pa.prerelease !== null && pb.prerelease === null) return -1;\n\n // \u5747\u4E3A prerelease \u65F6\u6BD4\u8F83\n return (pa.prerelease ?? \"\").localeCompare(pb.prerelease ?? \"\");\n}\n\n/**\n * \u5224\u5B9A\u4E00\u4E2A\u4F9D\u8D56\u9879\u662F\u5426\u771F\u6B63\u9700\u8981\u4E16\u754C\u5B58\u6863\u5F00\u542F\u6D4B\u8BD5\u7248\u73A9\u6CD5\uFF08Beta APIs / gametest\uFF09\u3002\n * \u6CE8\u610F\uFF1A@minecraft/server-net \u4E0E @minecraft/server-admin \u867D\u5E26 -beta\uFF0C\u4F46\u5C5E\u4E8E permissions.json \u6A21\u5757\u6743\u9650\uFF0C\n * \u4E0D\u9700\u8981 level.dat \u7684 gametest \u5B9E\u9A8C\u5F00\u5173\u3002\n */\nexport function isGametestBetaRequired(dep: PackManifestDependency): boolean {\n const mod = dep.module_name ?? \"\";\n const ver = cleanBedrockVersion(dep.version).toLowerCase();\n if (mod === \"@minecraft/server-gametest\" || mod === \"@minecraft/server-editor\") return true;\n if (mod === \"@minecraft/server-net\" || mod === \"@minecraft/server-admin\") return false;\n if ((mod === \"@minecraft/server\" || mod === \"@minecraft/server-ui\") && ver.includes(\"beta\")) {\n return true;\n }\n return false;\n}\n\n/**\n * \u52A8\u6001\u534F\u5546 Bedrock \u539F\u751F\u6A21\u5757\u4F9D\u8D56\u3002\n *\n * \u7B97\u6CD5\uFF1A\n * 1. \u4EE5 baseline \u4E3A\u57FA\u51C6\u5EFA\u7ACB\u6A21\u5757\u7D22\u5F15\u8868\uFF1B\n * 2. \u904D\u5386\u6240\u6709\u5DF2\u542F\u7528\u6A21\u5757\u58F0\u660E\u7684 dependencies\uFF1B\n * 3. \u82E5\u6A21\u5757\u5BF9\u67D0\u539F\u751F\u6A21\u5757\u63D0\u51FA\u4E86\u66F4\u9AD8\u7684\u7248\u672C\u9700\u6C42\uFF0C\u52A8\u6001\u63D0\u5347\uFF08promote\uFF09\u8BE5\u4F9D\u8D56\u7684\u7248\u672C\uFF0C\u5E76\u8BB0\u5F55\u63D0\u8BAE\u6A21\u7EC4\uFF1B\n * 4. \u7EDF\u8BA1\u662F\u5426\u5F15\u5165\u4E86\u9700\u8981\u6D4B\u8BD5\u73A9\u6CD5\u7684 Beta API\u3002\n *\n * @param baseline \u57FA\u51C6\u4F9D\u8D56\u5217\u8868\uFF08\u7F3A\u7701\u4F7F\u7528 BASELINE_BEDROCK_DEPENDENCIES\uFF09\n * @param moduleRequirements \u5404\u5DF2\u542F\u7528\u6A21\u5757\u58F0\u660E\u7684\u4F9D\u8D56\u9879\u5217\u8868\n */\nexport function negotiateBedrockDependencies(\n baseline: PackManifestDependency[] = BASELINE_BEDROCK_DEPENDENCIES,\n moduleRequirements: ModuleDeclaredDependencies[] = []\n): NegotiatedDependenciesResult {\n // \u5EFA\u7ACB\u6A21\u5757\u6620\u5C04\u8868\uFF0C\u4FDD\u6301\u57FA\u51C6\u4F9D\u8D56\u7684\u539F\u6709\u987A\u5E8F\n const order: string[] = [];\n const map = new Map<\n string,\n {\n version: string;\n uuid?: string | undefined;\n requestedBy: string[];\n promotedFrom?: string | undefined;\n }\n >();\n\n for (const b of baseline) {\n if (!b.module_name) continue;\n order.push(b.module_name);\n map.set(b.module_name, {\n version: cleanBedrockVersion(b.version),\n uuid: b.uuid,\n requestedBy: [\"__sfmc_baseline__\"],\n });\n }\n\n for (const mod of moduleRequirements) {\n for (const dep of mod.dependencies) {\n if (!dep.module_name) continue;\n const modName = dep.module_name;\n const reqVer = cleanBedrockVersion(dep.version);\n\n if (!map.has(modName)) {\n order.push(modName);\n map.set(modName, {\n version: reqVer,\n uuid: dep.uuid,\n requestedBy: [mod.folderId],\n promotedFrom: undefined,\n });\n continue;\n }\n\n const existing = map.get(modName)!;\n if (compareBedrockVersion(reqVer, existing.version) > 0) {\n // \u53D1\u751F\u4E86\u7248\u672C\u63D0\u5347\n map.set(modName, {\n version: reqVer,\n uuid: dep.uuid ?? existing.uuid,\n requestedBy: [mod.folderId],\n promotedFrom: existing.promotedFrom ?? existing.version,\n });\n } else if (compareBedrockVersion(reqVer, existing.version) === 0) {\n if (!existing.requestedBy.includes(mod.folderId)) {\n existing.requestedBy.push(mod.folderId);\n }\n }\n }\n }\n\n const promotions: DependencyPromotion[] = [];\n const finalDeps: PackManifestDependency[] = [];\n let hasBetaApis = false;\n\n for (const name of order) {\n const entry = map.get(name)!;\n const dep: PackManifestDependency = {\n module_name: name,\n version: entry.version,\n ...(entry.uuid ? { uuid: entry.uuid } : {}),\n };\n finalDeps.push(dep);\n\n if (entry.promotedFrom && entry.promotedFrom !== entry.version) {\n promotions.push({\n moduleName: name,\n from: entry.promotedFrom,\n to: entry.version,\n requestedBy: entry.requestedBy.filter((x) => x !== \"__sfmc_baseline__\"),\n });\n }\n\n if (isGametestBetaRequired(dep)) {\n hasBetaApis = true;\n }\n }\n\n return {\n dependencies: finalDeps,\n promotions,\n hasBetaApis,\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/fsx.d.ts CHANGED
@@ -3,19 +3,27 @@
3
3
  */
4
4
  /**
5
5
  * 流式计算文件哈希 (sha1 / sha256),
6
- * 用于大文件 (例如 bedrock_server.exe ~80MB),不会 OOM。
6
+ * 用于大文件 (例如 BDS 可执行文件 ~80MB),不会 OOM。
7
7
  */
8
8
  export declare function hashFileAsync(filePath: string, algo?: "sha1" | "sha256"): Promise<string>;
9
9
  /** 同步版本(用于小文件) */
10
10
  export declare function hashFileSync(filePath: string, algo?: "sha1" | "sha256"): string;
11
- /** 同步流式拷贝单文件 (复制中) */
11
+ /** 排除无需备份/复制的仓库与系统垃圾元数据 */
12
+ export declare const DEFAULT_COPY_IGNORE: Set<string>;
13
+ /**
14
+ * Windows 兼容的安全单文件拷贝。
15
+ * 若目标文件已存在且处于只读状态(例如 git objects 属性为只读),先赋写权限并覆写,
16
+ * 并确保拷贝后的目标文件具有可写权限,避免后续重复备份报错。
17
+ */
18
+ export declare function copyFileSyncSafe(src: string, dest: string): void;
19
+ /** 同步流式拷贝单文件,目标只读时自动解除并覆写 */
12
20
  export declare function copyFileAsync(src: string, dest: string): Promise<void>;
13
- /** 同步目录复制 (递归) */
14
- export declare function copyDirSync(src: string, dest: string): void;
15
- /** 异步目录复制 (基于流) */
16
- export declare function copyDirAsync(src: string, dest: string): Promise<void>;
17
- /** 计算目录大小 (字节) */
18
- export declare function getDirSize(dir: string): number;
21
+ /** 同步目录复制 (递归),默认排除 .git / node_modules 等元数据 */
22
+ export declare function copyDirSync(src: string, dest: string, ignore?: Set<string>): void;
23
+ /** 异步目录复制 (基于流),默认排除 .git / node_modules 等元数据 */
24
+ export declare function copyDirAsync(src: string, dest: string, ignore?: Set<string>): Promise<void>;
25
+ /** 计算目录大小 (字节),默认排除 .git / node_modules 等元数据 */
26
+ export declare function getDirSize(dir: string, ignore?: Set<string>): number;
19
27
  /** 强制清空目录内容 (但保留目录本身) */
20
28
  export declare function emptyDirSync(dir: string): void;
21
29
  /** 安全删除整个目录 */
@@ -24,12 +32,7 @@ export declare function rmSafe(path: string): void;
24
32
  export declare function writeFileSafe(filePath: string, data: string | Buffer): void;
25
33
  /**
26
34
  * 读 JSON 文件(utf8)。
27
- * 若文件以 UTF-8 BOM(U+FEFF)开头则剥离后再解析(兼容记事本「UTF-8 with BOM」)。
28
- * Utf8BomError 已弃用且不再抛出,保留类仅供旧调用方类型兼容。
35
+ * 若文件以 UTF-8 BOM(U+FEFF)开头则剥离后再解析(记事本「UTF-8 with BOM」)。
29
36
  */
30
- export declare class Utf8BomError extends Error {
31
- readonly filePath: string;
32
- constructor(filePath: string);
33
- }
34
37
  export declare function readJsonFile<T = unknown>(filePath: string): T;
35
38
  //# sourceMappingURL=fsx.d.ts.map
package/dist/fsx.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../src/fsx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzG;AAED,kBAAkB;AAClB,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,MAAM,CAQzF;AAED,sBAAsB;AACtB,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED,kBAAkB;AAClB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAW3D;AAED,mBAAmB;AACnB,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3E;AAED,kBAAkB;AAClB,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU9C;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAY9C;AAED,eAAe;AACf,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzC;AAED,iCAAiC;AACjC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,YAAY,QAAQ,EAAE,MAAM,EAM3B;CACF;AAED,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAM7D"}
1
+ {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../src/fsx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzG;AAED,kBAAkB;AAClB,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,QAAmB,GAAG,MAAM,CAQzF;AAED,2BAA2B;AAC3B,eAAO,MAAM,mBAAmB,aAQ9B,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBhE;AAED,6BAA6B;AAC7B,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5E;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GACxC,IAAI,CAYN;AAED,iDAAiD;AACjD,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GACxC,OAAO,CAAC,IAAI,CAAC,CAef;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,GAAG,CAAC,MAAM,CAAuB,GAAG,MAAM,CAWzF;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAY9C;AAED,eAAe;AACf,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzC;AAED,iCAAiC;AACjC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAM7D"}
package/dist/fsx.js CHANGED
@@ -22,42 +22,99 @@ function hashFileSync(filePath, algo = "sha256") {
22
22
  return "";
23
23
  }
24
24
  }
25
+ const DEFAULT_COPY_IGNORE = /* @__PURE__ */ new Set([
26
+ ".git",
27
+ ".svn",
28
+ ".hg",
29
+ "node_modules",
30
+ ".DS_Store",
31
+ "Thumbs.db",
32
+ "desktop.ini"
33
+ ]);
34
+ function copyFileSyncSafe(src, dest) {
35
+ try {
36
+ fs.copyFileSync(src, dest);
37
+ } catch (err) {
38
+ const code = err?.code;
39
+ if (code === "EPERM" || code === "EACCES") {
40
+ try {
41
+ if (fs.existsSync(dest)) {
42
+ fs.chmodSync(dest, 438);
43
+ fs.unlinkSync(dest);
44
+ }
45
+ fs.copyFileSync(src, dest);
46
+ } catch {
47
+ throw err;
48
+ }
49
+ } else {
50
+ throw err;
51
+ }
52
+ }
53
+ try {
54
+ fs.chmodSync(dest, 438);
55
+ } catch {
56
+ }
57
+ }
25
58
  async function copyFileAsync(src, dest) {
26
- await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
59
+ try {
60
+ await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
61
+ } catch (err) {
62
+ const code = err?.code;
63
+ if (code === "EPERM" || code === "EACCES") {
64
+ try {
65
+ if (fs.existsSync(dest)) {
66
+ fs.chmodSync(dest, 438);
67
+ fs.unlinkSync(dest);
68
+ }
69
+ await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));
70
+ } catch {
71
+ throw err;
72
+ }
73
+ } else {
74
+ throw err;
75
+ }
76
+ }
77
+ try {
78
+ fs.chmodSync(dest, 438);
79
+ } catch {
80
+ }
27
81
  }
28
- function copyDirSync(src, dest) {
82
+ function copyDirSync(src, dest, ignore = DEFAULT_COPY_IGNORE) {
29
83
  fs.mkdirSync(dest, { recursive: true });
30
84
  for (const entry of fs.readdirSync(src)) {
85
+ if (ignore.has(entry)) continue;
31
86
  const srcPath = path.join(src, entry);
32
87
  const destPath = path.join(dest, entry);
33
88
  if (fs.statSync(srcPath).isDirectory()) {
34
- copyDirSync(srcPath, destPath);
89
+ copyDirSync(srcPath, destPath, ignore);
35
90
  } else {
36
- fs.copyFileSync(srcPath, destPath);
91
+ copyFileSyncSafe(srcPath, destPath);
37
92
  }
38
93
  }
39
94
  }
40
- async function copyDirAsync(src, dest) {
95
+ async function copyDirAsync(src, dest, ignore = DEFAULT_COPY_IGNORE) {
41
96
  fs.mkdirSync(dest, { recursive: true });
42
97
  await Promise.all(
43
98
  fs.readdirSync(src).map(async (entry) => {
99
+ if (ignore.has(entry)) return;
44
100
  const srcPath = path.join(src, entry);
45
101
  const destPath = path.join(dest, entry);
46
102
  const stat = fs.statSync(srcPath);
47
103
  if (stat.isDirectory()) {
48
- await copyDirAsync(srcPath, destPath);
104
+ await copyDirAsync(srcPath, destPath, ignore);
49
105
  } else {
50
106
  await copyFileAsync(srcPath, destPath);
51
107
  }
52
108
  })
53
109
  );
54
110
  }
55
- function getDirSize(dir) {
111
+ function getDirSize(dir, ignore = DEFAULT_COPY_IGNORE) {
56
112
  let total = 0;
57
113
  try {
58
114
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
115
+ if (ignore.has(entry.name)) continue;
59
116
  const full = path.join(dir, entry.name);
60
- if (entry.isDirectory()) total += getDirSize(full);
117
+ if (entry.isDirectory()) total += getDirSize(full, ignore);
61
118
  else if (entry.isFile()) total += fs.statSync(full).size;
62
119
  }
63
120
  } catch {
@@ -89,16 +146,6 @@ function writeFileSafe(filePath, data) {
89
146
  fs.writeFileSync(tmp, data);
90
147
  fs.renameSync(tmp, filePath);
91
148
  }
92
- class Utf8BomError extends Error {
93
- filePath;
94
- constructor(filePath) {
95
- super(
96
- `UTF-8 BOM in ${filePath}: re-save as UTF-8 without BOM (Notepad "UTF-8 with BOM" is not valid for Bedrock packs)`
97
- );
98
- this.name = "Utf8BomError";
99
- this.filePath = filePath;
100
- }
101
- }
102
149
  function readJsonFile(filePath) {
103
150
  let text = fs.readFileSync(filePath, "utf8");
104
151
  if (text.length > 0 && text.charCodeAt(0) === 65279) {
@@ -107,10 +154,11 @@ function readJsonFile(filePath) {
107
154
  return JSON.parse(text);
108
155
  }
109
156
  export {
110
- Utf8BomError,
157
+ DEFAULT_COPY_IGNORE,
111
158
  copyDirAsync,
112
159
  copyDirSync,
113
160
  copyFileAsync,
161
+ copyFileSyncSafe,
114
162
  emptyDirSync,
115
163
  getDirSize,
116
164
  hashFileAsync,
package/dist/fsx.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/fsx.ts"],
4
- "sourcesContent": ["/**\n * fsx.ts \u2014 \u5F02\u6B65/\u6D41\u5F0F\u6587\u4EF6\u64CD\u4F5C (\u907F\u514D\u5927\u6587\u4EF6\u52A0\u8F7D\u8FDB\u5185\u5B58)\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\n\n/**\n * \u6D41\u5F0F\u8BA1\u7B97\u6587\u4EF6\u54C8\u5E0C (sha1 / sha256)\uFF0C\n * \u7528\u4E8E\u5927\u6587\u4EF6 (\u4F8B\u5982 bedrock_server.exe ~80MB)\uFF0C\u4E0D\u4F1A OOM\u3002\n */\nexport async function hashFileAsync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): Promise<string> {\n return new Promise((resolve, reject) => {\n const h = crypto.createHash(algo);\n const stream = fs.createReadStream(filePath);\n stream.on(\"data\", (chunk: Buffer | string) => {\n h.update(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stream.on(\"end\", () => resolve(h.digest(\"hex\").toLowerCase()));\n stream.on(\"error\", reject);\n });\n}\n\n/** \u540C\u6B65\u7248\u672C\uFF08\u7528\u4E8E\u5C0F\u6587\u4EF6\uFF09 */\nexport function hashFileSync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): string {\n try {\n const h = crypto.createHash(algo);\n h.update(fs.readFileSync(filePath));\n return h.digest(\"hex\").toLowerCase();\n } catch {\n return \"\";\n }\n}\n\n/** \u540C\u6B65\u6D41\u5F0F\u62F7\u8D1D\u5355\u6587\u4EF6 (\u590D\u5236\u4E2D) */\nexport async function copyFileAsync(src: string, dest: string): Promise<void> {\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n}\n\n/** \u540C\u6B65\u76EE\u5F55\u590D\u5236 (\u9012\u5F52) */\nexport function copyDirSync(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src)) {\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/** \u5F02\u6B65\u76EE\u5F55\u590D\u5236 (\u57FA\u4E8E\u6D41) */\nexport async function copyDirAsync(src: string, dest: string): Promise<void> {\n fs.mkdirSync(dest, { recursive: true });\n await Promise.all(\n fs.readdirSync(src).map(async (entry) => {\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n const stat = fs.statSync(srcPath);\n if (stat.isDirectory()) {\n await copyDirAsync(srcPath, destPath);\n } else {\n await copyFileAsync(srcPath, destPath);\n }\n })\n );\n}\n\n/** \u8BA1\u7B97\u76EE\u5F55\u5927\u5C0F (\u5B57\u8282) */\nexport function getDirSize(dir: string): number {\n let total = 0;\n try {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) total += getDirSize(full);\n else if (entry.isFile()) total += fs.statSync(full).size;\n }\n } catch {}\n return total;\n}\n\n/** \u5F3A\u5236\u6E05\u7A7A\u76EE\u5F55\u5185\u5BB9 (\u4F46\u4FDD\u7559\u76EE\u5F55\u672C\u8EAB) */\nexport function emptyDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n try {\n const stat = fs.statSync(full);\n if (stat.isDirectory()) fs.rmSync(full, { recursive: true, force: true });\n else fs.unlinkSync(full);\n } catch (e) {\n // \u5FFD\u7565: \u9876\u5C42\u4ECD\u4FDD\u7559\u76EE\u5F55\uFF0C\u5373\u4F7F\u90E8\u5206\u5B50\u9879\u65E0\u6CD5\u5220\u9664\n }\n }\n}\n\n/** \u5B89\u5168\u5220\u9664\u6574\u4E2A\u76EE\u5F55 */\nexport function rmSafe(path: string): void {\n try {\n fs.rmSync(path, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** \u5B89\u5168\u5199\u6587\u4EF6 (\u539F\u5B50: \u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename) */\nexport function writeFileSafe(filePath: string, data: string | Buffer): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${filePath}.${process.pid}.tmp`;\n fs.writeFileSync(tmp, data);\n fs.renameSync(tmp, filePath);\n}\n\n/**\n * \u8BFB JSON \u6587\u4EF6\uFF08utf8\uFF09\u3002\n * \u82E5\u6587\u4EF6\u4EE5 UTF-8 BOM\uFF08U+FEFF\uFF09\u5F00\u5934\u5219\u5265\u79BB\u540E\u518D\u89E3\u6790\uFF08\u517C\u5BB9\u8BB0\u4E8B\u672C\u300CUTF-8 with BOM\u300D\uFF09\u3002\n * Utf8BomError \u5DF2\u5F03\u7528\u4E14\u4E0D\u518D\u629B\u51FA\uFF0C\u4FDD\u7559\u7C7B\u4EC5\u4F9B\u65E7\u8C03\u7528\u65B9\u7C7B\u578B\u517C\u5BB9\u3002\n */\nexport class Utf8BomError extends Error {\n readonly filePath: string;\n constructor(filePath: string) {\n super(\n `UTF-8 BOM in ${filePath}: re-save as UTF-8 without BOM (Notepad \"UTF-8 with BOM\" is not valid for Bedrock packs)`\n );\n this.name = \"Utf8BomError\";\n this.filePath = filePath;\n }\n}\n\nexport function readJsonFile<T = unknown>(filePath: string): T {\n let text = fs.readFileSync(filePath, \"utf8\");\n if (text.length > 0 && text.charCodeAt(0) === 0xfeff) {\n text = text.slice(1);\n }\n return JSON.parse(text) as T;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * fsx.ts \u2014 \u5F02\u6B65/\u6D41\u5F0F\u6587\u4EF6\u64CD\u4F5C (\u907F\u514D\u5927\u6587\u4EF6\u52A0\u8F7D\u8FDB\u5185\u5B58)\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\n\n/**\n * \u6D41\u5F0F\u8BA1\u7B97\u6587\u4EF6\u54C8\u5E0C (sha1 / sha256)\uFF0C\n * \u7528\u4E8E\u5927\u6587\u4EF6 (\u4F8B\u5982 BDS \u53EF\u6267\u884C\u6587\u4EF6 ~80MB)\uFF0C\u4E0D\u4F1A OOM\u3002\n */\nexport async function hashFileAsync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): Promise<string> {\n return new Promise((resolve, reject) => {\n const h = crypto.createHash(algo);\n const stream = fs.createReadStream(filePath);\n stream.on(\"data\", (chunk: Buffer | string) => {\n h.update(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stream.on(\"end\", () => resolve(h.digest(\"hex\").toLowerCase()));\n stream.on(\"error\", reject);\n });\n}\n\n/** \u540C\u6B65\u7248\u672C\uFF08\u7528\u4E8E\u5C0F\u6587\u4EF6\uFF09 */\nexport function hashFileSync(filePath: string, algo: \"sha1\" | \"sha256\" = \"sha256\"): string {\n try {\n const h = crypto.createHash(algo);\n h.update(fs.readFileSync(filePath));\n return h.digest(\"hex\").toLowerCase();\n } catch {\n return \"\";\n }\n}\n\n/** \u6392\u9664\u65E0\u9700\u5907\u4EFD/\u590D\u5236\u7684\u4ED3\u5E93\u4E0E\u7CFB\u7EDF\u5783\u573E\u5143\u6570\u636E */\nexport const DEFAULT_COPY_IGNORE = new Set([\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \".DS_Store\",\n \"Thumbs.db\",\n \"desktop.ini\",\n]);\n\n/**\n * Windows \u517C\u5BB9\u7684\u5B89\u5168\u5355\u6587\u4EF6\u62F7\u8D1D\u3002\n * \u82E5\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E14\u5904\u4E8E\u53EA\u8BFB\u72B6\u6001\uFF08\u4F8B\u5982 git objects \u5C5E\u6027\u4E3A\u53EA\u8BFB\uFF09\uFF0C\u5148\u8D4B\u5199\u6743\u9650\u5E76\u8986\u5199\uFF0C\n * \u5E76\u786E\u4FDD\u62F7\u8D1D\u540E\u7684\u76EE\u6807\u6587\u4EF6\u5177\u6709\u53EF\u5199\u6743\u9650\uFF0C\u907F\u514D\u540E\u7EED\u91CD\u590D\u5907\u4EFD\u62A5\u9519\u3002\n */\nexport function copyFileSyncSafe(src: string, dest: string): void {\n try {\n fs.copyFileSync(src, dest);\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"EPERM\" || code === \"EACCES\") {\n try {\n if (fs.existsSync(dest)) {\n fs.chmodSync(dest, 0o666);\n fs.unlinkSync(dest);\n }\n fs.copyFileSync(src, dest);\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n try {\n fs.chmodSync(dest, 0o666);\n } catch {\n /* ignore */\n }\n}\n\n/** \u540C\u6B65\u6D41\u5F0F\u62F7\u8D1D\u5355\u6587\u4EF6\uFF0C\u76EE\u6807\u53EA\u8BFB\u65F6\u81EA\u52A8\u89E3\u9664\u5E76\u8986\u5199 */\nexport async function copyFileAsync(src: string, dest: string): Promise<void> {\n try {\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"EPERM\" || code === \"EACCES\") {\n try {\n if (fs.existsSync(dest)) {\n fs.chmodSync(dest, 0o666);\n fs.unlinkSync(dest);\n }\n await pipeline(fs.createReadStream(src), fs.createWriteStream(dest));\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n try {\n fs.chmodSync(dest, 0o666);\n } catch {\n /* ignore */\n }\n}\n\n/** \u540C\u6B65\u76EE\u5F55\u590D\u5236 (\u9012\u5F52)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport function copyDirSync(\n src: string,\n dest: string,\n ignore: Set<string> = DEFAULT_COPY_IGNORE\n): void {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src)) {\n if (ignore.has(entry)) continue;\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n if (fs.statSync(srcPath).isDirectory()) {\n copyDirSync(srcPath, destPath, ignore);\n } else {\n copyFileSyncSafe(srcPath, destPath);\n }\n }\n}\n\n/** \u5F02\u6B65\u76EE\u5F55\u590D\u5236 (\u57FA\u4E8E\u6D41)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport async function copyDirAsync(\n src: string,\n dest: string,\n ignore: Set<string> = DEFAULT_COPY_IGNORE\n): Promise<void> {\n fs.mkdirSync(dest, { recursive: true });\n await Promise.all(\n fs.readdirSync(src).map(async (entry) => {\n if (ignore.has(entry)) return;\n const srcPath = path.join(src, entry);\n const destPath = path.join(dest, entry);\n const stat = fs.statSync(srcPath);\n if (stat.isDirectory()) {\n await copyDirAsync(srcPath, destPath, ignore);\n } else {\n await copyFileAsync(srcPath, destPath);\n }\n })\n );\n}\n\n/** \u8BA1\u7B97\u76EE\u5F55\u5927\u5C0F (\u5B57\u8282)\uFF0C\u9ED8\u8BA4\u6392\u9664 .git / node_modules \u7B49\u5143\u6570\u636E */\nexport function getDirSize(dir: string, ignore: Set<string> = DEFAULT_COPY_IGNORE): number {\n let total = 0;\n try {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (ignore.has(entry.name)) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) total += getDirSize(full, ignore);\n else if (entry.isFile()) total += fs.statSync(full).size;\n }\n } catch {}\n return total;\n}\n\n/** \u5F3A\u5236\u6E05\u7A7A\u76EE\u5F55\u5185\u5BB9 (\u4F46\u4FDD\u7559\u76EE\u5F55\u672C\u8EAB) */\nexport function emptyDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir)) {\n const full = path.join(dir, entry);\n try {\n const stat = fs.statSync(full);\n if (stat.isDirectory()) fs.rmSync(full, { recursive: true, force: true });\n else fs.unlinkSync(full);\n } catch (e) {\n // \u5FFD\u7565: \u9876\u5C42\u4ECD\u4FDD\u7559\u76EE\u5F55\uFF0C\u5373\u4F7F\u90E8\u5206\u5B50\u9879\u65E0\u6CD5\u5220\u9664\n }\n }\n}\n\n/** \u5B89\u5168\u5220\u9664\u6574\u4E2A\u76EE\u5F55 */\nexport function rmSafe(path: string): void {\n try {\n fs.rmSync(path, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** \u5B89\u5168\u5199\u6587\u4EF6 (\u539F\u5B50: \u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename) */\nexport function writeFileSafe(filePath: string, data: string | Buffer): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${filePath}.${process.pid}.tmp`;\n fs.writeFileSync(tmp, data);\n fs.renameSync(tmp, filePath);\n}\n\n/**\n * \u8BFB JSON \u6587\u4EF6\uFF08utf8\uFF09\u3002\n * \u82E5\u6587\u4EF6\u4EE5 UTF-8 BOM\uFF08U+FEFF\uFF09\u5F00\u5934\u5219\u5265\u79BB\u540E\u518D\u89E3\u6790\uFF08\u8BB0\u4E8B\u672C\u300CUTF-8 with BOM\u300D\uFF09\u3002\n */\nexport function readJsonFile<T = unknown>(filePath: string): T {\n let text = fs.readFileSync(filePath, \"utf8\");\n if (text.length > 0 && text.charCodeAt(0) === 0xfeff) {\n text = text.slice(1);\n }\n return JSON.parse(text) as T;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path"]
7
7
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * host-platform.ts — BDS 宿主平台契约(单一权威来源)
3
+ *
4
+ * Windows / Linux 官方 BDS 的可执行文件名、CDN 路径、启动环境不同。
5
+ * 启动器与更新器只依赖本模块,禁止在业务里再写 bedrock_server.exe / bin-win。
6
+ * macOS 无官方 BDS,按 linux 处理(调用方应避免在 darwin 上当生产宿主)。
7
+ */
8
+ export type BdsHostOs = "windows" | "linux";
9
+ export declare function bdsHostOs(platform?: NodeJS.Platform): BdsHostOs;
10
+ export declare function bdsExeName(os?: BdsHostOs): string;
11
+ export declare function bdsExePath(bdsPath: string, os?: BdsHostOs): string;
12
+ /** BDS-Versions 详情 JSON 的 platform 段:windows / windows_preview / linux / linux_preview */
13
+ export declare function bdsDetailsPlatformKey(channel: string, os?: BdsHostOs): string;
14
+ /** minecraft.net / azureedge CDN 上的 zip 相对路径 */
15
+ export declare function bdsCdnZipSuffix(channel: string, version: string, os?: BdsHostOs): string;
16
+ /** 解压后完整性检查的必备相对路径 */
17
+ export declare function bdsInstallRequiredFiles(os?: BdsHostOs): string[];
18
+ /**
19
+ * 仅返回需覆盖进 spawn env 的键。
20
+ * Linux 官方 BDS 依赖同目录 lib*.so,须把安装目录放进 LD_LIBRARY_PATH。
21
+ */
22
+ export declare function bdsSpawnEnvExtra(bdsPath: string, os?: BdsHostOs): Record<string, string>;
23
+ /** Linux zip 解压后往往没有 +x,启动前补上 */
24
+ export declare function ensureBdsExecutable(exePath: string, os?: BdsHostOs): void;
25
+ //# sourceMappingURL=host-platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-platform.d.ts","sourceRoot":"","sources":["../src/host-platform.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5C,wBAAgB,SAAS,CAAC,QAAQ,kBAAmB,GAAG,SAAS,CAEhE;AAED,wBAAgB,UAAU,CAAC,EAAE,GAAE,SAAuB,GAAG,MAAM,CAE9D;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAuB,GAAG,MAAM,CAE/E;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAuB,GAAG,MAAM,CAI1F;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAuB,GAAG,MAAM,CAUrG;AAED,sBAAsB;AACtB,wBAAgB,uBAAuB,CAAC,EAAE,GAAE,SAAuB,GAAG,MAAM,EAAE,CAE7E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAKrG;AAED,iCAAiC;AACjC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,SAAuB,GAAG,IAAI,CAOtF"}
@@ -0,0 +1,50 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ function bdsHostOs(platform = process.platform) {
4
+ return platform === "win32" ? "windows" : "linux";
5
+ }
6
+ function bdsExeName(os = bdsHostOs()) {
7
+ return os === "windows" ? "bedrock_server.exe" : "bedrock_server";
8
+ }
9
+ function bdsExePath(bdsPath, os = bdsHostOs()) {
10
+ return path.join(bdsPath, bdsExeName(os));
11
+ }
12
+ function bdsDetailsPlatformKey(channel, os = bdsHostOs()) {
13
+ const preview = channel === "preview";
14
+ if (os === "windows") return preview ? "windows_preview" : "windows";
15
+ return preview ? "linux_preview" : "linux";
16
+ }
17
+ function bdsCdnZipSuffix(channel, version, os = bdsHostOs()) {
18
+ const preview = channel === "preview";
19
+ if (os === "windows") {
20
+ return preview ? `/bin-win-preview/bedrock-server-${version}-preview.zip` : `/bin-win/bedrock-server-${version}.zip`;
21
+ }
22
+ return preview ? `/bin-linux-preview/bedrock-server-${version}-preview.zip` : `/bin-linux/bedrock-server-${version}.zip`;
23
+ }
24
+ function bdsInstallRequiredFiles(os = bdsHostOs()) {
25
+ return [bdsExeName(os), "permissions.json"];
26
+ }
27
+ function bdsSpawnEnvExtra(bdsPath, os = bdsHostOs()) {
28
+ if (os === "windows") return {};
29
+ const prev = process.env.LD_LIBRARY_PATH ?? "";
30
+ const ld = prev ? `${bdsPath}${path.delimiter}${prev}` : bdsPath;
31
+ return { LD_LIBRARY_PATH: ld };
32
+ }
33
+ function ensureBdsExecutable(exePath, os = bdsHostOs()) {
34
+ if (os === "windows") return;
35
+ try {
36
+ if (fs.existsSync(exePath)) fs.chmodSync(exePath, 493);
37
+ } catch {
38
+ }
39
+ }
40
+ export {
41
+ bdsCdnZipSuffix,
42
+ bdsDetailsPlatformKey,
43
+ bdsExeName,
44
+ bdsExePath,
45
+ bdsHostOs,
46
+ bdsInstallRequiredFiles,
47
+ bdsSpawnEnvExtra,
48
+ ensureBdsExecutable
49
+ };
50
+ //# sourceMappingURL=host-platform.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/host-platform.ts"],
4
+ "sourcesContent": ["/**\n * host-platform.ts \u2014 BDS \u5BBF\u4E3B\u5E73\u53F0\u5951\u7EA6\uFF08\u5355\u4E00\u6743\u5A01\u6765\u6E90\uFF09\n *\n * Windows / Linux \u5B98\u65B9 BDS \u7684\u53EF\u6267\u884C\u6587\u4EF6\u540D\u3001CDN \u8DEF\u5F84\u3001\u542F\u52A8\u73AF\u5883\u4E0D\u540C\u3002\n * \u542F\u52A8\u5668\u4E0E\u66F4\u65B0\u5668\u53EA\u4F9D\u8D56\u672C\u6A21\u5757\uFF0C\u7981\u6B62\u5728\u4E1A\u52A1\u91CC\u518D\u5199 bedrock_server.exe / bin-win\u3002\n * macOS \u65E0\u5B98\u65B9 BDS\uFF0C\u6309 linux \u5904\u7406\uFF08\u8C03\u7528\u65B9\u5E94\u907F\u514D\u5728 darwin \u4E0A\u5F53\u751F\u4EA7\u5BBF\u4E3B\uFF09\u3002\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport type BdsHostOs = \"windows\" | \"linux\";\n\nexport function bdsHostOs(platform = process.platform): BdsHostOs {\n return platform === \"win32\" ? \"windows\" : \"linux\";\n}\n\nexport function bdsExeName(os: BdsHostOs = bdsHostOs()): string {\n return os === \"windows\" ? \"bedrock_server.exe\" : \"bedrock_server\";\n}\n\nexport function bdsExePath(bdsPath: string, os: BdsHostOs = bdsHostOs()): string {\n return path.join(bdsPath, bdsExeName(os));\n}\n\n/** BDS-Versions \u8BE6\u60C5 JSON \u7684 platform \u6BB5\uFF1Awindows / windows_preview / linux / linux_preview */\nexport function bdsDetailsPlatformKey(channel: string, os: BdsHostOs = bdsHostOs()): string {\n const preview = channel === \"preview\";\n if (os === \"windows\") return preview ? \"windows_preview\" : \"windows\";\n return preview ? \"linux_preview\" : \"linux\";\n}\n\n/** minecraft.net / azureedge CDN \u4E0A\u7684 zip \u76F8\u5BF9\u8DEF\u5F84 */\nexport function bdsCdnZipSuffix(channel: string, version: string, os: BdsHostOs = bdsHostOs()): string {\n const preview = channel === \"preview\";\n if (os === \"windows\") {\n return preview\n ? `/bin-win-preview/bedrock-server-${version}-preview.zip`\n : `/bin-win/bedrock-server-${version}.zip`;\n }\n return preview\n ? `/bin-linux-preview/bedrock-server-${version}-preview.zip`\n : `/bin-linux/bedrock-server-${version}.zip`;\n}\n\n/** \u89E3\u538B\u540E\u5B8C\u6574\u6027\u68C0\u67E5\u7684\u5FC5\u5907\u76F8\u5BF9\u8DEF\u5F84 */\nexport function bdsInstallRequiredFiles(os: BdsHostOs = bdsHostOs()): string[] {\n return [bdsExeName(os), \"permissions.json\"];\n}\n\n/**\n * \u4EC5\u8FD4\u56DE\u9700\u8986\u76D6\u8FDB spawn env \u7684\u952E\u3002\n * Linux \u5B98\u65B9 BDS \u4F9D\u8D56\u540C\u76EE\u5F55 lib*.so\uFF0C\u987B\u628A\u5B89\u88C5\u76EE\u5F55\u653E\u8FDB LD_LIBRARY_PATH\u3002\n */\nexport function bdsSpawnEnvExtra(bdsPath: string, os: BdsHostOs = bdsHostOs()): Record<string, string> {\n if (os === \"windows\") return {};\n const prev = process.env.LD_LIBRARY_PATH ?? \"\";\n const ld = prev ? `${bdsPath}${path.delimiter}${prev}` : bdsPath;\n return { LD_LIBRARY_PATH: ld };\n}\n\n/** Linux zip \u89E3\u538B\u540E\u5F80\u5F80\u6CA1\u6709 +x\uFF0C\u542F\u52A8\u524D\u8865\u4E0A */\nexport function ensureBdsExecutable(exePath: string, os: BdsHostOs = bdsHostOs()): void {\n if (os === \"windows\") return;\n try {\n if (fs.existsSync(exePath)) fs.chmodSync(exePath, 0o755);\n } catch {\n /* \u53EA\u8BFB\u6587\u4EF6\u7CFB\u7EDF\u65F6\u5FFD\u7565\uFF0Cspawn \u4F1A\u518D\u62A5\u9519 */\n }\n}\n"],
5
+ "mappings": "AAQA,OAAO,QAAQ;AACf,OAAO,UAAU;AAIV,SAAS,UAAU,WAAW,QAAQ,UAAqB;AAChE,SAAO,aAAa,UAAU,YAAY;AAC5C;AAEO,SAAS,WAAW,KAAgB,UAAU,GAAW;AAC9D,SAAO,OAAO,YAAY,uBAAuB;AACnD;AAEO,SAAS,WAAW,SAAiB,KAAgB,UAAU,GAAW;AAC/E,SAAO,KAAK,KAAK,SAAS,WAAW,EAAE,CAAC;AAC1C;AAGO,SAAS,sBAAsB,SAAiB,KAAgB,UAAU,GAAW;AAC1F,QAAM,UAAU,YAAY;AAC5B,MAAI,OAAO,UAAW,QAAO,UAAU,oBAAoB;AAC3D,SAAO,UAAU,kBAAkB;AACrC;AAGO,SAAS,gBAAgB,SAAiB,SAAiB,KAAgB,UAAU,GAAW;AACrG,QAAM,UAAU,YAAY;AAC5B,MAAI,OAAO,WAAW;AACpB,WAAO,UACH,mCAAmC,OAAO,iBAC1C,2BAA2B,OAAO;AAAA,EACxC;AACA,SAAO,UACH,qCAAqC,OAAO,iBAC5C,6BAA6B,OAAO;AAC1C;AAGO,SAAS,wBAAwB,KAAgB,UAAU,GAAa;AAC7E,SAAO,CAAC,WAAW,EAAE,GAAG,kBAAkB;AAC5C;AAMO,SAAS,iBAAiB,SAAiB,KAAgB,UAAU,GAA2B;AACrG,MAAI,OAAO,UAAW,QAAO,CAAC;AAC9B,QAAM,OAAO,QAAQ,IAAI,mBAAmB;AAC5C,QAAM,KAAK,OAAO,GAAG,OAAO,GAAG,KAAK,SAAS,GAAG,IAAI,KAAK;AACzD,SAAO,EAAE,iBAAiB,GAAG;AAC/B;AAGO,SAAS,oBAAoB,SAAiB,KAAgB,UAAU,GAAS;AACtF,MAAI,OAAO,UAAW;AACtB,MAAI;AACF,QAAI,GAAG,WAAW,OAAO,EAAG,IAAG,UAAU,SAAS,GAAK;AAAA,EACzD,QAAQ;AAAA,EAER;AACF;",
6
+ "names": []
7
+ }
package/dist/http.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  /**
2
- * http.ts — 稳定 HTTP 工具 (分阶段超时 + 自动重定向 + 流式下载)
2
+ * http.ts — 针对大文件与外部上游设计的 HTTP 网络请求工具
3
3
  *
4
- * 改进:
5
- * - connect timeout vs total timeout 分开
6
- * - 下载通过流管道,避免大文件加载到内存
7
- * - 失败后已写入的临时文件可被清理
4
+ * 核心机制:
5
+ * - 分阶段超时控制:区分连接建立超时(connectTimeout)与全量传输超时(totalTimeout)
6
+ * - 自动重定向处理:安全跟踪 3xx 跳转(最多 5 次)
7
+ * - 流式文件下载:通过 pipeline 管道直接落盘,避免大文件一次性加载至内存
8
+ * - 异常容错清理:下载失败时自动清理残留的临时文件碎片
8
9
  */
9
10
  interface HttpOptions {
10
11
  method?: "GET" | "HEAD" | "POST";
@@ -14,24 +15,61 @@ interface HttpOptions {
14
15
  totalTimeoutMs?: number;
15
16
  redirects?: number;
16
17
  }
18
+ /**
19
+ * 发起底层 HTTP/HTTPS 请求。
20
+ *
21
+ * @param url 目标请求地址。
22
+ * @param opts 请求参数(包含请求方法、请求头、主体、阶段超时时间及重定向次数等)。
23
+ * @returns 包含状态码、响应体 Buffer 及响应头字典的结果对象。
24
+ */
17
25
  export declare function httpRequest(url: string, opts?: HttpOptions): Promise<{
18
26
  statusCode: number;
19
27
  body: Buffer;
20
28
  headers: Record<string, string | string[] | undefined>;
21
29
  }>;
30
+ /**
31
+ * 发起 GET 请求并自动将响应体解析为 JSON 数据对象。
32
+ *
33
+ * @template T 预期的 JSON 数据类型。
34
+ * @param url 请求目标 URL。
35
+ * @param opts 请求配置选项。
36
+ * @returns 解析后的 JSON 对象。
37
+ */
22
38
  export declare function httpGetJson<T = unknown>(url: string, opts?: HttpOptions): Promise<T>;
39
+ /**
40
+ * 发起 GET 请求并获取 UTF-8 纯文本响应内容。
41
+ *
42
+ * @param url 请求目标 URL。
43
+ * @param opts 请求配置选项。
44
+ * @returns 响应文本字符串。
45
+ */
23
46
  export declare function httpGetText(url: string, opts?: HttpOptions): Promise<string>;
24
- /** 多个源并发请求,谁先成功返回(每个源都用 JSON 解析,解析失败也失败) */
25
- export declare function fetchJsonWithFallback<T = unknown>(sources: string[], timeoutMs?: number): Promise<T>;
26
47
  /**
27
- * 流式下载到指定路径,返回字节数。
28
- * - 失败时自动清理 partial 文件
29
- * - 支持 progress 回调
30
- * - 支持 connect/total 阶段超时
48
+ * 针对多个备选源并发发起请求,由最先成功返回且合法解析 JSON 的源提供数据(Happy Eyeballs 机制)。
49
+ *
50
+ * @template T 返回的 JSON 数据类型。
51
+ * @param sources 候选 URL 列表。
52
+ * @param timeoutMs 超时时间(毫秒,默认为 15000)。
53
+ * @returns 最先成功响应的数据。
54
+ * @throws 当所有备选源均失败时抛出聚合错误。
31
55
  */
56
+ export declare function fetchJsonWithFallback<T = unknown>(sources: string[], timeoutMs?: number): Promise<T>;
57
+ /** 下载配置选项。 */
32
58
  export interface DownloadOptions extends HttpOptions {
59
+ /** 下载进度变化回调函数。 */
33
60
  onProgress?: (downloaded: number, total: number) => void;
34
61
  }
62
+ /**
63
+ * 流式下载网络资源至本地指定路径。
64
+ * - 传输失败时自动删除残留的临时文件碎片
65
+ * - 支持节流的进度通知回调
66
+ * - 支持连接建立与全量传输双阶段独立超时
67
+ *
68
+ * @param url 下载目标地址。
69
+ * @param destPath 本地落盘目标绝对路径。
70
+ * @param opts 下载参数选项。
71
+ * @returns 成功下载的总字节数。
72
+ */
35
73
  export declare function httpDownload(url: string, destPath: string, opts?: DownloadOptions): Promise<number>;
36
74
  export {};
37
75
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;CAAE,CAAC,CA2DvG;AAED,wBAAsB,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3C,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGtF;AAED,4CAA4C;AAC5C,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAcZ;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,MAAM,CAAC,CA4GjB"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAE/B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;CAAE,CAAC,CA2DvG;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3C,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGtF;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,SAAS,GACjB,OAAO,CAAC,CAAC,CAAC,CAcZ;AAED,cAAc;AACd,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,kBAAkB;IAClB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED;;;;;;;;;;GAUG;AAGH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,MAAM,CAAC,CA4GjB"}