rn-update-cli 1.0.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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -0
  3. package/README.zh-CN.md +167 -0
  4. package/cli.json +525 -0
  5. package/lib/api.d.ts +56 -0
  6. package/lib/api.js +671 -0
  7. package/lib/app.d.ts +107 -0
  8. package/lib/app.js +329 -0
  9. package/lib/auto-update.d.ts +35 -0
  10. package/lib/auto-update.js +507 -0
  11. package/lib/bin.d.ts +2 -0
  12. package/lib/bin.js +133 -0
  13. package/lib/bundle-pack.d.ts +6 -0
  14. package/lib/bundle-pack.js +91 -0
  15. package/lib/bundle-runner.d.ts +168 -0
  16. package/lib/bundle-runner.js +1305 -0
  17. package/lib/bundle.d.ts +45 -0
  18. package/lib/bundle.js +226 -0
  19. package/lib/cache.d.ts +10 -0
  20. package/lib/cache.js +25 -0
  21. package/lib/commands.d.ts +11 -0
  22. package/lib/commands.js +72 -0
  23. package/lib/diff.d.ts +18 -0
  24. package/lib/diff.js +690 -0
  25. package/lib/exports.d.ts +11 -0
  26. package/lib/exports.js +20 -0
  27. package/lib/install.d.ts +9 -0
  28. package/lib/install.js +51 -0
  29. package/lib/locales/en.d.ts +187 -0
  30. package/lib/locales/en.js +194 -0
  31. package/lib/locales/zh.d.ts +187 -0
  32. package/lib/locales/zh.js +194 -0
  33. package/lib/native-package.d.ts +21 -0
  34. package/lib/native-package.js +298 -0
  35. package/lib/package.d.ts +68 -0
  36. package/lib/package.js +487 -0
  37. package/lib/provider.d.ts +24 -0
  38. package/lib/provider.js +244 -0
  39. package/lib/standalone-publish.d.ts +17 -0
  40. package/lib/standalone-publish.js +433 -0
  41. package/lib/symbolicate.d.ts +35 -0
  42. package/lib/symbolicate.js +130 -0
  43. package/lib/types.d.ts +152 -0
  44. package/lib/types.js +2 -0
  45. package/lib/user.d.ts +8 -0
  46. package/lib/user.js +50 -0
  47. package/lib/utils/add-gitignore.d.ts +6 -0
  48. package/lib/utils/add-gitignore.js +44 -0
  49. package/lib/utils/app-info-parser/aab.d.ts +27 -0
  50. package/lib/utils/app-info-parser/aab.js +256 -0
  51. package/lib/utils/app-info-parser/apk.d.ts +19 -0
  52. package/lib/utils/app-info-parser/apk.js +95 -0
  53. package/lib/utils/app-info-parser/app.d.ts +9 -0
  54. package/lib/utils/app-info-parser/app.js +15 -0
  55. package/lib/utils/app-info-parser/index.d.ts +21 -0
  56. package/lib/utils/app-info-parser/index.js +51 -0
  57. package/lib/utils/app-info-parser/ipa.d.ts +19 -0
  58. package/lib/utils/app-info-parser/ipa.js +101 -0
  59. package/lib/utils/app-info-parser/resource-finder.d.ts +49 -0
  60. package/lib/utils/app-info-parser/resource-finder.js +429 -0
  61. package/lib/utils/app-info-parser/utils.d.ts +36 -0
  62. package/lib/utils/app-info-parser/utils.js +140 -0
  63. package/lib/utils/app-info-parser/xml-parser/binary.d.ts +61 -0
  64. package/lib/utils/app-info-parser/xml-parser/binary.js +577 -0
  65. package/lib/utils/app-info-parser/xml-parser/manifest.d.ts +15 -0
  66. package/lib/utils/app-info-parser/xml-parser/manifest.js +207 -0
  67. package/lib/utils/app-info-parser/zip.d.ts +29 -0
  68. package/lib/utils/app-info-parser/zip.js +97 -0
  69. package/lib/utils/check-lockfile.d.ts +6 -0
  70. package/lib/utils/check-lockfile.js +93 -0
  71. package/lib/utils/check-plugin.d.ts +12 -0
  72. package/lib/utils/check-plugin.js +36 -0
  73. package/lib/utils/command-result.d.ts +8 -0
  74. package/lib/utils/command-result.js +27 -0
  75. package/lib/utils/constants.d.ts +10 -0
  76. package/lib/utils/constants.js +39 -0
  77. package/lib/utils/dep-versions.d.ts +20 -0
  78. package/lib/utils/dep-versions.js +129 -0
  79. package/lib/utils/git.d.ts +14 -0
  80. package/lib/utils/git.js +64 -0
  81. package/lib/utils/hbcTransform.d.ts +111 -0
  82. package/lib/utils/hbcTransform.js +561 -0
  83. package/lib/utils/hermes-base.d.ts +227 -0
  84. package/lib/utils/hermes-base.js +1287 -0
  85. package/lib/utils/hermes-literals.d.ts +64 -0
  86. package/lib/utils/hermes-literals.js +260 -0
  87. package/lib/utils/http-helper.d.ts +10 -0
  88. package/lib/utils/http-helper.js +150 -0
  89. package/lib/utils/i18n.d.ts +22 -0
  90. package/lib/utils/i18n.js +46 -0
  91. package/lib/utils/index.d.ts +67 -0
  92. package/lib/utils/index.js +545 -0
  93. package/lib/utils/latest-version/index.d.ts +154 -0
  94. package/lib/utils/latest-version/index.js +331 -0
  95. package/lib/utils/options.d.ts +10 -0
  96. package/lib/utils/options.js +68 -0
  97. package/lib/utils/plugin-config.d.ts +14 -0
  98. package/lib/utils/plugin-config.js +66 -0
  99. package/lib/utils/runtime.d.ts +54 -0
  100. package/lib/utils/runtime.js +263 -0
  101. package/lib/utils/slim-sourcemap.d.ts +28 -0
  102. package/lib/utils/slim-sourcemap.js +106 -0
  103. package/lib/utils/zip-entries.d.ts +10 -0
  104. package/lib/utils/zip-entries.js +211 -0
  105. package/lib/utils/zip-options.d.ts +17 -0
  106. package/lib/utils/zip-options.js +190 -0
  107. package/lib/utils/zip-range.d.ts +148 -0
  108. package/lib/utils/zip-range.js +581 -0
  109. package/lib/utils/zip-raw-writer.d.ts +52 -0
  110. package/lib/utils/zip-raw-writer.js +209 -0
  111. package/lib/version-operations.d.ts +21 -0
  112. package/lib/version-operations.js +320 -0
  113. package/lib/versions.d.ts +66 -0
  114. package/lib/versions.js +402 -0
  115. package/package.json +113 -0
  116. package/proto/Configuration.proto +183 -0
  117. package/proto/Resources.proto +569 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * [INPUT]: 依赖 Node/Bun 子进程、HTTP agent、代理环境变量与包管理器运行时布局
