tirtc-devtools-cli 0.0.9 → 0.0.11

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 (115) hide show
  1. package/README.md +17 -11
  2. package/USAGE.md +72 -33
  3. package/bin/tirtc-devtools-cli.js +1 -1
  4. package/dist/cli/src/bootstrap_flows.d.ts +46 -0
  5. package/dist/cli/src/bootstrap_flows.js +249 -0
  6. package/dist/{devtools/cli → cli}/src/config.d.ts +4 -15
  7. package/dist/{devtools/cli → cli}/src/config.js +7 -31
  8. package/dist/cli/src/default_paths.d.ts +3 -0
  9. package/dist/cli/src/default_paths.js +23 -0
  10. package/dist/{devtools/cli → cli}/src/embedded_paths.d.ts +1 -0
  11. package/dist/{devtools/cli → cli}/src/embedded_paths.js +18 -1
  12. package/dist/{devtools/cli → cli}/src/facade.d.ts +41 -235
  13. package/dist/{devtools/cli → cli}/src/facade.js +8 -27
  14. package/dist/cli/src/guide.js +47 -0
  15. package/dist/{devtools/cli → cli}/src/index.js +55 -141
  16. package/dist/{devtools/cli → cli}/src/session_manager.js +9 -11
  17. package/dist/{devtools/cli → cli}/src/token_command.js +69 -0
  18. package/dist/{devtools/cli → cli}/src/token_tool.d.ts +26 -0
  19. package/dist/{devtools/cli → cli}/src/token_tool.js +123 -22
  20. package/dist/{devtools/cli → cli}/src/transport.d.ts +1 -1
  21. package/package.json +6 -2
  22. package/script/ensure_ffmpeg.sh +1 -1
  23. package/vendor/app-server/bin/native/linux-x64/credential_napi.node +0 -0
  24. package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
  25. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/credential.h +34 -0
  26. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/error.h +13 -0
  27. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/foundation/build_info.h +27 -0
  28. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/http.h +57 -0
  29. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/logging.h +3 -1
  30. package/vendor/app-server/bin/runtime/linux-x64/lib/libcrypto.a +0 -0
  31. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_credential.a +0 -0
  32. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_http.a +0 -0
  33. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  34. package/vendor/app-server/bin/runtime/linux-x64/lib/libssl.a +0 -0
  35. package/vendor/app-server/bin/runtime/linux-x64/manifest.txt +2 -32
  36. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +176 -133
  37. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +223 -182
  38. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +2 -0
  39. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +6 -0
  40. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/transport.h +58 -133
  41. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +47 -224
  42. package/vendor/app-server/bin/runtime/macos-arm64/lib/libTGTRP.a +0 -0
  43. package/vendor/app-server/bin/runtime/macos-arm64/lib/libTiRTC.a +0 -0
  44. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
  45. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
  46. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
  47. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
  48. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  49. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
  50. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
  51. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
  52. package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +19 -15
  53. package/vendor/app-server/dist/host/HostCommandCoordinator.d.ts +19 -0
  54. package/vendor/app-server/dist/host/HostCommandCoordinator.js +196 -0
  55. package/vendor/app-server/dist/host/HostProtocol.d.ts +1 -11
  56. package/vendor/app-server/dist/host/HostProtocol.js +3 -37
  57. package/vendor/app-server/dist/host/HostServer.d.ts +1 -4
  58. package/vendor/app-server/dist/host/HostServer.js +16 -152
  59. package/vendor/app-server/dist/host/RuntimeAdapter.js +2 -2
  60. package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +3 -3
  61. package/vendor/app-server/dist/host/native/RuntimeHostBridge.js +4 -4
  62. package/vendor/app-server/dist/host/runtime_backed_preflight.js +2 -2
  63. package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.js +1 -1
  64. package/vendor/app-server/dist/protocol/contract.d.ts +5 -64
  65. package/vendor/app-server/dist/protocol/contract.js +3 -12
  66. package/dist/devtools/cli/src/guide.js +0 -50
  67. package/dist/dummy.d.ts +0 -0
  68. package/dist/dummy.js +0 -1
  69. package/dist/index.d.ts +0 -1
  70. package/dist/index.js +0 -48
  71. package/vendor/app-server/bin/native/macos-arm64/libcrypto.dylib +0 -0
  72. package/vendor/app-server/bin/native/macos-arm64/libssl.dylib +0 -0
  73. package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
  74. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_codec.h +0 -23
  75. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_frame.h +0 -36
  76. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io.h +0 -56
  77. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_android.h +0 -19
  78. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_apple.h +0 -19
  79. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_harmony.h +0 -19
  80. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_windows.h +0 -19
  81. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_processing.h +0 -56
  82. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_sample_rate.h +0 -18
  83. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_codec.h +0 -21
  84. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_downlink.h +0 -89
  85. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_uplink.h +0 -115
  86. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/runtime.h +0 -236
  87. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_codec.h +0 -57
  88. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_frame.h +0 -55
  89. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io.h +0 -46
  90. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_android.h +0 -32
  91. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_apple.h +0 -34
  92. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_harmony.h +0 -32
  93. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_windows.h +0 -26
  94. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_processing.h +0 -34
  95. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_audio.a +0 -0
  96. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
  97. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_media.a +0 -0
  98. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_video.a +0 -0
  99. package/vendor/app-server/bin/runtime/linux-x64/lib/libwebrtc_apm.a +0 -0
  100. package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.d.ts +0 -30
  101. package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.js +0 -224
  102. /package/dist/{devtools/cli → cli}/src/dummy.d.ts +0 -0
  103. /package/dist/{devtools/cli → cli}/src/dummy.js +0 -0
  104. /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.d.ts +0 -0
  105. /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.js +0 -0
  106. /package/dist/{devtools/cli → cli}/src/guide.d.ts +0 -0
  107. /package/dist/{devtools/cli → cli}/src/index.d.ts +0 -0
  108. /package/dist/{devtools/cli → cli}/src/media_assets.d.ts +0 -0
  109. /package/dist/{devtools/cli → cli}/src/media_assets.js +0 -0
  110. /package/dist/{devtools/cli → cli}/src/progress.d.ts +0 -0
  111. /package/dist/{devtools/cli → cli}/src/progress.js +0 -0
  112. /package/dist/{devtools/cli → cli}/src/session_manager.d.ts +0 -0
  113. /package/dist/{devtools/cli → cli}/src/token_command.d.ts +0 -0
  114. /package/dist/{devtools/cli → cli}/src/transport.js +0 -0
  115. /package/vendor/app-server/bin/{native/macos-arm64 → runtime/macos-arm64/lib}/libtgrtc.dylib +0 -0
