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
package/lib/app.d.ts ADDED
@@ -0,0 +1,107 @@
1
+ import type { ServiceChannel } from './api';
2
+ import type { Platform } from './types';
3
+ interface AppSummary {
4
+ id: string | number;
5
+ name: string;
6
+ platform: Platform;
7
+ }
8
+ export interface AppTargetOptions {
9
+ appId?: string;
10
+ config?: string;
11
+ platform?: Platform | '';
12
+ }
13
+ export interface ResolvedChannel {
14
+ channel: ServiceChannel;
15
+ created: boolean;
16
+ }
17
+ /** The selected-app config file was missing or has no entry for the platform. */
18
+ export declare class AppNotSelectedError extends Error {
19
+ readonly code = "APP_NOT_SELECTED";
20
+ constructor(platform: Platform);
21
+ }
22
+ /** Resolve an explicit platform or prompt for one interactively. */
23
+ export declare function getPlatform(platform?: string): Promise<Platform>;
24
+ /** Validate that a string names a platform supported by the update service. */
25
+ export declare function assertPlatform(platform: string): Platform;
26
+ /** Read the selected app for a platform from the requested config file. */
27
+ export declare function getSelectedApp(platform: Platform, configPath?: string): Promise<{
28
+ appId: string;
29
+ appKey: string;
30
+ platform: Platform;
31
+ }>;
32
+ /** Resolve a standalone channel and create it on first use when absent. */
33
+ export declare function getOrCreateChannel(appId: string, code: string): Promise<ResolvedChannel>;
34
+ /**
35
+ * Resolve the app an operation targets: an explicit `--appId` wins, otherwise
36
+ * the app selected for the platform in `--config` (default: update.json).
37
+ * Prompts for the platform only when it is needed and not given.
38
+ */
39
+ export declare function resolveAppId(options?: AppTargetOptions): Promise<string>;
40
+ /** List apps, optionally filtering them to one platform. */
41
+ export declare function listApp(platform?: Platform | ''): Promise<AppSummary[]>;
42
+ /** Prompt until the user chooses an app belonging to the target platform. */
43
+ export declare function chooseApp(platform: Platform): Promise<AppSummary>;
44
+ /** Persist an app selection in the requested brand-aware config file. */
45
+ declare function selectApp({ args, options, }: {
46
+ args: string[];
47
+ options: {
48
+ platform?: Platform | '';
49
+ config?: string;
50
+ };
51
+ }): Promise<void>;
52
+ /** Build the application-management command handlers used by the CLI. */
53
+ export declare function getAppCommands(): {
54
+ /** Create an app and select it in the same configuration file. */
55
+ createApp: ({ options, }: {
56
+ options: {
57
+ name: string;
58
+ downloadUrl: string;
59
+ platform?: Platform | '';
60
+ config?: string;
61
+ };
62
+ }) => Promise<void>;
63
+ /** Delete the specified app, or prompt for one when no ID is supplied. */
64
+ deleteApp: ({ args, options, }: {
65
+ args: string[];
66
+ options: {
67
+ platform: Platform;
68
+ };
69
+ }) => Promise<void>;
70
+ /** List apps through the command interface. */
71
+ apps: ({ options }: {
72
+ options: {
73
+ platform?: Platform | '';
74
+ };
75
+ }) => Promise<AppSummary[]>;
76
+ /** List channels without exposing service-internal UUIDs as input. */
77
+ channels: ({ options }: {
78
+ options: AppTargetOptions & {
79
+ json?: boolean;
80
+ };
81
+ }) => Promise<ServiceChannel[]>;
82
+ /** Create a channel; the default channel is created with the application. */
83
+ createChannel: ({ options }: {
84
+ options: AppTargetOptions & {
85
+ code: string;
86
+ name: string;
87
+ nativePackageUrl?: string;
88
+ paused?: boolean;
89
+ json?: boolean;
90
+ };
91
+ }) => Promise<any>;
92
+ updateChannel: ({ args, options }: {
93
+ args: string[];
94
+ options: AppTargetOptions & {
95
+ code: string;
96
+ name: string;
97
+ nativePackageUrl?: string;
98
+ paused?: boolean;
99
+ json?: boolean;
100
+ };
101
+ }) => Promise<any>;
102
+ deleteChannel: ({ args }: {
103
+ args: string[];
104
+ }) => Promise<void>;
105
+ selectApp: typeof selectApp;
106
+ };
107
+ export {};
package/lib/app.js ADDED
@@ -0,0 +1,329 @@
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.AppNotSelectedError = void 0;
7
+ exports.getPlatform = getPlatform;
8
+ exports.assertPlatform = assertPlatform;
9
+ exports.getSelectedApp = getSelectedApp;
10
+ exports.getOrCreateChannel = getOrCreateChannel;
11
+ exports.resolveAppId = resolveAppId;
12
+ exports.listApp = listApp;
13
+ exports.chooseApp = chooseApp;
14
+ exports.getAppCommands = getAppCommands;
15
+ /**
16
+ * [INPUT]: 依赖 CLI API、update.json 配置和平台交互提示
17
+ * [OUTPUT]: 对外提供应用选择、应用 CRUD、独立服务渠道 CRUD 与缺失渠道幂等创建
18
+ * [POS]: CLI 目标解析层,负责把平台/应用/渠道身份收敛为服务端 UUID,并为发布命令补齐渠道
19
+ */
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const api_1 = require("./api");
22
+ const utils_1 = require("./utils");
23
+ const constants_1 = require("./utils/constants");
24
+ const http_helper_1 = require("./utils/http-helper");
25
+ const i18n_1 = require("./utils/i18n");
26
+ /** The selected-app config file was missing or has no entry for the platform. */
27
+ class AppNotSelectedError extends Error {
28
+ code = 'APP_NOT_SELECTED';
29
+ constructor(platform) {
30
+ super((0, i18n_1.t)('appNotSelected', { platform }));
31
+ this.name = 'AppNotSelectedError';
32
+ }
33
+ }
34
+ exports.AppNotSelectedError = AppNotSelectedError;
35
+ /** Resolve an explicit platform or prompt for one interactively. */
36
+ async function getPlatform(platform) {
37
+ return assertPlatform(platform || (await (0, utils_1.question)((0, i18n_1.t)('platformQuestion'))));
38
+ }
39
+ /** Validate that a string names a platform supported by the update service. */
40
+ function assertPlatform(platform) {
41
+ if (platform !== 'ios' && platform !== 'android' && platform !== 'harmony') {
42
+ throw new Error((0, i18n_1.t)('unsupportedPlatform', { platform }));
43
+ }
44
+ return platform;
45
+ }
46
+ /** Parse a legacy positive integer or an RFC 9562 UUID used by standalone services. */
47
+ function parseAppId(value) {
48
+ if ((0, http_helper_1.isStandaloneService)() && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
49
+ return value;
50
+ }
51
+ const id = Number(value);
52
+ if (!/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(id)) {
53
+ throw new Error((0, i18n_1.t)('invalidId', { id: value }));
54
+ }
55
+ return String(id);
56
+ }
57
+ /** Read the selected app for a platform from the requested config file. */
58
+ async function getSelectedApp(platform, configPath) {
59
+ assertPlatform(platform);
60
+ const resolvedConfigPath = configPath || constants_1.updateJson;
61
+ let raw;
62
+ try {
63
+ raw = await fs_1.default.promises.readFile(resolvedConfigPath, 'utf8');
64
+ }
65
+ catch (e) {
66
+ if (e.code === 'ENOENT') {
67
+ throw new AppNotSelectedError(platform);
68
+ }
69
+ throw e;
70
+ }
71
+ let updateInfo;
72
+ try {
73
+ updateInfo = JSON.parse(raw);
74
+ }
75
+ catch {
76
+ throw new Error((0, i18n_1.t)('failedToParseUpdateJson', { configPath: resolvedConfigPath }));
77
+ }
78
+ const info = updateInfo[platform];
79
+ if (!info) {
80
+ throw new AppNotSelectedError(platform);
81
+ }
82
+ return {
83
+ appId: String(info.appId),
84
+ appKey: info.appKey,
85
+ platform,
86
+ };
87
+ }
88
+ /** Resolve a standalone channel and create it on first use when absent. */
89
+ async function getOrCreateChannel(appId, code) {
90
+ const normalizedCode = code.trim().toLowerCase();
91
+ if (!normalizedCode) {
92
+ throw new Error('渠道 code 不能为空。');
93
+ }
94
+ const findChannel = (channels) => channels.find((channel) => channel.code.trim().toLowerCase() === normalizedCode);
95
+ const existing = findChannel(await (0, api_1.getChannels)(appId));
96
+ if (existing) {
97
+ return { channel: existing, created: false };
98
+ }
99
+ try {
100
+ return {
101
+ channel: await (0, api_1.createChannel)(appId, normalizedCode, normalizedCode),
102
+ created: true,
103
+ };
104
+ }
105
+ catch (error) {
106
+ // Two CLI processes may race to create the same channel. Re-read before
107
+ // surfacing the original failure so the loser remains idempotent.
108
+ try {
109
+ const concurrent = findChannel(await (0, api_1.getChannels)(appId));
110
+ if (concurrent) {
111
+ return { channel: concurrent, created: false };
112
+ }
113
+ }
114
+ catch {
115
+ // Preserve the original create error when the recovery lookup fails.
116
+ }
117
+ throw error;
118
+ }
119
+ }
120
+ /**
121
+ * Fail fast when an explicit `--appId` names an app of another platform.
122
+ * The server accepts a bundle for any app the account owns and never sees
123
+ * the platform it was built for, so this is the only place the mistake can
124
+ * be caught before it reaches devices. A missing or foreign app fails here
125
+ * too (403/404) instead of after the expensive work.
126
+ */
127
+ async function assertAppPlatform(appId, platform) {
128
+ const app = (0, api_1.unwrapData)(await (0, api_1.get)((0, http_helper_1.isStandaloneService)() ? (0, api_1.servicePath)(`/apps/${encodeURIComponent(appId)}`) : `/app/${appId}`));
129
+ if (app.platform && app.platform !== platform) {
130
+ throw new Error((0, i18n_1.t)('appPlatformMismatch', { appId, appPlatform: app.platform, platform }));
131
+ }
132
+ return app;
133
+ }
134
+ /**
135
+ * Resolve the app an operation targets: an explicit `--appId` wins, otherwise
136
+ * the app selected for the platform in `--config` (default: update.json).
137
+ * Prompts for the platform only when it is needed and not given.
138
+ */
139
+ async function resolveAppId(options = {}) {
140
+ if (options.platform) {
141
+ assertPlatform(options.platform);
142
+ }
143
+ if (options.appId) {
144
+ const appId = String(options.appId);
145
+ if (options.platform) {
146
+ await assertAppPlatform(appId, options.platform);
147
+ }
148
+ return appId;
149
+ }
150
+ const platform = await getPlatform(options.platform || undefined);
151
+ return (await getSelectedApp(platform, options.config)).appId;
152
+ }
153
+ /** List apps, optionally filtering them to one platform. */
154
+ async function listApp(platform = '') {
155
+ const response = await (0, api_1.get)((0, http_helper_1.isStandaloneService)()
156
+ ? (0, api_1.servicePath)('/apps?page=1&pageSize=100')
157
+ : '/app/list');
158
+ const page = (0, api_1.unwrapData)(response);
159
+ const allApps = (0, http_helper_1.isStandaloneService)()
160
+ ? (page?.items ?? [])
161
+ : (response?.data ?? []);
162
+ const list = platform
163
+ ? allApps.filter((app) => app.platform === platform)
164
+ : allApps;
165
+ const header = [
166
+ { value: (0, i18n_1.t)('appId') },
167
+ { value: (0, i18n_1.t)('appName') },
168
+ { value: (0, i18n_1.t)('platform') },
169
+ ];
170
+ const rows = [];
171
+ for (const app of list) {
172
+ rows.push([app.id, app.name, app.platform]);
173
+ }
174
+ // tty-table is ~25 ms to load; only pay for it when a table is rendered
175
+ const Table = (0, utils_1.loadTtyTable)();
176
+ console.log(Table(header, rows).render());
177
+ console.log(`\n${(0, i18n_1.t)('totalApps', { count: list.length, platform })}`);
178
+ return list;
179
+ }
180
+ /** Prompt until the user chooses an app belonging to the target platform. */
181
+ async function chooseApp(platform) {
182
+ // Fail before a network request or table output when no prompt is possible.
183
+ if ((0, utils_1.isNonInteractive)()) {
184
+ throw new Error((0, i18n_1.t)('appIdRequired'));
185
+ }
186
+ const list = await listApp(platform);
187
+ while (true) {
188
+ const id = await (0, utils_1.question)((0, i18n_1.t)('enterAppIdQuestion'));
189
+ const app = list.find((item) => String(item.id) === id);
190
+ if (app) {
191
+ return app;
192
+ }
193
+ }
194
+ }
195
+ /** Persist an app selection in the requested brand-aware config file. */
196
+ async function selectApp({ args, options, }) {
197
+ const platform = await getPlatform(options.platform);
198
+ const id = args[0]
199
+ ? parseAppId(args[0])
200
+ : (await chooseApp(platform)).id;
201
+ if (!id) {
202
+ throw new Error((0, i18n_1.t)('invalidId', { id: args[0] }));
203
+ }
204
+ const app = await assertAppPlatform(String(id), platform);
205
+ if (typeof app.appKey !== 'string' || !app.appKey) {
206
+ throw new Error((0, i18n_1.t)('appKeyMissing', { appId: id }));
207
+ }
208
+ const appKey = app.appKey;
209
+ const configPath = options.config || constants_1.updateJson;
210
+ let updateInfo = {};
211
+ try {
212
+ updateInfo = JSON.parse(await fs_1.default.promises.readFile(configPath, 'utf8'));
213
+ }
214
+ catch (e) {
215
+ if (e.code !== 'ENOENT') {
216
+ console.error((0, i18n_1.t)('failedToParseUpdateJson', { configPath }));
217
+ throw e;
218
+ }
219
+ }
220
+ updateInfo[platform] = {
221
+ // 遗留服务沿用数字 appId 的历史契约;独立服务才可能写入 UUID。
222
+ appId: /^[1-9]\d*$/.test(String(id)) ? Number(id) : id,
223
+ appKey,
224
+ };
225
+ await fs_1.default.promises.writeFile(configPath, JSON.stringify(updateInfo, null, 4), 'utf8');
226
+ }
227
+ /** Build the application-management command handlers used by the CLI. */
228
+ function getAppCommands() {
229
+ return {
230
+ /** Create an app and select it in the same configuration file. */
231
+ createApp: async ({ options, }) => {
232
+ const name = options.name || (await (0, utils_1.question)((0, i18n_1.t)('appNameQuestion')));
233
+ const { downloadUrl } = options;
234
+ const platform = await getPlatform(options.platform);
235
+ const created = (0, api_1.unwrapData)(await (0, api_1.post)((0, http_helper_1.isStandaloneService)() ? (0, api_1.servicePath)('/apps') : '/app/create', (0, http_helper_1.isStandaloneService)()
236
+ ? {
237
+ name,
238
+ platform,
239
+ ...(downloadUrl ? { nativePackageUrl: downloadUrl } : {}),
240
+ }
241
+ : { name, platform, downloadUrl }));
242
+ const { id } = created;
243
+ console.log((0, i18n_1.t)('createAppSuccess', { id }));
244
+ await selectApp({
245
+ args: [String(id)],
246
+ options: { platform, config: options.config },
247
+ });
248
+ },
249
+ /** Delete the specified app, or prompt for one when no ID is supplied. */
250
+ deleteApp: async ({ args, options, }) => {
251
+ const { platform } = options;
252
+ const id = args[0]
253
+ ? parseAppId(args[0])
254
+ : (await chooseApp(platform)).id;
255
+ if (!id) {
256
+ console.log((0, i18n_1.t)('cancelled'));
257
+ return;
258
+ }
259
+ await (0, api_1.doDelete)((0, http_helper_1.isStandaloneService)()
260
+ ? (0, api_1.servicePath)(`/apps/${encodeURIComponent(String(id))}`)
261
+ : `/app/${id}`);
262
+ console.log((0, i18n_1.t)('operationSuccess'));
263
+ },
264
+ /** List apps through the command interface. */
265
+ apps: async ({ options }) => {
266
+ const { platform = '' } = options;
267
+ return listApp(platform);
268
+ },
269
+ /** List channels without exposing service-internal UUIDs as input. */
270
+ channels: async ({ options }) => {
271
+ const appId = await resolveAppId(options);
272
+ if (!(0, http_helper_1.isStandaloneService)()) {
273
+ throw new Error('渠道管理需要独立服务(请设置 RNU_SERVICE_URL)。');
274
+ }
275
+ const channels = await (0, api_1.getChannels)(appId);
276
+ if (options.json) {
277
+ console.log(JSON.stringify(channels, null, 2));
278
+ }
279
+ else {
280
+ for (const channel of channels) {
281
+ console.log(`${channel.code}\t${channel.name}\t${channel.id}${channel.paused ? '\tpaused' : ''}`);
282
+ }
283
+ }
284
+ return channels;
285
+ },
286
+ /** Create a channel; the default channel is created with the application. */
287
+ createChannel: async ({ options }) => {
288
+ const appId = await resolveAppId(options);
289
+ if (!(0, http_helper_1.isStandaloneService)()) {
290
+ throw new Error('渠道管理需要独立服务(请设置 RNU_SERVICE_URL)。');
291
+ }
292
+ const channel = (0, api_1.unwrapData)(await (0, api_1.post)((0, api_1.servicePath)(`/apps/${encodeURIComponent(appId)}/channels`), {
293
+ code: options.code,
294
+ name: options.name,
295
+ nativePackageUrl: options.nativePackageUrl || '',
296
+ paused: Boolean(options.paused),
297
+ }));
298
+ console.log(options.json ? JSON.stringify(channel, null, 2) : `已创建渠道 ${options.code}`);
299
+ return channel;
300
+ },
301
+ updateChannel: async ({ args, options }) => {
302
+ const channelId = args[0];
303
+ if (!channelId)
304
+ throw new Error('updateChannel 需要 channelId。');
305
+ if (!(0, http_helper_1.isStandaloneService)()) {
306
+ throw new Error('渠道管理需要独立服务(请设置 RNU_SERVICE_URL)。');
307
+ }
308
+ const channel = (0, api_1.unwrapData)(await (0, api_1.put)((0, api_1.servicePath)(`/channels/${encodeURIComponent(channelId)}`), {
309
+ code: options.code,
310
+ name: options.name,
311
+ nativePackageUrl: options.nativePackageUrl || '',
312
+ paused: Boolean(options.paused),
313
+ }));
314
+ console.log(options.json ? JSON.stringify(channel, null, 2) : `已更新渠道 ${channelId}`);
315
+ return channel;
316
+ },
317
+ deleteChannel: async ({ args }) => {
318
+ const channelId = args[0];
319
+ if (!channelId)
320
+ throw new Error('deleteChannel 需要 channelId。');
321
+ if (!(0, http_helper_1.isStandaloneService)()) {
322
+ throw new Error('渠道管理需要独立服务(请设置 RNU_SERVICE_URL)。');
323
+ }
324
+ await (0, api_1.doDelete)((0, api_1.servicePath)(`/channels/${encodeURIComponent(channelId)}`));
325
+ console.log((0, i18n_1.t)('operationSuccess'));
326
+ },
327
+ selectApp,
328
+ };
329
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * [INPUT]: 依赖 Node 子进程、文件系统、环境变量、全局包管理器布局与本地化文案
3
+ * [OUTPUT]: 对外提供 PackageManager、AutoUpdateNotice、全局包管理器探测及后台更新编排
4
+ * [POS]: CLI 后台自更新边界,负责包管理器归属、锁与失败重试,不参与前台命令分发
5
+ */
6
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
7
+ export interface AutoUpdateNotice {
8
+ kind: 'updated' | 'permission';
9
+ currentVersion: string;
10
+ targetVersion: string;
11
+ command?: string;
12
+ }
13
+ interface PackageManagerDetectionOptions {
14
+ packageRoot: string;
15
+ env?: NodeJS.ProcessEnv;
16
+ npmGlobalDir?: string;
17
+ yarnGlobalDir?: string;
18
+ }
19
+ /**
20
+ * Identify the package manager that owns this global installation. Project
21
+ * lockfiles are deliberately ignored: they say how the app is installed, not
22
+ * how this CLI was installed.
23
+ */
24
+ export declare function detectGlobalPackageManager({ packageRoot, env, npmGlobalDir, yarnGlobalDir, }: PackageManagerDetectionOptions): PackageManager | undefined;
25
+ export declare function buildUpdateCommand(manager: PackageManager, targetVersion: string, registryUrl: string, installPrefix?: string): {
26
+ command: string;
27
+ args: string[];
28
+ };
29
+ /**
30
+ * Start a detached updater after the foreground command has completed. This
31
+ * function is synchronous on purpose: it is safe to call from process.exit.
32
+ */
33
+ export declare function launchAutoUpdate(currentVersion: string, targetVersion: string | undefined, env?: NodeJS.ProcessEnv): boolean;
34
+ export declare function consumeAutoUpdateNotice(currentVersion: string): AutoUpdateNotice | undefined;
35
+ export {};