tirtc-devtools-cli 0.0.5 → 0.0.7

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 (37) hide show
  1. package/README.md +4 -2
  2. package/USAGE.md +152 -365
  3. package/dist/devtools/cli/src/config.d.ts +4 -13
  4. package/dist/devtools/cli/src/config.js +7 -19
  5. package/dist/devtools/cli/src/facade.d.ts +39 -154
  6. package/dist/devtools/cli/src/facade.js +9 -23
  7. package/dist/devtools/cli/src/guide.js +7 -9
  8. package/dist/devtools/cli/src/index.js +146 -248
  9. package/dist/devtools/cli/src/progress.d.ts +19 -0
  10. package/dist/devtools/cli/src/progress.js +63 -0
  11. package/dist/devtools/cli/src/token_command.d.ts +7 -0
  12. package/dist/devtools/cli/src/token_command.js +139 -0
  13. package/package.json +1 -1
  14. package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
  15. package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
  16. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +30 -17
  17. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
  18. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
  19. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
  20. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
  21. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  22. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
  23. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
  24. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
  25. package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +10 -10
  26. package/vendor/app-server/dist/host/HostProtocol.d.ts +7 -5
  27. package/vendor/app-server/dist/host/HostProtocol.js +21 -10
  28. package/vendor/app-server/dist/host/HostServer.d.ts +2 -2
  29. package/vendor/app-server/dist/host/HostServer.js +93 -35
  30. package/vendor/app-server/dist/host/HostState.d.ts +0 -5
  31. package/vendor/app-server/dist/host/HostState.js +0 -1
  32. package/vendor/app-server/dist/host/RuntimeAdapter.d.ts +12 -0
  33. package/vendor/app-server/dist/host/RuntimeAdapter.js +42 -3
  34. package/vendor/app-server/dist/host/RuntimeSendWorker.d.ts +4 -0
  35. package/vendor/app-server/dist/host/RuntimeSendWorker.js +17 -0
  36. package/vendor/app-server/dist/protocol/contract.d.ts +72 -14
  37. package/vendor/app-server/dist/protocol/contract.js +11 -8
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerTokenCommands = registerTokenCommands;
4
+ const facade_1 = require("./facade");
5
+ const token_tool_1 = require("./token_tool");
6
+ const kTokenIssueAccessIdEnvVar = 'TIRTC_CONN_ACCESS_ID';
7
+ const kTokenIssueSecretKeyEnvVar = 'TIRTC_CONN_SECRET_KEY';
8
+ function normalizeTokenCommandError(error) {
9
+ if (error instanceof Error) {
10
+ return {
11
+ reasonCode: 'internal_error',
12
+ message: error.message,
13
+ data: undefined,
14
+ };
15
+ }
16
+ if (typeof error === 'object' && error !== null) {
17
+ const typed = error;
18
+ return {
19
+ reasonCode: typed.reasonCode ?? 'internal_error',
20
+ message: typed.message ?? 'Internal error',
21
+ data: typed.data,
22
+ };
23
+ }
24
+ return {
25
+ reasonCode: 'internal_error',
26
+ message: 'Internal error',
27
+ data: undefined,
28
+ };
29
+ }
30
+ function printTokenCommandError(error, options) {
31
+ const normalized = normalizeTokenCommandError(error);
32
+ const reasonCode = normalized.reasonCode;
33
+ const exitCode = facade_1.ErrorReasonCodeMapping[reasonCode] ?? 1;
34
+ if (options.json) {
35
+ console.log(JSON.stringify({
36
+ code: exitCode,
37
+ message: normalized.message,
38
+ data: normalized.data,
39
+ }));
40
+ }
41
+ else {
42
+ console.error('Error (' + reasonCode + '): ' + normalized.message);
43
+ }
44
+ return exitCode;
45
+ }
46
+ async function runTokenIssue(params, options) {
47
+ try {
48
+ const result = await (0, token_tool_1.issueTokenWithQrcode)(params);
49
+ if (options.json) {
50
+ console.log(JSON.stringify({
51
+ code: 0,
52
+ message: 'OK',
53
+ data: {
54
+ payload: result.payload,
55
+ payloadJson: result.payloadJson,
56
+ token: result.token,
57
+ qrCodePngPath: result.qrCodePngPath,
58
+ },
59
+ }));
60
+ }
61
+ else {
62
+ console.log((0, token_tool_1.formatTokenIssueConsoleOutput)(result));
63
+ }
64
+ return 0;
65
+ }
66
+ catch (error) {
67
+ return printTokenCommandError(error, options);
68
+ }
69
+ }
70
+ function resolveTokenIssueCredential(explicitValue, envVarName, optionName) {
71
+ const normalizedExplicit = explicitValue?.trim();
72
+ if (normalizedExplicit) {
73
+ return normalizedExplicit;
74
+ }
75
+ const normalizedEnv = process.env[envVarName]?.trim();
76
+ if (normalizedEnv) {
77
+ return normalizedEnv;
78
+ }
79
+ throw new Error('missing credential: set environment variable ' + envVarName +
80
+ ' or pass ' + optionName + ' explicitly');
81
+ }
82
+ async function runTokenIssueFromCli(peerId, commandOptions, options) {
83
+ const parsePositiveInt = (name, raw) => {
84
+ if (raw === undefined) {
85
+ return undefined;
86
+ }
87
+ const parsed = Number.parseInt(raw, 10);
88
+ if (!Number.isInteger(parsed) || parsed <= 0) {
89
+ throw new Error(name + ' must be a positive integer');
90
+ }
91
+ return parsed;
92
+ };
93
+ const parseQrErrorCorrectionLevel = (raw) => {
94
+ if (raw === undefined) {
95
+ return undefined;
96
+ }
97
+ const normalized = raw.trim().toUpperCase();
98
+ if (normalized !== 'L' && normalized !== 'M' && normalized !== 'Q' && normalized !== 'H') {
99
+ throw new Error('qr-error-correction-level must be one of: L, M, Q, H');
100
+ }
101
+ return normalized;
102
+ };
103
+ try {
104
+ const accessId = resolveTokenIssueCredential(commandOptions.accessId, kTokenIssueAccessIdEnvVar, '--access-id');
105
+ const secretKey = resolveTokenIssueCredential(commandOptions.secretKey, kTokenIssueSecretKeyEnvVar, '--secret-key');
106
+ return await runTokenIssue({
107
+ accessId,
108
+ secretKey,
109
+ localId: commandOptions.localId?.trim() || peerId,
110
+ peerId,
111
+ openapiEntry: commandOptions.openapiEntry,
112
+ serviceEntry: commandOptions.serviceEntry,
113
+ userTtlSeconds: parsePositiveInt('user-ttl-seconds', commandOptions.userTtlSeconds),
114
+ channelTtlSeconds: parsePositiveInt('channel-ttl-seconds', commandOptions.channelTtlSeconds),
115
+ qrErrorCorrectionLevel: parseQrErrorCorrectionLevel(commandOptions.qrErrorCorrectionLevel),
116
+ asciiMaxColumns: parsePositiveInt('ascii-max-columns', commandOptions.asciiMaxColumns),
117
+ }, options);
118
+ }
119
+ catch (error) {
120
+ return printTokenCommandError(error, options);
121
+ }
122
+ }
123
+ function registerTokenCommands(program, getCliOptions, runAndExit) {
124
+ const token = program.command('token').description('Token 工具:签发 token,并输出可直接使用的 JSON 与本地二维码 PNG');
125
+ token.command('issue <peer_id>')
126
+ .description('默认从环境变量读取 access/secret,并以 peer_id 作为默认 local_id 来签发 token')
127
+ .option('--access-id <accessId>', '显式 access id;不传时读取 ' + kTokenIssueAccessIdEnvVar)
128
+ .option('--secret-key <secretKey>', '显式 secret key;不传时读取 ' + kTokenIssueSecretKeyEnvVar)
129
+ .option('--local-id <localId>', '显式 local id;不传时默认使用 peer_id')
130
+ .option('--openapi-entry <url>', '可选 openapi entry;留空时走 runtime 默认值')
131
+ .option('--service-entry <entry>', '可选 service entry;用于组合连接 payload 与二维码 PNG')
132
+ .option('--user-ttl-seconds <seconds>', '可选 user token ttl(秒)')
133
+ .option('--channel-ttl-seconds <seconds>', '可选 channel token ttl(秒)')
134
+ .option('--qr-error-correction-level <level>', '二维码纠错级别:L/M/Q/H;默认 M')
135
+ .option('--ascii-max-columns <columns>', 'ASCII 二维码最大宽度;不传时优先读取当前终端宽度或 COLUMNS')
136
+ .action((peerId, commandOptions) => {
137
+ runAndExit(runTokenIssueFromCli(peerId, commandOptions, getCliOptions()));
138
+ });
139
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirtc-devtools-cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -154,6 +154,20 @@ typedef struct TirtcConnConnectOptions {
154
154
  const char* token;
155
155
  } TirtcConnConnectOptions;
156
156
 
157
+ /**
158
+ * @brief Optional observer bound when a connection object is created.
159
+ *
160
+ * The implementation copies the observer structure and stores the supplied
161
+ * user_data pointer with the created connection handle.
162
+ */
163
+ typedef struct TirtcConnCreateOptions {
164
+ /** @brief Optional observer copied into the new connection object. */
165
+ const struct TirtcConnObserver* observer;
166
+
167
+ /** @brief Opaque pointer returned to observer callbacks. */
168
+ void* user_data;
169
+ } TirtcConnCreateOptions;
170
+
157
171
  /** @brief Opaque handle returned by ::tirtc_conn_service_start. */
158
172
  typedef struct TirtcConnService TirtcConnService;
159
173
 
@@ -376,17 +390,12 @@ typedef struct TirtcConnServiceObserver {
376
390
  /**
377
391
  * @brief Optional observer for connection lifecycle and control-plane events.
378
392
  *
379
- * The implementation stores a copy of this structure. Passing NULL to
380
- * ::tirtc_conn_set_observer clears the current observer.
381
- *
382
- * Replay contract:
383
- * - Installing or replacing an observer immediately replays the current state.
384
- * - If the connection has already disconnected, the terminal disconnected
385
- * callback is replayed as part of observer installation.
393
+ * The implementation stores a copy of this structure inside the owning
394
+ * connection object.
386
395
  *
387
396
  * Callback threading is not restricted to a single caller thread. Some
388
- * callbacks may be replayed synchronously by API calls such as
389
- * ::tirtc_conn_set_observer, while others may arrive asynchronously from the
397
+ * callbacks may be replayed synchronously when a connection object becomes
398
+ * visible to the caller, while others may arrive asynchronously from the
390
399
  * internal transport layer.
391
400
  */
392
401
  typedef struct TirtcConnObserver {
@@ -475,25 +484,29 @@ TirtcError tirtc_conn_service_stop(TirtcConnService* service);
475
484
  * The runtime must already be initialized. The returned handle starts in
476
485
  * ::TIRTC_CONN_STATE_IDLE and must be released with ::tirtc_conn_destroy.
477
486
  *
487
+ * The observer, when provided, becomes part of the connection object's stable
488
+ * lifecycle contract. After creation succeeds, reconnects on the same handle
489
+ * keep using that observer.
490
+ *
491
+ * @param options Optional creation options. Pass NULL to create a connection
492
+ * without an observer.
478
493
  * @param out_connection Receives the created connection handle on success.
479
494
  * @return ::TIRTC_ERROR_OK on success.
480
495
  */
481
- TirtcError tirtc_conn_create(TirtcConn** out_connection);
496
+ TirtcError tirtc_conn_create(const TirtcConnCreateOptions* options, TirtcConn** out_connection);
482
497
 
483
498
  /**
484
499
  * @brief Install, replace, or clear the connection observer.
485
500
  *
501
+ * This legacy API remains available for accepted service connections and
502
+ * existing consumers that still bind observers after handle creation.
503
+ * New standalone-connection callers should prefer binding the observer through
504
+ * ::TirtcConnCreateOptions.
505
+ *
486
506
  * Passing NULL for ::observer clears the current observer and its user data.
487
- * The implementation stores a copy of the observer structure and does not
488
- * require it to outlive this call.
489
507
  * After a non-NULL observer is installed, the implementation immediately
490
508
  * replays the current state and, when applicable, the terminal disconnected
491
509
  * callback.
492
- *
493
- * @param connection Target connection.
494
- * @param observer Observer to install, or NULL to clear.
495
- * @param user_data Opaque pointer returned to observer callbacks.
496
- * @return ::TIRTC_ERROR_OK on success.
497
510
  */
498
511
  TirtcError tirtc_conn_set_observer(TirtcConn* connection, const TirtcConnObserver* observer,
499
512
  void* user_data);
@@ -1,5 +1,5 @@
1
1
  platform=macos-arm64
2
- staged_at_utc=2026-04-09T05:56:18Z
2
+ staged_at_utc=2026-04-09T14:57:31Z
3
3
  source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/macos-arm64
4
4
 
5
5
  dcca0b7ab8055d84e5bcfab7f1dde56df9037c40ddb99e9ca924ef2e867d8309 include/tirtc/audio.h
@@ -25,7 +25,7 @@ ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/
25
25
  a4f8ab44c1a20ad37f250363a403a9d4d007e61ddb2426c7966dbc05f6a04b4f include/tirtc/media_live_source.h
26
26
  1b3be6954e547f91a047866438bff1820c8406afaf91cef68ddee29a6ac70234 include/tirtc/media_uplink.h
27
27
  1e12daf9c5fc2e2f848444688081c9be0cb738245f0155327e8003b49308058f include/tirtc/transport.h
28
- 99b4b31b8359009ee74f0f2a52be6473d9c6c37b184e53eeb554d4bf61f6ee33 include/tirtc/trp.h
28
+ 137729c534213cb161c0853a8d4d38fcdc397c41a7fd8c813fbe0e80083ec931 include/tirtc/trp.h
29
29
  dff5b0a0ac4a40ad17c93e1e56b3c416371c81ab365e287ea8cd6ce37ccbed3b include/tirtc/video_codec.h
30
30
  e51379666c199588cc33279ccf52248035d1cae3d1d468b1615ebf29f0b39c9c include/tirtc/video_frame.h
31
31
  d920afad955b9f206b02b19ca152315190fa84ab6f24e895a5b24c3ab9ffd701 include/tirtc/video_io.h
@@ -36,14 +36,14 @@ cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/
36
36
  8cd6b66bea14890a665cc317f8572429b2c3e4463773f8b77c1e4dc30a4a8747 include/tirtc/video_processing.h
37
37
  b39daee6a3d39bf0ca20c45084601133c4198de8dca848dcff6dd9c70ae99016 lib/libcrypto.a
38
38
  c052857ef315e3d61db9c862cad10709a3a6b2487dc41799cbe4d74a805de875 lib/libcrypto.dylib
39
- 6ad596f3ad055be11f121f418aeff4e02c650f3cec6b37c471ed54e9498a1268 lib/libmatrix_runtime_audio.a
40
- 42d1a2e4aa59d53c0c35ad204a365b7d7d83698c21857f5ffe7421da240da3e1 lib/libmatrix_runtime_credential.a
41
- 2153ac1352ebb401f7920e8358c4988f9bd7f5275009ab94f6c4b7d7eb2a71c3 lib/libmatrix_runtime_facade.a
42
- 25d70d18d4b69e0f28514035811a4ae8e18a1dcbcdd88d6a68e3d7609e2537bb lib/libmatrix_runtime_foundation_http.a
43
- 78b82c288d2e58f1219d5f56772a1dc8683e8da5f2f4724c160e6bf97f9ddadc lib/libmatrix_runtime_foundation_logging.a
44
- 548230c283e262838d2492ae28817870cd191eb3b9cb3e943446645562a2e20f lib/libmatrix_runtime_media.a
45
- e5afb3d24fd62ad5f4fd68ea7ba65957e79bf27d5669a8d6bceb44aa9f297c16 lib/libmatrix_runtime_transport.a
46
- e0a087c9d0b0c929a20677db1aa8e053813baa3682458f407f04dc751d0d225a lib/libmatrix_runtime_video.a
39
+ 240fb613f79b39ce4ed74ebd2e56c714141a0ef858f106e1121c7d540cea7e64 lib/libmatrix_runtime_audio.a
40
+ e1070b1e7b262ad8a8e1dbec1ac9d524fbf4a7fdcc855bb84f69bdd13f31ae9d lib/libmatrix_runtime_credential.a
41
+ 7081b1021d32939a1cbf399bbfa2b4f72a74e7eb48f111f34c80450f8d8a4bfe lib/libmatrix_runtime_facade.a
42
+ d268be4f9309c1af33f7734a692e0bf89402c96a6fe689f6d7df691d5563b391 lib/libmatrix_runtime_foundation_http.a
43
+ d7c51d52995b0c1be194fafb3d922b98f8c87eccbfb3a240bad1d4b7b27de1b2 lib/libmatrix_runtime_foundation_logging.a
44
+ 37332652b4cb75f1d6a0a3a7209013d05ec55874b5103b89fd37ecd3b4601702 lib/libmatrix_runtime_media.a
45
+ e0ed1c103c4e2392c423aacdbf314bf13848281318c6f57496136756664c4275 lib/libmatrix_runtime_transport.a
46
+ f00064a09bc2c03963518e05c659becc0a24e2ec6b696ce13ca03fa1ec576f22 lib/libmatrix_runtime_video.a
47
47
  c11c65d373a127028350c41fa58cd2d1223f2b5d70a84e13b115d90daaba25ca lib/libssl.a
48
48
  ef1c1104bbdd2528ed7b958fb7252bd6249875f92300b0c9577d6c4bd6c0d88a lib/libssl.dylib
49
49
  dc3e0e6ded26e90fd59c166933a5289d57f4cf25fbe6246b6b83c86fe898e63d lib/libwebrtc_apm.a
@@ -1,4 +1,4 @@
1
- import { StreamRequestPolicyMode, StreamSource } from './HostState';
1
+ import { StreamSource } from './HostState';
2
2
  export type JsonRpcId = string | number;
3
3
  export type JsonRpcRequest = {
4
4
  id?: JsonRpcId;
@@ -22,6 +22,7 @@ export type ServiceStartParams = {
22
22
  serviceEntry?: string;
23
23
  license: string;
24
24
  timeoutMs: number;
25
+ bootstrapSendStreams?: StreamSendStartParams[];
25
26
  };
26
27
  export type ConnectionAutoTokenConfig = {
27
28
  openapiEntry?: string;
@@ -47,6 +48,10 @@ export type StreamSendStartParams = {
47
48
  export type StreamStopParams = {
48
49
  streamId: number;
49
50
  };
51
+ export type StreamMessageSendParams = {
52
+ streamId: number;
53
+ payload: string;
54
+ };
50
55
  export type StreamReceiveStartParams = {
51
56
  streamId: number;
52
57
  media: 'audio' | 'video';
@@ -78,9 +83,6 @@ export type EventsSubscribeParams = {
78
83
  export type ArtifactExportParams = {
79
84
  outputPath: string;
80
85
  };
81
- export type StreamRequestPolicySetParams = {
82
- mode: StreamRequestPolicyMode;
83
- };
84
86
  export type DebugTokenQrcodeParams = {
85
87
  payload: string;
86
88
  outputStem?: string;
@@ -96,12 +98,12 @@ export declare function parseServiceStartParams(params: Record<string, unknown>)
96
98
  export declare function parseConnectionConnectParams(params: Record<string, unknown>): ConnectionConnectParams;
97
99
  export declare function parseStreamSendStartParams(params: Record<string, unknown>): StreamSendStartParams;
98
100
  export declare function parseStreamStopParams(params: Record<string, unknown>): StreamStopParams;
101
+ export declare function parseStreamMessageSendParams(params: Record<string, unknown>): StreamMessageSendParams;
99
102
  export declare function parseStreamReceiveStartParams(params: Record<string, unknown>): StreamReceiveStartParams;
100
103
  export declare function parseOutputAttachParams(params: Record<string, unknown>): OutputAttachParams;
101
104
  export declare function parseOutputDetachParams(params: Record<string, unknown>): OutputDetachParams;
102
105
  export declare function parseCommandSendParams(params: Record<string, unknown>): CommandSendParams;
103
106
  export declare function parseEventsSubscribeParams(params: Record<string, unknown>): EventsSubscribeParams;
104
107
  export declare function parseArtifactExportParams(params: Record<string, unknown>): ArtifactExportParams;
105
- export declare function parseStreamRequestPolicySetParams(params: Record<string, unknown>): StreamRequestPolicySetParams;
106
108
  export declare function parseDebugTokenQrcodeParams(params: Record<string, unknown>): DebugTokenQrcodeParams;
107
109
  export declare function normalizeError(error: unknown): HostProtocolError;
@@ -7,13 +7,13 @@ exports.parseServiceStartParams = parseServiceStartParams;
7
7
  exports.parseConnectionConnectParams = parseConnectionConnectParams;
8
8
  exports.parseStreamSendStartParams = parseStreamSendStartParams;
9
9
  exports.parseStreamStopParams = parseStreamStopParams;
10
+ exports.parseStreamMessageSendParams = parseStreamMessageSendParams;
10
11
  exports.parseStreamReceiveStartParams = parseStreamReceiveStartParams;
11
12
  exports.parseOutputAttachParams = parseOutputAttachParams;
12
13
  exports.parseOutputDetachParams = parseOutputDetachParams;
13
14
  exports.parseCommandSendParams = parseCommandSendParams;
14
15
  exports.parseEventsSubscribeParams = parseEventsSubscribeParams;
15
16
  exports.parseArtifactExportParams = parseArtifactExportParams;
16
- exports.parseStreamRequestPolicySetParams = parseStreamRequestPolicySetParams;
17
17
  exports.parseDebugTokenQrcodeParams = parseDebugTokenQrcodeParams;
18
18
  exports.normalizeError = normalizeError;
19
19
  class HostProtocolError extends Error {
@@ -122,10 +122,24 @@ function parseStreamSource(source) {
122
122
  };
123
123
  }
124
124
  function parseServiceStartParams(params) {
125
+ const bootstrapSendStreamsRaw = params.bootstrapSendStreams;
126
+ let bootstrapSendStreams;
127
+ if (bootstrapSendStreamsRaw !== undefined) {
128
+ if (!Array.isArray(bootstrapSendStreamsRaw)) {
129
+ throw new HostProtocolError('invalid_request', 'Invalid bootstrapSendStreams', false);
130
+ }
131
+ bootstrapSendStreams = bootstrapSendStreamsRaw.map((entry) => {
132
+ if (!isRecord(entry)) {
133
+ throw new HostProtocolError('invalid_request', 'Invalid bootstrapSendStreams item', false);
134
+ }
135
+ return parseStreamSendStartParams(entry);
136
+ });
137
+ }
125
138
  return {
126
139
  serviceEntry: getOptionalString(params, 'serviceEntry'),
127
140
  license: getString(params, 'license'),
128
141
  timeoutMs: getNumber(params, 'timeoutMs'),
142
+ bootstrapSendStreams,
129
143
  };
130
144
  }
131
145
  function parseConnectionConnectParams(params) {
@@ -178,6 +192,12 @@ function parseStreamSendStartParams(params) {
178
192
  function parseStreamStopParams(params) {
179
193
  return { streamId: getNumber(params, 'streamId') };
180
194
  }
195
+ function parseStreamMessageSendParams(params) {
196
+ return {
197
+ streamId: getNumber(params, 'streamId'),
198
+ payload: getString(params, 'payload'),
199
+ };
200
+ }
181
201
  function parseStreamReceiveStartParams(params) {
182
202
  const media = getString(params, 'media');
183
203
  if (media !== 'audio' && media !== 'video') {
@@ -230,15 +250,6 @@ function parseArtifactExportParams(params) {
230
250
  outputPath: getString(params, 'outputPath'),
231
251
  };
232
252
  }
233
- function parseStreamRequestPolicySetParams(params) {
234
- const mode = getString(params, 'mode');
235
- if (mode !== 'manual' && mode !== 'auto-if-bound') {
236
- throw new HostProtocolError('invalid_request', 'Invalid mode', false);
237
- }
238
- return {
239
- mode,
240
- };
241
- }
242
253
  function parseDebugTokenQrcodeParams(params) {
243
254
  return {
244
255
  payload: getString(params, 'payload'),
@@ -18,6 +18,7 @@ export declare class HostServer {
18
18
  removeEventSink(sink: (event: Record<string, unknown>) => void): void;
19
19
  appendHostLog(line: string): void;
20
20
  private handleRuntimeEvent;
21
+ private noteIncomingConnection;
21
22
  private maybeAutoStartStreamFromRemoteDemand;
22
23
  private dispatch;
23
24
  private handleInitialize;
@@ -34,10 +35,9 @@ export declare class HostServer {
34
35
  private handleStreamList;
35
36
  private handleStreamSendStart;
36
37
  private handleStreamSendStop;
38
+ private handleStreamMessageSend;
37
39
  private handleStreamReceiveStart;
38
40
  private handleStreamReceiveStop;
39
- private handleStreamRequestPolicyGet;
40
- private handleStreamRequestPolicySet;
41
41
  private handleOutputAttach;
42
42
  private handleOutputDetach;
43
43
  private handleCommandSend;
@@ -175,18 +175,30 @@ class HostServer {
175
175
  if (family !== 'runtime') {
176
176
  return;
177
177
  }
178
- if (kind === 'transport.remote.request') {
178
+ if (kind === 'transport.remote.request_audio' ||
179
+ kind === 'transport.remote.request_video' ||
180
+ kind === 'transport.remote.request_iframe') {
179
181
  const streamId = Number(payload.streamId);
180
- const mediaRaw = String(payload.media ?? '');
181
- if ((mediaRaw === 'audio' || mediaRaw === 'video') && Number.isFinite(streamId)) {
182
- this.maybeAutoStartStreamFromRemoteDemand(streamId, mediaRaw, payload);
182
+ if (!Number.isFinite(streamId)) {
183
+ return;
183
184
  }
185
+ const media = kind === 'transport.remote.request_audio' ? 'audio' : 'video';
186
+ this.noteIncomingConnection(payload);
187
+ this.maybeAutoStartStreamFromRemoteDemand(streamId, media, payload);
184
188
  }
185
189
  }
186
- maybeAutoStartStreamFromRemoteDemand(streamId, media, payload) {
187
- if (this.state.streamRequestPolicy.mode !== 'auto-if-bound') {
190
+ noteIncomingConnection(payload) {
191
+ if (this.state.connection.state === 'connected') {
188
192
  return;
189
193
  }
194
+ this.state.connection = {
195
+ state: 'connected',
196
+ direction: 'incoming',
197
+ peerId: typeof payload.peerId === 'string' && payload.peerId.length > 0 ? payload.peerId : undefined,
198
+ connectedAt: new Date().toISOString(),
199
+ };
200
+ }
201
+ maybeAutoStartStreamFromRemoteDemand(streamId, media, payload) {
190
202
  const key = streamBindingKey(streamId, media);
191
203
  const bound = this.state.streamSourceBindings.get(key);
192
204
  if (!bound) {
@@ -248,14 +260,12 @@ class HostServer {
248
260
  return this.handleStreamSendStart((0, HostProtocol_1.parseStreamSendStartParams)(params));
249
261
  case 'stream/sendStop':
250
262
  return this.handleStreamSendStop((0, HostProtocol_1.parseStreamStopParams)(params));
263
+ case 'stream/message/send':
264
+ return this.handleStreamMessageSend((0, HostProtocol_1.parseStreamMessageSendParams)(params));
251
265
  case 'stream/receiveStart':
252
266
  return this.handleStreamReceiveStart((0, HostProtocol_1.parseStreamReceiveStartParams)(params));
253
267
  case 'stream/receiveStop':
254
268
  return this.handleStreamReceiveStop((0, HostProtocol_1.parseStreamStopParams)(params));
255
- case 'stream/requestPolicy/get':
256
- return this.handleStreamRequestPolicyGet();
257
- case 'stream/requestPolicy/set':
258
- return this.handleStreamRequestPolicySet((0, HostProtocol_1.parseStreamRequestPolicySetParams)(params));
259
269
  case 'output/attach':
260
270
  return this.handleOutputAttach((0, HostProtocol_1.parseOutputAttachParams)(params));
261
271
  case 'output/detach':
@@ -285,11 +295,7 @@ class HostServer {
285
295
  protocolVersion: this.state.protocolVersion,
286
296
  runtimeTarget: this.state.runtimeTarget,
287
297
  hostEndpoint: this.state.hostEndpoint,
288
- capabilities: {
289
- streamRequestPolicy: {
290
- mode: this.state.streamRequestPolicy.mode,
291
- },
292
- },
298
+ capabilities: {},
293
299
  };
294
300
  }
295
301
  async handleHostStatus() {
@@ -301,7 +307,6 @@ class HostServer {
301
307
  startedAt: this.state.startedAt,
302
308
  service: this.state.service,
303
309
  connection: this.state.connection,
304
- streamRequestPolicy: this.state.streamRequestPolicy,
305
310
  artifactPaths: this.artifactManager.getPaths(),
306
311
  };
307
312
  }
@@ -327,6 +332,44 @@ class HostServer {
327
332
  serviceEntry: resolvedServiceEntry,
328
333
  startedAt: new Date().toISOString(),
329
334
  };
335
+ if (params.bootstrapSendStreams && params.bootstrapSendStreams.length > 0) {
336
+ const bootstrapStreams = params.bootstrapSendStreams.map((streamParams) => ({
337
+ streamId: streamParams.streamId,
338
+ media: streamParams.media,
339
+ source: streamParams.source,
340
+ }));
341
+ const sendResults = this.runtimeAdapter.startSendStreams
342
+ ? await this.runtimeAdapter.startSendStreams(bootstrapStreams)
343
+ : await Promise.all(bootstrapStreams.map(async (streamParams) => await this.runtimeAdapter.startSendStream(streamParams.streamId, streamParams.media, streamParams.source)));
344
+ const updatedAt = new Date().toISOString();
345
+ bootstrapStreams.forEach((streamParams, index) => {
346
+ const stream = {
347
+ streamId: streamParams.streamId,
348
+ media: streamParams.media,
349
+ direction: 'send',
350
+ state: this.state.connection.state === 'connected' ? 'active' : 'pending_on_connection',
351
+ source: streamParams.source,
352
+ updatedAt,
353
+ };
354
+ this.state.streams.set(streamParams.streamId, stream);
355
+ this.state.streamSourceBindings.set(streamBindingKey(streamParams.streamId, streamParams.media), {
356
+ streamId: streamParams.streamId,
357
+ media: streamParams.media,
358
+ source: streamParams.source,
359
+ updatedAt,
360
+ });
361
+ this.writeEvent('stream', 'send.bootstrap.bound', {
362
+ streamId: streamParams.streamId,
363
+ media: streamParams.media,
364
+ sourceMode: streamParams.source.mode,
365
+ assetsDir: streamParams.source.local_assets.assets_dir,
366
+ autoStarted: sendResults[index]?.autoStarted ?? false,
367
+ workerPid: sendResults[index]?.workerPid,
368
+ state: stream.state,
369
+ at: updatedAt,
370
+ });
371
+ });
372
+ }
330
373
  return this.state.service;
331
374
  }
332
375
  async handleServiceStop() {
@@ -510,6 +553,40 @@ class HostServer {
510
553
  stream.updatedAt = new Date().toISOString();
511
554
  return stream;
512
555
  }
556
+ async handleStreamMessageSend(params) {
557
+ const acceptedAt = new Date().toISOString();
558
+ this.writeEvent('stream', 'message.send.requested', {
559
+ streamId: params.streamId,
560
+ payloadPreview: params.payload.slice(0, 120),
561
+ payloadLength: params.payload.length,
562
+ at: acceptedAt,
563
+ });
564
+ try {
565
+ await this.runtimeAdapter.sendStreamMessage(params.streamId, params.payload);
566
+ }
567
+ catch (error) {
568
+ const message = error instanceof Error ? error.message : String(error);
569
+ this.writeEvent('stream', 'message.send.failed', {
570
+ streamId: params.streamId,
571
+ payloadPreview: params.payload.slice(0, 120),
572
+ payloadLength: params.payload.length,
573
+ message,
574
+ at: new Date().toISOString(),
575
+ });
576
+ throw error;
577
+ }
578
+ this.writeEvent('stream', 'message.send.completed', {
579
+ streamId: params.streamId,
580
+ payloadPreview: params.payload.slice(0, 120),
581
+ payloadLength: params.payload.length,
582
+ at: new Date().toISOString(),
583
+ });
584
+ return {
585
+ streamId: params.streamId,
586
+ payloadLength: params.payload.length,
587
+ acceptedAt,
588
+ };
589
+ }
513
590
  async handleStreamReceiveStart(params) {
514
591
  await this.runtimeAdapter.startReceiveStream(params.streamId, params.media);
515
592
  const stream = {
@@ -532,24 +609,6 @@ class HostServer {
532
609
  stream.updatedAt = new Date().toISOString();
533
610
  return stream;
534
611
  }
535
- async handleStreamRequestPolicyGet() {
536
- return {
537
- mode: this.state.streamRequestPolicy.mode,
538
- updatedAt: new Date().toISOString(),
539
- };
540
- }
541
- async handleStreamRequestPolicySet(params) {
542
- this.state.streamRequestPolicy.mode = params.mode;
543
- const updatedAt = new Date().toISOString();
544
- this.writeEvent('stream', 'request_policy.updated', {
545
- mode: params.mode,
546
- at: updatedAt,
547
- });
548
- return {
549
- mode: this.state.streamRequestPolicy.mode,
550
- updatedAt,
551
- };
552
- }
553
612
  async handleOutputAttach(params) {
554
613
  const attachment = await this.runtimeAdapter.attachOutput(params.streamId, params.consumer, params.mediaView, params.format, params.delivery, params.targetPath, params.maxFiles);
555
614
  return {
@@ -600,7 +659,6 @@ class HostServer {
600
659
  service: this.state.service,
601
660
  connection: this.state.connection,
602
661
  streams: Array.from(this.state.streams.values()),
603
- streamRequestPolicy: this.state.streamRequestPolicy,
604
662
  artifacts: this.artifactManager.getPaths(),
605
663
  lastError: this.state.lastError,
606
664
  };
@@ -29,10 +29,6 @@ export interface StreamLocalAssetsSource {
29
29
  };
30
30
  }
31
31
  export type StreamSource = StreamLocalAssetsSource;
32
- export type StreamRequestPolicyMode = 'manual' | 'auto-if-bound';
33
- export interface StreamRequestPolicy {
34
- mode: StreamRequestPolicyMode;
35
- }
36
32
  export interface StreamSourceBinding {
37
33
  streamId: number;
38
34
  media: 'audio' | 'video';
@@ -45,7 +41,6 @@ export declare class HostState {
45
41
  streams: Map<number, StreamSnapshot>;
46
42
  subscriptions: Set<string>;
47
43
  internalConnections: Set<string>;
48
- streamRequestPolicy: StreamRequestPolicy;
49
44
  streamSourceBindings: Map<string, StreamSourceBinding>;
50
45
  protocolVersion: string;
51
46
  serverVersion: string;
@@ -7,7 +7,6 @@ class HostState {
7
7
  streams = new Map();
8
8
  subscriptions = new Set();
9
9
  internalConnections = new Set();
10
- streamRequestPolicy = { mode: 'manual' };
11
10
  streamSourceBindings = new Map();
12
11
  protocolVersion = '1.0.0';
13
12
  serverVersion = '1.0.0';