@@ -1,21 +1,17 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const commander_1 = require("commander");
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const protocol_client_1 = require("../../../app-server/protocol-client");
10
- const facade_1 = require("./facade");
4
+ const protocol_client_1 = require("../../app-server/protocol-client");
5
+ const bootstrap_flows_1 = require("./bootstrap_flows");
11
6
  const config_1 = require("./config");
7
+ const facade_1 = require("./facade");
12
8
  const guide_1 = require("./guide");
13
9
  const session_manager_1 = require("./session_manager");
14
10
  const media_assets_1 = require("./media_assets");
15
11
  const token_command_1 = require("./token_command");
16
12
  const transport_1 = require("./transport");
17
13
  const progress_1 = require("./progress");
18
- const CLI_VERSION = '0.0.9';
14
+ const CLI_VERSION = '0.0.10';
19
15
  const HOST_VERSION = '1.0.0';
20
16
  const PROTOCOL_VERSION = '1.0.0';
21
17
  if (process.argv.includes('--version') || process.argv.includes('-V')) {
@@ -29,6 +25,16 @@ function getCliOptions() {
29
25
  return program.opts();
30
26
  }
31
27
  function normalizeError(error) {
28
+ if (typeof error === 'object' && error !== null) {
29
+ const typed = error;
30
+ if (typed.reasonCode || typed.message || typed.data !== undefined) {
31
+ return {
32
+ reasonCode: typed.reasonCode ?? 'internal_error',
33
+ message: typed.message ?? 'Internal error',
34
+ data: typed.data,
35
+ };
36
+ }
37
+ }
32
38
  if (error instanceof Error) {
33
39
  return {
34
40
  reasonCode: 'internal_error',
@@ -36,14 +42,6 @@ function normalizeError(error) {
36
42
  data: undefined,
37
43
  };
38
44
  }
39
- if (typeof error === 'object' && error !== null) {
40
- const typed = error;
41
- return {
42
- reasonCode: typed.reasonCode ?? 'internal_error',
43
- message: typed.message ?? 'Internal error',
44
- data: typed.data,
45
- };
46
- }
47
45
  return {
48
46
  reasonCode: 'internal_error',
49
47
  message: 'Internal error',
@@ -55,18 +53,14 @@ function createSessionTransport(sessionId) {
55
53
  return new transport_1.SocketTransport(session.socketPath);
56
54
  }
57
55
  function isBootstrapCommand(cmdName) {
58
- return cmdName === 'service start' || cmdName === 'connection connect';
56
+ return cmdName === 'service start' || cmdName === 'connection connect' || cmdName === 'client start';
59
57
  }
60
- function resolveSessionForCommand(cmdName, options, config) {
61
- const sessionOptions = {
62
- logRootDir: config.logging?.root_dir,
63
- consoleMirror: config.logging?.console_mirror,
64
- };
65
- if (cmdName === 'connection connect') {
58
+ function resolveSessionForCommand(cmdName, options) {
59
+ if (cmdName === 'connection connect' || cmdName === 'client start') {
66
60
  if (options.session && options.session.trim().length > 0) {
67
- throw new Error('connection connect always creates a new session; do not pass --session');
61
+ throw new Error(cmdName + ' always creates a new session; do not pass --session');
68
62
  }
69
- const created = (0, session_manager_1.createSession)({ ...sessionOptions, role: 'client' });
63
+ const created = (0, session_manager_1.createSession)({ role: 'client' });
70
64
  return { sessionId: created.sessionId, created: true };
71
65
  }
72
66
  if (cmdName === 'service start') {
@@ -75,7 +69,7 @@ function resolveSessionForCommand(cmdName, options, config) {
75
69
  (0, session_manager_1.setSessionRole)(existing.sessionId, 'service');
76
70
  return { sessionId: existing.sessionId, created: false };
77
71
  }
78
- const created = (0, session_manager_1.createSession)({ ...sessionOptions, role: 'service' });
72
+ const created = (0, session_manager_1.createSession)({ role: 'service' });
79
73
  return { sessionId: created.sessionId, created: true };
80
74
  }
81
75
  if (cmdName === 'debug bootstrap qrcode') {
@@ -109,104 +103,21 @@ function toResultObject(result) {
109
103
  }
110
104
  function requireConfigPath(configPath) {
111
105
  if (!configPath || configPath.trim().length === 0) {
112
- throw new Error('server-only service start requires --config <path>');
106
+ throw new Error('command requires --config <path>');
113
107
  }
114
108
  return configPath;
115
109
  }
116
- function validateServerConfig(config) {
117
- const server = config.server;
118
- const license = server?.license?.trim() ?? '';
119
- const mp4Path = server?.mp4_path?.trim() ?? '';
120
- const audioStreamIdValue = server?.audio_stream_id;
121
- const videoStreamIdValue = server?.video_stream_id;
122
- if (license.length === 0) {
123
- throw new Error('server-only config requires [server].license');
124
- }
125
- if (mp4Path.length === 0) {
126
- throw new Error('server-only config requires [server].mp4_path');
127
- }
128
- if (typeof audioStreamIdValue !== 'number') {
129
- throw new Error('server-only config requires [server].audio_stream_id as non-negative integer');
130
- }
131
- if (!Number.isInteger(audioStreamIdValue) || audioStreamIdValue < 0) {
132
- throw new Error('server-only config requires [server].audio_stream_id as non-negative integer');
133
- }
134
- if (typeof videoStreamIdValue !== 'number') {
135
- throw new Error('server-only config requires [server].video_stream_id as non-negative integer');
136
- }
137
- if (!Number.isInteger(videoStreamIdValue) || videoStreamIdValue < 0) {
138
- throw new Error('server-only config requires [server].video_stream_id as non-negative integer');
139
- }
140
- const audioStreamId = audioStreamIdValue;
141
- const videoStreamId = videoStreamIdValue;
142
- if (audioStreamId === videoStreamId) {
143
- throw new Error('server-only config requires distinct audio_stream_id and video_stream_id');
144
- }
145
- const resolvedMp4Path = path_1.default.resolve(mp4Path);
146
- let stats;
147
- try {
148
- stats = fs_1.default.statSync(resolvedMp4Path);
149
- }
150
- catch {
151
- throw new Error('server-only config mp4_path does not exist: ' + resolvedMp4Path);
152
- }
153
- if (!stats.isFile()) {
154
- throw new Error('server-only config mp4_path must be a readable file: ' + resolvedMp4Path);
155
- }
156
- const serviceEntry = server?.service_entry?.trim();
157
- return {
158
- serviceEntry: serviceEntry && serviceEntry.length > 0 ? serviceEntry : undefined,
159
- license,
160
- mp4Path: resolvedMp4Path,
161
- audioStreamId,
162
- videoStreamId,
163
- };
164
- }
165
110
  function createProgressIndicator(options) {
166
111
  if (options.json) {
167
112
  return undefined;
168
113
  }
169
114
  return new progress_1.ProgressIndicator();
170
115
  }
171
- function resolvePrepareOutputRoot(config) {
172
- const loggingRoot = config.logging?.root_dir?.trim();
173
- if (loggingRoot && loggingRoot.length > 0) {
174
- return path_1.default.resolve(loggingRoot, '..', 'prepared-assets');
175
- }
176
- return path_1.default.resolve(process.cwd(), '.tmp', 'tirtc-devtools-cli', 'prepared-assets');
177
- }
178
- async function applyConfiguredServerBootstrap(client, config, progress) {
179
- const server = validateServerConfig(config);
180
- progress?.start('Preparing MP4 assets');
181
- const prepared = await (0, media_assets_1.prepareMediaAssets)({
182
- source: server.mp4Path,
183
- outputRoot: resolvePrepareOutputRoot(config),
184
- });
185
- progress?.update('Prepared MP4 assets');
186
- const bootstrapSendStreams = [
187
- { streamId: server.audioStreamId, media: 'audio' },
188
- { streamId: server.videoStreamId, media: 'video' },
189
- ].map(({ streamId, media }) => ({
190
- streamId,
191
- media,
192
- source: {
193
- mode: 'local_assets',
194
- local_assets: {
195
- assets_dir: prepared.assets_dir,
196
- },
197
- },
198
- }));
199
- return {
200
- preparedAssetsDir: prepared.assets_dir,
201
- mediaSendPolicy: 'AUTO_ON_CONNECTED',
202
- bootstrapSendStreams,
203
- };
204
- }
205
116
  async function runCommand(cmdName, params, options) {
206
117
  let transport;
207
118
  try {
208
119
  const config = (0, config_1.loadConfig)(options.config);
209
- const session = resolveSessionForCommand(cmdName, options, config);
120
+ const session = resolveSessionForCommand(cmdName, options);
210
121
  transport = createSessionTransport(session.sessionId);
211
122
  const client = new protocol_client_1.AppServerClient(transport);
212
123
  await client.initialize({ name: 'tirtc-devtools-cli', version: CLI_VERSION });
@@ -218,7 +129,7 @@ async function runCommand(cmdName, params, options) {
218
129
  if (cmdName === 'service start') {
219
130
  const progress = createProgressIndicator(options);
220
131
  try {
221
- const autoApplied = await applyConfiguredServerBootstrap(client, config, progress);
132
+ const autoApplied = await (0, bootstrap_flows_1.applyConfiguredServerBootstrap)(client, config, progress);
222
133
  progress?.update('Starting service session');
223
134
  const requestParams = {
224
135
  ...params,
@@ -240,6 +151,20 @@ async function runCommand(cmdName, params, options) {
240
151
  throw error;
241
152
  }
242
153
  }
154
+ if (cmdName === 'client start') {
155
+ const progress = createProgressIndicator(options);
156
+ try {
157
+ const token = String(params.token ?? '');
158
+ const result = await (0, bootstrap_flows_1.applyClientStartBootstrap)(client, config, token, progress);
159
+ printSuccess(options, result, session, cmdName);
160
+ transport.stop();
161
+ return 0;
162
+ }
163
+ catch (error) {
164
+ progress?.fail('Client start failed');
165
+ throw error;
166
+ }
167
+ }
243
168
  const result = await client.sendRequest(method, params);
244
169
  resultForPrint = result;
245
170
  printSuccess(options, resultForPrint, session, cmdName);
@@ -353,7 +278,7 @@ program.name('tirtc-devtools-cli')
353
278
  .description('TiRTC DevTools CLI')
354
279
  .option('--config <path>', '配置文件路径(TOML)')
355
280
  .option('--json', '以机器可读 JSON 输出(便于脚本集成)')
356
- .option('--session <sessionId>', '指定会话 ID;除 service start/connect 外必须传');
281
+ .option('--session <sessionId>', '指定会话 ID;除 service start / client start / connection connect 外必须传');
357
282
  const host = program.command('host').description('Host 基础能力(状态、停止)');
358
283
  host.command('status').description('查看 Host/service/connection/artifact 当前状态').action(() => {
359
284
  runAndExit(runCommand('host status', {}, getCliOptions()));
@@ -390,10 +315,7 @@ const hostSession = host.command('session').description('会话管理:start/li
390
315
  hostSession.command('start').description('创建并启动一个常驻会话,返回 sessionId').action(() => {
391
316
  try {
392
317
  const options = getCliOptions();
393
- const config = (0, config_1.loadConfig)(options.config);
394
318
  const created = (0, session_manager_1.createSession)({
395
- logRootDir: config.logging?.root_dir,
396
- consoleMirror: config.logging?.console_mirror,
397
319
  role: 'idle',
398
320
  });
399
321
  if (options.json) {
@@ -503,49 +425,41 @@ service.command('start')
503
425
  .action(() => {
504
426
  const options = getCliOptions();
505
427
  const config = (0, config_1.loadConfig)(requireConfigPath(options.config));
506
- const server = validateServerConfig(config);
428
+ const server = (0, bootstrap_flows_1.validateServerConfig)(config);
507
429
  runAndExit(runCommand('service start', { serviceEntry: server.serviceEntry, license: server.license, timeoutMs: 5000 }, options));
508
430
  });
509
431
  service.command('stop').description('停止服务端监听').action(() => {
510
432
  runAndExit(runCommand('service stop', {}, getCliOptions()));
511
433
  });
434
+ const client = program.command('client').description('客户端正式入口:连接远端并自动挂载本地 web preview');
435
+ client.command('start')
436
+ .description('读取 [client] 配置,连接远端并输出 web preview 地址')
437
+ .requiredOption('--token <token>', '显式 client token;不支持 auto token')
438
+ .action((commandOptions) => {
439
+ const options = getCliOptions();
440
+ (0, config_1.loadConfig)(requireConfigPath(options.config));
441
+ runAndExit(runCommand('client start', { token: commandOptions.token }, options));
442
+ });
512
443
  const connection = program.command('connection').description('客户端能力:主动连接远端 peer');
513
444
  connection.command('show').description('查看连接状态').action(() => {
514
445
  runAndExit(runCommand('connection show', {}, getCliOptions()));
515
446
  });
516
- connection.command('connect [service_entry] <peer_id> [token]')
517
- .description('作为客户端连接远端(总是新建 session;不传 token 时自动签发)')
447
+ connection.command('connect [service_entry] <peer_id> <token>')
448
+ .description('作为客户端连接远端(总是新建 session;要求显式 token')
518
449
  .action((serviceEntry, peerId, token) => {
519
450
  const config = (0, config_1.loadConfig)(getCliOptions().config);
520
- const finalServiceEntry = [serviceEntry, config.connection?.service_entry, config.server?.service_entry]
451
+ const finalServiceEntry = [serviceEntry, config.client?.service_entry, config.server?.service_entry]
521
452
  .find((value) => typeof value === 'string' && value.trim().length > 0);
522
- const configuredToken = config.connection?.token?.trim();
523
- const manualToken = (token ?? configuredToken)?.trim();
524
- const autoTokenCfg = config.connection?.auto_token;
525
- const hasAutoToken = Boolean(autoTokenCfg?.access_id && autoTokenCfg?.secret_key);
526
- if (!manualToken && !hasAutoToken) {
527
- throw new Error('connection connect requires token or [connection.auto_token] access_id/secret_key');
453
+ const manualToken = token.trim();
454
+ if (manualToken.length === 0) {
455
+ throw new Error('connection connect requires non-empty token');
528
456
  }
529
457
  const params = {
530
458
  serviceEntry: finalServiceEntry,
531
459
  peerId,
460
+ token: manualToken,
532
461
  timeoutMs: 5000,
533
462
  };
534
- if (manualToken && manualToken.length > 0) {
535
- params.token = manualToken;
536
- params.tokenMode = 'manual';
537
- }
538
- else {
539
- params.tokenMode = 'auto';
540
- params.autoToken = {
541
- openapiEntry: autoTokenCfg?.openapi_entry,
542
- accessId: autoTokenCfg?.access_id,
543
- secretKey: autoTokenCfg?.secret_key,
544
- localId: autoTokenCfg?.local_id ?? peerId,
545
- userTtlSeconds: autoTokenCfg?.user_ttl_seconds,
546
- channelTtlSeconds: autoTokenCfg?.channel_ttl_seconds,
547
- };
548
- }
549
463
  runAndExit(runCommand('connection connect', params, getCliOptions()));
550
464
  });
551
465
  connection.command('disconnect').description('断开当前连接').action(() => {
@@ -14,6 +14,7 @@ const os_1 = __importDefault(require("os"));
14
14
  const path_1 = __importDefault(require("path"));
15
15
  const crypto_1 = require("crypto");
16
16
  const child_process_1 = require("child_process");
17
+ const default_paths_1 = require("./default_paths");
17
18
  const embedded_paths_1 = require("./embedded_paths");
18
19
  const kStartupTimeoutMs = 5000;
19
20
  const kStartupPollIntervalMs = 100;
@@ -26,11 +27,7 @@ function sleepMs(ms) {
26
27
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
27
28
  }
28
29
  function getStateDir() {
29
- const explicit = process.env.TIRTC_DEVTOOL_STATE_DIR;
30
- if (explicit && explicit.trim().length > 0) {
31
- return explicit.trim();
32
- }
33
- return path_1.default.join(os_1.default.homedir(), '.tirtc-devtools-cli');
30
+ return (0, default_paths_1.resolveCliStateRootDir)();
34
31
  }
35
32
  function getSocketDir() {
36
33
  const explicit = process.env.TIRTC_DEVTOOL_SOCKET_DIR;
@@ -148,10 +145,10 @@ function getHostBinaryPath() {
148
145
  return embedded;
149
146
  }
150
147
  const candidates = [
151
- path_1.default.resolve(__dirname, '../../../app-server/bin/tirtc-devtool-host.js'),
152
- path_1.default.resolve(__dirname, '../../../../../../app-server/bin/tirtc-devtool-host.js'),
153
- path_1.default.resolve(process.cwd(), '../app-server/bin/tirtc-devtool-host.js'),
154
- path_1.default.resolve(process.cwd(), 'app-server/bin/tirtc-devtool-host.js'),
148
+ path_1.default.resolve(__dirname, '../../../products/app-server/bin/tirtc-devtool-host.js'),
149
+ path_1.default.resolve(__dirname, '../../../../../../products/app-server/bin/tirtc-devtool-host.js'),
150
+ path_1.default.resolve(process.cwd(), '../products/app-server/bin/tirtc-devtool-host.js'),
151
+ path_1.default.resolve(process.cwd(), 'products/app-server/bin/tirtc-devtool-host.js'),
155
152
  ];
156
153
  for (const candidate of candidates) {
157
154
  if (fs_1.default.existsSync(candidate)) {
@@ -191,7 +188,7 @@ function waitForSocketReady(socketPath, pid) {
191
188
  throw new Error(`session startup timeout: socket not ready within ${kStartupTimeoutMs}ms`);
192
189
  }
193
190
  function resolveDefaultLogRootDir() {
194
- return path_1.default.resolve(process.cwd(), '.tmp/tirtc-devtools-cli/logging');
191
+ return (0, default_paths_1.resolveCliLogRootDir)();
195
192
  }
196
193
  function createSession(options) {
197
194
  const runtimePlatform = resolveRuntimePlatform();
@@ -285,7 +282,8 @@ function killLingeringHostProcesses() {
285
282
  if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) {
286
283
  continue;
287
284
  }
288
- if (!command.includes('app-server/bin/tirtc-devtool-host.js')) {
285
+ if (!command.includes('products/app-server/bin/tirtc-devtool-host.js') &&
286
+ !command.includes('vendor/app-server/bin/tirtc-devtool-host.js')) {
289
287
  continue;
290
288
  }
291
289
  if (!command.includes('--socket /tmp/tirtc-')) {
@@ -67,6 +67,29 @@ async function runTokenIssue(params, options) {
67
67
  return printTokenCommandError(error, options);
68
68
  }
69
69
  }
70
+ async function runLicenseQrcode(params, options) {
71
+ try {
72
+ const result = await (0, token_tool_1.buildLicenseQrcode)(params);
73
+ if (options.json) {
74
+ console.log(JSON.stringify({
75
+ code: 0,
76
+ message: 'OK',
77
+ data: {
78
+ payload: result.payload,
79
+ payloadJson: result.payloadJson,
80
+ qrCodePngPath: result.qrCodePngPath,
81
+ },
82
+ }));
83
+ }
84
+ else {
85
+ console.log((0, token_tool_1.formatLicenseQrcodeConsoleOutput)(result));
86
+ }
87
+ return 0;
88
+ }
89
+ catch (error) {
90
+ return printTokenCommandError(error, options);
91
+ }
92
+ }
70
93
  function resolveTokenIssueCredential(explicitValue, envVarName, optionName) {
71
94
  const normalizedExplicit = explicitValue?.trim();
72
95
  if (normalizedExplicit) {
@@ -120,6 +143,43 @@ async function runTokenIssueFromCli(peerId, commandOptions, options) {
120
143
  return printTokenCommandError(error, options);
121
144
  }
122
145
  }
146
+ async function runLicenseQrcodeFromCli(license, commandOptions, options) {
147
+ const parsePositiveInt = (name, raw) => {
148
+ if (raw === undefined) {
149
+ return undefined;
150
+ }
151
+ const parsed = Number.parseInt(raw, 10);
152
+ if (!Number.isInteger(parsed) || parsed <= 0) {
153
+ throw new Error(name + ' must be a positive integer');
154
+ }
155
+ return parsed;
156
+ };
157
+ const parseQrErrorCorrectionLevel = (raw) => {
158
+ if (raw === undefined) {
159
+ return undefined;
160
+ }
161
+ const normalized = raw.trim().toUpperCase();
162
+ if (normalized !== 'L' && normalized !== 'M' && normalized !== 'Q' && normalized !== 'H') {
163
+ throw new Error('qr-error-correction-level must be one of: L, M, Q, H');
164
+ }
165
+ return normalized;
166
+ };
167
+ try {
168
+ const normalizedLicense = license.trim();
169
+ if (normalizedLicense.length === 0) {
170
+ throw new Error('license must not be empty');
171
+ }
172
+ return await runLicenseQrcode({
173
+ license: normalizedLicense,
174
+ serviceEntry: commandOptions.serviceEntry,
175
+ qrErrorCorrectionLevel: parseQrErrorCorrectionLevel(commandOptions.qrErrorCorrectionLevel),
176
+ asciiMaxColumns: parsePositiveInt('ascii-max-columns', commandOptions.asciiMaxColumns),
177
+ }, options);
178
+ }
179
+ catch (error) {
180
+ return printTokenCommandError(error, options);
181
+ }
182
+ }
123
183
  function registerTokenCommands(program, getCliOptions, runAndExit) {
124
184
  const token = program.command('token').description('Token 工具:签发 token,并输出可直接使用的 JSON 与本地二维码 PNG');
125
185
  token.command('issue <peer_id>')
@@ -136,4 +196,13 @@ function registerTokenCommands(program, getCliOptions, runAndExit) {
136
196
  .action((peerId, commandOptions) => {
137
197
  runAndExit(runTokenIssueFromCli(peerId, commandOptions, getCliOptions()));
138
198
  });
199
+ const license = program.command('license').description('License 工具:生成 server 扫码 JSON 与本地二维码 PNG');
200
+ license.command('qrcode <license>')
201
+ .description('生成包含 license 与可选 service_entry 的本地二维码')
202
+ .option('--service-entry <entry>', '可选 service entry;留空时消费端走默认值')
203
+ .option('--qr-error-correction-level <level>', '二维码纠错级别:L/M/Q/H;默认 M')
204
+ .option('--ascii-max-columns <columns>', 'ASCII 二维码最大宽度;不传时优先读取当前终端宽度或 COLUMNS')
205
+ .action((licenseValue, commandOptions) => {
206
+ runAndExit(runLicenseQrcodeFromCli(licenseValue, commandOptions, getCliOptions()));
207
+ });
139
208
  }
@@ -30,9 +30,35 @@ export type TokenIssueOutput = {
30
30
  qrCodeAscii: string;
31
31
  qrCodeAsciiIncluded: boolean;
32
32
  };
33
+ export type LicenseQrcodeInput = {
34
+ license: string;
35
+ serviceEntry?: string;
36
+ qrErrorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
37
+ asciiMaxColumns?: number;
38
+ };
39
+ export type LicenseQrcodePayload = {
40
+ license: string;
41
+ service_entry: string;
42
+ };
43
+ export type LicenseQrcodeOutput = {
44
+ payload: LicenseQrcodePayload;
45
+ payloadJson: string;
46
+ qrCodePngPath: string;
47
+ qrCodeAscii: string;
48
+ qrCodeAsciiIncluded: boolean;
49
+ };
50
+ export declare function resolveIssueTokenEnvironment(runtimePlatform?: string, fromDir?: string): {
51
+ runtimePlatform: string;
52
+ runtimeBundleRoot: string;
53
+ repoRoot: string;
54
+ addonPath: string;
55
+ };
33
56
  export declare function issueToken(input: TokenIssueInput): Promise<string>;
34
57
  export declare function buildIssuedTokenPayload(input: TokenIssueInput, token: string): IssuedTokenPayload;
58
+ export declare function buildLicenseQrcodePayload(input: LicenseQrcodeInput): LicenseQrcodePayload;
35
59
  export declare function writePngQrcode(payloadJson: string, outputPath: string, errorCorrectionLevel: 'L' | 'M' | 'Q' | 'H'): Promise<string>;
36
60
  export declare function buildAsciiQrcode(payloadJson: string, terminalColumns?: number, errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'): Promise<string>;
37
61
  export declare function issueTokenWithQrcode(input: TokenIssueInput): Promise<TokenIssueOutput>;
62
+ export declare function buildLicenseQrcode(input: LicenseQrcodeInput): Promise<LicenseQrcodeOutput>;
38
63
  export declare function formatTokenIssueConsoleOutput(output: TokenIssueOutput): string;
64
+ export declare function formatLicenseQrcodeConsoleOutput(output: LicenseQrcodeOutput): string;