3
+ * [OUTPUT]: 对外提供代理感知请求、网络延迟探测、包管理器/JavaScript runtime 选择及进程启动函数
4
+ * [POS]: CLI 跨运行时基础设施,统一网络和子进程行为,供 API、bundle 与安装命令复用
5
+ */
6
+ import { type ChildProcessWithoutNullStreams, type SpawnOptionsWithoutStdio, type SpawnSyncOptions } from 'child_process';
7
+ import type { Agent as HttpAgent } from 'http';
8
+ export type RuntimeRequestInit = {
9
+ method?: string;
10
+ headers?: Record<string, string>;
11
+ body?: any;
12
+ signal?: AbortSignal;
13
+ };
14
+ export type RuntimeResponse = {
15
+ status: number;
16
+ statusText: string;
17
+ text: () => Promise<string>;
18
+ };
19
+ export type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn';
20
+ export type JavaScriptRuntime = 'bun' | 'node';
21
+ export declare const isBunRuntime: boolean;
22
+ export declare function runtimeFetch(url: string, options?: RuntimeRequestInit): Promise<RuntimeResponse>;
23
+ /**
24
+ * The proxy url for `targetUrl` from the environment, or undefined for a
25
+ * direct connection (no proxy configured, NO_PROXY exempts the host, or the
26
+ * proxy is not an http(s) url).
27
+ */
28
+ export declare function resolveProxy(targetUrl: string, env?: NodeJS.ProcessEnv): string | undefined;
29
+ /**
30
+ * fetch with the WHATWG Response, through the environment's proxy when one
31
+ * applies to `url`. The proxy path goes through undici's own fetch (Node's
32
+ * built-in one cannot take a dispatcher), loaded only then.
33
+ */
34
+ export declare function webFetch(url: string, init?: RequestInit): Promise<Response>;
35
+ /**
36
+ * An http.Agent routing `targetUrl` through its proxy, for the core
37
+ * http/https APIs and node-fetch (the streaming uploads); undefined when the
38
+ * connection is direct. Always a CONNECT tunnel (also for http targets, like
39
+ * undici's ProxyAgent above): the absolute-form alternative rewrites the
40
+ * request head after it was buffered, which garbles a streaming body.
41
+ */
42
+ export declare function proxyAgentFor(targetUrl: string): HttpAgent | undefined;
43
+ export declare function measureTcpLatency(input: string, { attempts, timeout, }?: {
44
+ attempts?: number;
45
+ timeout?: number;
46
+ }): Promise<number>;
47
+ export declare function detectPackageManager(cwd?: string, env?: NodeJS.ProcessEnv): PackageManager;
48
+ export declare function getInstallCommand(installArgs: string[], cwd?: string): {
49
+ command: string;
50
+ args: string[];
51
+ };
52
+ export declare function getJavaScriptRuntime(env?: NodeJS.ProcessEnv): JavaScriptRuntime;
53
+ export declare function spawnJavaScript(args: string[], options?: SpawnOptionsWithoutStdio, env?: NodeJS.ProcessEnv): ChildProcessWithoutNullStreams;
54
+ export declare function spawnJavaScriptSync(args: string[], options?: SpawnSyncOptions, env?: NodeJS.ProcessEnv): import("node:child_process").SpawnSyncReturns<string | NonSharedBuffer>;
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * [INPUT]: 依赖 Node/Bun 子进程、HTTP agent、代理环境变量与包管理器运行时布局
4
+ * [OUTPUT]: 对外提供代理感知请求、网络延迟探测、包管理器/JavaScript runtime 选择及进程启动函数
5
+ * [POS]: CLI 跨运行时基础设施,统一网络和子进程行为,供 API、bundle 与安装命令复用
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.isBunRuntime = void 0;
12
+ exports.runtimeFetch = runtimeFetch;
13
+ exports.resolveProxy = resolveProxy;
14
+ exports.webFetch = webFetch;
15
+ exports.proxyAgentFor = proxyAgentFor;
16
+ exports.measureTcpLatency = measureTcpLatency;
17
+ exports.detectPackageManager = detectPackageManager;
18
+ exports.getInstallCommand = getInstallCommand;
19
+ exports.getJavaScriptRuntime = getJavaScriptRuntime;
20
+ exports.spawnJavaScript = spawnJavaScript;
21
+ exports.spawnJavaScriptSync = spawnJavaScriptSync;
22
+ const child_process_1 = require("child_process");
23
+ const fs_1 = __importDefault(require("fs"));
24
+ const net_1 = require("net");
25
+ const path_1 = __importDefault(require("path"));
26
+ exports.isBunRuntime = typeof process.versions.bun ===
27
+ 'string';
28
+ function runtimeFetch(url, options) {
29
+ return webFetch(url, options);
30
+ }
31
+ // ---------------------------------------------------------------------------
32
+ // proxies
33
+ //
34
+ // Node's built-in fetch ignores HTTP(S)_PROXY, so behind a corporate proxy or
35
+ // a VPN every request of the CLI used to fail with a connection error. Every
36
+ // network path (API, uploads, source map / Hermes base downloads, the registry
37
+ // version check) resolves its proxy here, with the conventions curl, npm and
38
+ // undici share: HTTPS_PROXY for https targets (falling back to HTTP_PROXY),
39
+ // HTTP_PROXY for http targets, NO_PROXY to exempt hosts.
40
+ // ---------------------------------------------------------------------------
41
+ function firstEnv(env, ...names) {
42
+ for (const name of names) {
43
+ const value = env[name]?.trim();
44
+ if (value)
45
+ return value;
46
+ }
47
+ return undefined;
48
+ }
49
+ /**
50
+ * NO_PROXY: comma/space separated hosts; `*` exempts everything; a leading
51
+ * `.` (or `*.`) matches sub-domains, a plain host matches itself and its
52
+ * sub-domains, `host:port` only that port.
53
+ */
54
+ function matchesNoProxy(target, noProxy) {
55
+ if (!noProxy)
56
+ return false;
57
+ const host = target.hostname.toLowerCase();
58
+ const port = target.port || (target.protocol === 'https:' ? '443' : '80');
59
+ for (const raw of noProxy.split(/[\s,]+/)) {
60
+ let entry = raw.trim().toLowerCase();
61
+ if (!entry)
62
+ continue;
63
+ if (entry === '*')
64
+ return true;
65
+ let entryPort;
66
+ const withPort = /^([^:]+):(\d+)$/.exec(entry);
67
+ if (withPort) {
68
+ entry = withPort[1];
69
+ entryPort = withPort[2];
70
+ }
71
+ if (entryPort && entryPort !== port)
72
+ continue;
73
+ if (entry.startsWith('*.'))
74
+ entry = entry.slice(1);
75
+ if (entry.startsWith('.'))
76
+ entry = entry.slice(1);
77
+ if (host === entry || host.endsWith(`.${entry}`))
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+ /**
83
+ * The proxy url for `targetUrl` from the environment, or undefined for a
84
+ * direct connection (no proxy configured, NO_PROXY exempts the host, or the
85
+ * proxy is not an http(s) url).
86
+ */
87
+ function resolveProxy(targetUrl, env = process.env) {
88
+ let target;
89
+ try {
90
+ target = new URL(targetUrl);
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ if (target.protocol !== 'http:' && target.protocol !== 'https:') {
96
+ return undefined;
97
+ }
98
+ const proxy = target.protocol === 'https:'
99
+ ? firstEnv(env, 'HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy')
100
+ : firstEnv(env, 'HTTP_PROXY', 'http_proxy');
101
+ if (!proxy || matchesNoProxy(target, firstEnv(env, 'NO_PROXY', 'no_proxy'))) {
102
+ return undefined;
103
+ }
104
+ try {
105
+ const parsed = new URL(proxy);
106
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
107
+ return undefined;
108
+ }
109
+ }
110
+ catch {
111
+ return undefined;
112
+ }
113
+ return proxy;
114
+ }
115
+ const proxyDispatchers = new Map();
116
+ /**
117
+ * fetch with the WHATWG Response, through the environment's proxy when one
118
+ * applies to `url`. The proxy path goes through undici's own fetch (Node's
119
+ * built-in one cannot take a dispatcher), loaded only then.
120
+ */
121
+ function webFetch(url, init = {}) {
122
+ const proxy = resolveProxy(url);
123
+ if (proxy) {
124
+ const undici = require('undici');
125
+ let dispatcher = proxyDispatchers.get(proxy);
126
+ if (!dispatcher) {
127
+ dispatcher = new undici.ProxyAgent(proxy);
128
+ proxyDispatchers.set(proxy, dispatcher);
129
+ }
130
+ return undici.fetch(url, {
131
+ ...init,
132
+ dispatcher,
133
+ });
134
+ }
135
+ if (typeof globalThis.fetch === 'function') {
136
+ return globalThis.fetch(url, init);
137
+ }
138
+ // Node < 18 only. Loaded on demand so the built-in fetch path never pays
139
+ // for node-fetch (nor for the punycode deprecation warning it triggers on
140
+ // Node ≥ 21).
141
+ const mod = require('node-fetch');
142
+ const nodeFetch = (mod.default ?? mod);
143
+ return nodeFetch(url, init);
144
+ }
145
+ const proxyAgents = new Map();
146
+ /**
147
+ * An http.Agent routing `targetUrl` through its proxy, for the core
148
+ * http/https APIs and node-fetch (the streaming uploads); undefined when the
149
+ * connection is direct. Always a CONNECT tunnel (also for http targets, like
150
+ * undici's ProxyAgent above): the absolute-form alternative rewrites the
151
+ * request head after it was buffered, which garbles a streaming body.
152
+ */
153
+ function proxyAgentFor(targetUrl) {
154
+ const proxy = resolveProxy(targetUrl);
155
+ if (!proxy)
156
+ return undefined;
157
+ let agent = proxyAgents.get(proxy);
158
+ if (!agent) {
159
+ const { HttpsProxyAgent } = require('https-proxy-agent');
160
+ agent = new HttpsProxyAgent(proxy);
161
+ proxyAgents.set(proxy, agent);
162
+ }
163
+ return agent;
164
+ }
165
+ function resolveTcpTarget(input) {
166
+ try {
167
+ const parsed = new URL(input);
168
+ const port = parsed.port || (parsed.protocol === 'http:' ? '80' : '443');
169
+ return {
170
+ host: parsed.hostname,
171
+ port: Number(port),
172
+ };
173
+ }
174
+ catch {
175
+ const [host, port] = input.split(':');
176
+ return {
177
+ host,
178
+ port: port ? Number(port) : 443,
179
+ };
180
+ }
181
+ }
182
+ function measureTcpConnectOnce(host, port, timeout) {
183
+ return new Promise((resolve) => {
184
+ const startedAt = Date.now();
185
+ const socket = (0, net_1.createConnection)({ host, port });
186
+ const finish = (latency) => {
187
+ socket.removeAllListeners();
188
+ socket.destroy();
189
+ resolve(latency);
190
+ };
191
+ socket.setTimeout(timeout);
192
+ socket.once('connect', () => {
193
+ finish(Date.now() - startedAt);
194
+ });
195
+ socket.once('timeout', () => {
196
+ finish(Number.POSITIVE_INFINITY);
197
+ });
198
+ socket.once('error', () => {
199
+ finish(Number.POSITIVE_INFINITY);
200
+ });
201
+ });
202
+ }
203
+ async function measureTcpLatency(input, { attempts = 4, timeout = 1000, } = {}) {
204
+ const { host, port } = resolveTcpTarget(input);
205
+ const promises = Array.from({ length: attempts }, () => measureTcpConnectOnce(host, port, timeout));
206
+ const results = await Promise.all(promises);
207
+ const latencies = results.filter(Number.isFinite);
208
+ if (latencies.length === 0) {
209
+ return Number.POSITIVE_INFINITY;
210
+ }
211
+ return (latencies.reduce((sum, latency) => sum + latency, 0) / latencies.length);
212
+ }
213
+ function detectPackageManager(cwd = process.cwd(), env = process.env) {
214
+ const lockFiles = [
215
+ ['bun.lock', 'bun'],
216
+ ['bun.lockb', 'bun'],
217
+ ['pnpm-lock.yaml', 'pnpm'],
218
+ ['yarn.lock', 'yarn'],
219
+ ['package-lock.json', 'npm'],
220
+ ];
221
+ for (const [lockFile, manager] of lockFiles) {
222
+ if (fs_1.default.existsSync(path_1.default.join(cwd, lockFile))) {
223
+ return manager;
224
+ }
225
+ }
226
+ const userAgent = env.npm_config_user_agent ?? '';
227
+ if (userAgent.startsWith('bun/')) {
228
+ return 'bun';
229
+ }
230
+ if (userAgent.startsWith('pnpm/')) {
231
+ return 'pnpm';
232
+ }
233
+ if (userAgent.startsWith('yarn/')) {
234
+ return 'yarn';
235
+ }
236
+ if (userAgent.startsWith('npm/')) {
237
+ return 'npm';
238
+ }
239
+ return exports.isBunRuntime ? 'bun' : 'npm';
240
+ }
241
+ function getInstallCommand(installArgs, cwd = process.cwd()) {
242
+ const packageManager = detectPackageManager(cwd);
243
+ if (packageManager === 'npm') {
244
+ return { command: 'npm', args: ['install', ...installArgs] };
245
+ }
246
+ return { command: packageManager, args: ['add', ...installArgs] };
247
+ }
248
+ function getJavaScriptRuntime(env = process.env) {
249
+ const configured = env.RNU_JS_RUNTIME?.toLowerCase();
250
+ if (configured === 'bun') {
251
+ return 'bun';
252
+ }
253
+ if (configured === 'auto') {
254
+ return exports.isBunRuntime ? 'bun' : 'node';
255
+ }
256
+ return 'node';
257
+ }
258
+ function spawnJavaScript(args, options, env = process.env) {
259
+ return (0, child_process_1.spawn)(getJavaScriptRuntime(env), args, options ?? {});
260
+ }
261
+ function spawnJavaScriptSync(args, options, env = process.env) {
262
+ return (0, child_process_1.spawnSync)(getJavaScriptRuntime(env), args, options ?? {});
263
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Shrink a source map before archiving it with a version, without losing the
3
+ * ability to locate any frame:
4
+ *
5
+ * - absolute source paths under the project root become relative (build
6
+ * machine paths do not belong in an uploaded artifact);
7
+ * - `sourcesContent` of node_modules sources is dropped. Mappings and the
8
+ * source paths stay, so frames inside dependencies still symbolicate to
9
+ * `node_modules/...:line:column` — only the inline code snippet for those
10
+ * frames is lost, and dependency sources are recoverable from the lockfile
11
+ * anyway. On an RN app this is the bulk of the map's bytes.
12
+ *
13
+ * Returns null when the content is not a usable plain source map (invalid
14
+ * JSON, or an indexed map with `sections`); the caller then uploads the
15
+ * original file untouched.
16
+ */
17
+ export declare function slimSourceMap(content: string, projectRoot: string): string | null;
18
+ /**
19
+ * Build the bytes actually archived with a version: the slimmed map (when it
20
+ * is a plain map we understand), gzipped. Source maps are JSON and compress
21
+ * about 5x, which is the difference between a multi-megabyte upload on every
22
+ * publish and a small one. Readers detect the gzip magic bytes rather than
23
+ * trusting a file name, so plain maps archived by older CLI versions keep
24
+ * working unchanged.
25
+ */
26
+ export declare function packSourceMap(content: string, projectRoot: string): Buffer;
27
+ /** Decode an archived source map: gzip when the magic bytes say so. */
28
+ export declare function unpackSourceMap(data: Buffer): string;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.slimSourceMap = slimSourceMap;
7
+ exports.packSourceMap = packSourceMap;
8
+ exports.unpackSourceMap = unpackSourceMap;
9
+ /**
10
+ * [INPUT]: 依赖 Node path/zlib 与 source map JSON,接收构建机项目根和待归档 map
11
+ * [OUTPUT]: 对外提供 source map 瘦身、gzip 归档与兼容解包函数
12
+ * [POS]: CLI source map 归档边界,清除机器绝对路径与依赖源码内容但保留符号定位
13
+ */
14
+ const path_1 = __importDefault(require("path"));
15
+ const zlib_1 = __importDefault(require("zlib"));
16
+ /**
17
+ * Shrink a source map before archiving it with a version, without losing the
18
+ * ability to locate any frame:
19
+ *
20
+ * - absolute source paths under the project root become relative (build
21
+ * machine paths do not belong in an uploaded artifact);
22
+ * - `sourcesContent` of node_modules sources is dropped. Mappings and the
23
+ * source paths stay, so frames inside dependencies still symbolicate to
24
+ * `node_modules/...:line:column` — only the inline code snippet for those
25
+ * frames is lost, and dependency sources are recoverable from the lockfile
26
+ * anyway. On an RN app this is the bulk of the map's bytes.
27
+ *
28
+ * Returns null when the content is not a usable plain source map (invalid
29
+ * JSON, or an indexed map with `sections`); the caller then uploads the
30
+ * original file untouched.
31
+ */
32
+ function slimSourceMap(content, projectRoot) {
33
+ let map;
34
+ try {
35
+ map = JSON.parse(content);
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ if (!map || typeof map !== 'object' || Array.isArray(map)) {
41
+ return null;
42
+ }
43
+ if (map.sections !== undefined) {
44
+ return null;
45
+ }
46
+ if (!Array.isArray(map.sources)) {
47
+ return null;
48
+ }
49
+ const rootPrefix = resolveProjectRoot(projectRoot);
50
+ const sources = map.sources.map((source) => typeof source === 'string' ? relativizeSource(source, rootPrefix) : source);
51
+ map.sources = sources;
52
+ if (Array.isArray(map.sourcesContent)) {
53
+ map.sourcesContent = map.sourcesContent.map((item, index) => {
54
+ const source = sources[index];
55
+ if (typeof source === 'string' && isDependencySource(source)) {
56
+ return null;
57
+ }
58
+ return item;
59
+ });
60
+ }
61
+ return JSON.stringify(map);
62
+ }
63
+ function normalizeSlashes(value) {
64
+ return value.replace(/\\/g, '/');
65
+ }
66
+ function resolveProjectRoot(value) {
67
+ const normalized = normalizeSlashes(value);
68
+ // Source-map fixtures and CI metadata may use POSIX roots even when the
69
+ // CLI itself runs on Windows. Do not reinterpret `/work/app` as a drive
70
+ // rooted path; real Windows paths still use the host resolver below.
71
+ return normalized.startsWith('/')
72
+ ? normalizeSlashes(path_1.default.posix.resolve(normalized))
73
+ : normalizeSlashes(path_1.default.resolve(value));
74
+ }
75
+ function relativizeSource(source, rootPrefix) {
76
+ const normalized = normalizeSlashes(source);
77
+ if (normalized === rootPrefix) {
78
+ return '';
79
+ }
80
+ if (normalized.startsWith(`${rootPrefix}/`)) {
81
+ return normalized.slice(rootPrefix.length + 1);
82
+ }
83
+ return normalized;
84
+ }
85
+ function isDependencySource(source) {
86
+ return (source.startsWith('node_modules/') || source.includes('/node_modules/'));
87
+ }
88
+ /**
89
+ * Build the bytes actually archived with a version: the slimmed map (when it
90
+ * is a plain map we understand), gzipped. Source maps are JSON and compress
91
+ * about 5x, which is the difference between a multi-megabyte upload on every
92
+ * publish and a small one. Readers detect the gzip magic bytes rather than
93
+ * trusting a file name, so plain maps archived by older CLI versions keep
94
+ * working unchanged.
95
+ */
96
+ function packSourceMap(content, projectRoot) {
97
+ const slimmed = slimSourceMap(content, projectRoot);
98
+ return zlib_1.default.gzipSync(Buffer.from(slimmed ?? content, 'utf8'));
99
+ }
100
+ /** Decode an archived source map: gzip when the magic bytes say so. */
101
+ function unpackSourceMap(data) {
102
+ if (data.length >= 2 && data[0] === 0x1f && data[1] === 0x8b) {
103
+ return zlib_1.default.gunzipSync(data).toString('utf8');
104
+ }
105
+ return data.toString('utf8');
106
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * [INPUT]: 依赖 fs-extra、临时目录、路径、流式管道与 ZIP 条目元数据
3
+ * [OUTPUT]: 对外提供 ZIP 条目读取、写入、前缀读取和枚举能力
4
+ * [POS]: CLI 归档基础设施,统一本地/嵌套 ZIP 的资源访问和临时目录生命周期
5
+ */
6
+ import { type Entry, type ZipFile as YauzlZipFile } from 'yauzl';
7
+ export declare function readEntry(entry: Entry, zipFile: YauzlZipFile): Promise<Buffer>;
8
+ export declare function writeEntry(entry: Entry, zipFile: YauzlZipFile, outputPath: string): Promise<void>;
9
+ export declare function readEntryPrefix(entry: Entry, zipFile: YauzlZipFile, maxBytes: number): Promise<Buffer>;
10
+ export declare function enumZipEntries(zipFn: string, callback: (entry: Entry, zipFile: YauzlZipFile, nestedPath?: string) => Promise<any> | undefined, nestedPath?: string): Promise<unknown>;
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ /**
3
+ * [INPUT]: 依赖 fs-extra、临时目录、路径、流式管道与 ZIP 条目元数据
4
+ * [OUTPUT]: 对外提供 ZIP 条目读取、写入、前缀读取和枚举能力
5
+ * [POS]: CLI 归档基础设施,统一本地/嵌套 ZIP 的资源访问和临时目录生命周期
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.readEntry = readEntry;
45
+ exports.writeEntry = writeEntry;
46
+ exports.readEntryPrefix = readEntryPrefix;
47
+ exports.enumZipEntries = enumZipEntries;
48
+ const fs = __importStar(require("fs-extra"));
49
+ const os_1 = __importDefault(require("os"));
50
+ const path_1 = __importDefault(require("path"));
51
+ const promises_1 = require("stream/promises");
52
+ const yauzl_1 = require("yauzl");
53
+ function readEntry(entry, zipFile) {
54
+ const buffers = [];
55
+ return new Promise((resolve, reject) => {
56
+ zipFile.openReadStream(entry, (err, stream) => {
57
+ if (err) {
58
+ return reject(err);
59
+ }
60
+ if (!stream) {
61
+ return reject(new Error(`Unable to read zip entry: ${entry.fileName}`));
62
+ }
63
+ stream.on('data', (chunk) => {
64
+ buffers.push(chunk);
65
+ });
66
+ stream.on('end', () => {
67
+ // a single chunk (a cached Range read) is handed back as-is, not copied
68
+ resolve(buffers.length === 1 ? buffers[0] : Buffer.concat(buffers));
69
+ });
70
+ stream.on('error', (err) => {
71
+ reject(err);
72
+ });
73
+ });
74
+ });
75
+ }
76
+ function writeEntry(entry, zipFile, outputPath) {
77
+ fs.ensureDirSync(path_1.default.dirname(outputPath));
78
+ return new Promise((resolve, reject) => {
79
+ zipFile.openReadStream(entry, (err, stream) => {
80
+ if (err) {
81
+ reject(err);
82
+ return;
83
+ }
84
+ if (!stream) {
85
+ reject(new Error(`Unable to read zip entry: ${entry.fileName}`));
86
+ return;
87
+ }
88
+ (0, promises_1.pipeline)(stream, fs.createWriteStream(outputPath)).then(resolve, reject);
89
+ });
90
+ });
91
+ }
92
+ function readEntryPrefix(entry, zipFile, maxBytes) {
93
+ if (maxBytes <= 0) {
94
+ return Promise.resolve(Buffer.alloc(0));
95
+ }
96
+ const buffers = [];
97
+ let length = 0;
98
+ return new Promise((resolve, reject) => {
99
+ zipFile.openReadStream(entry, (err, stream) => {
100
+ if (err) {
101
+ return reject(err);
102
+ }
103
+ if (!stream) {
104
+ return reject(new Error(`Unable to read zip entry: ${entry.fileName}`));
105
+ }
106
+ let settled = false;
107
+ let expectedDestroyError;
108
+ const cleanup = () => {
109
+ stream.off('data', onData);
110
+ stream.off('end', onEnd);
111
+ stream.off('error', onError);
112
+ };
113
+ const finish = (destroyStream = false) => {
114
+ if (settled) {
115
+ return;
116
+ }
117
+ settled = true;
118
+ stream.off('data', onData);
119
+ stream.off('end', onEnd);
120
+ if (!destroyStream) {
121
+ stream.off('error', onError);
122
+ }
123
+ resolve(Buffer.concat(buffers, length));
124
+ if (destroyStream) {
125
+ expectedDestroyError = new Error('zip entry prefix read complete');
126
+ stream.destroy(expectedDestroyError);
127
+ }
128
+ };
129
+ const onData = (chunk) => {
130
+ const remaining = maxBytes - length;
131
+ if (remaining <= 0) {
132
+ finish(true);
133
+ return;
134
+ }
135
+ const slice = chunk.length > remaining ? chunk.subarray(0, remaining) : chunk;
136
+ buffers.push(slice);
137
+ length += slice.length;
138
+ if (length >= maxBytes) {
139
+ finish(true);
140
+ }
141
+ };
142
+ const onEnd = () => finish();
143
+ const onError = (error) => {
144
+ if (settled && error === expectedDestroyError) {
145
+ cleanup();
146
+ return;
147
+ }
148
+ if (settled) {
149
+ return;
150
+ }
151
+ settled = true;
152
+ cleanup();
153
+ reject(error);
154
+ };
155
+ stream.on('data', onData);
156
+ stream.once('end', onEnd);
157
+ stream.once('error', onError);
158
+ });
159
+ });
160
+ }
161
+ async function enumZipEntries(zipFn, callback, nestedPath = '') {
162
+ return new Promise((resolve, reject) => {
163
+ (0, yauzl_1.open)(zipFn, { lazyEntries: true }, async (err, zipfile) => {
164
+ if (err) {
165
+ return reject(err);
166
+ }
167
+ zipfile.on('end', resolve);
168
+ zipfile.on('error', reject);
169
+ zipfile.on('entry', async (entry) => {
170
+ const fullPath = nestedPath + entry.fileName;
171
+ try {
172
+ if (!entry.fileName.endsWith('/') &&
173
+ entry.fileName.toLowerCase().endsWith('.hap')) {
174
+ const tempDir = await fs.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'nested_zip_'));
175
+ const tempZipPath = path_1.default.join(tempDir, 'temp.zip');
176
+ try {
177
+ await new Promise((res, rej) => {
178
+ zipfile.openReadStream(entry, async (err, readStream) => {
179
+ if (err)
180
+ return rej(err);
181
+ const writeStream = fs.createWriteStream(tempZipPath);
182
+ readStream.on('error', rej);
183
+ readStream.pipe(writeStream);
184
+ writeStream.on('finish', () => res(void 0));
185
+ writeStream.on('error', rej);
186
+ });
187
+ });
188
+ await enumZipEntries(tempZipPath, callback, `${fullPath}/`);
189
+ }
190
+ finally {
191
+ await fs.remove(tempDir);
192
+ }
193
+ }
194
+ const result = callback(entry, zipfile, fullPath);
195
+ if (result && typeof result.then === 'function') {
196
+ await result;
197
+ }
198
+ }
199
+ catch (error) {
200
+ // the rejection carries the error; logging it here too would make
201
+ // callers report it twice
202
+ zipfile.close();
203
+ reject(error);
204
+ return;
205
+ }
206
+ zipfile.readEntry();
207
+ });
208
+ zipfile.readEntry();
209
+ });
210
+ });
211
+ }