io.appium.settings 8.0.10 → 8.1.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 (62) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +97 -0
  3. package/apks/settings_apk-debug.apk +0 -0
  4. package/build/lib/client.d.ts +4 -0
  5. package/build/lib/client.d.ts.map +1 -1
  6. package/build/lib/client.js +4 -0
  7. package/build/lib/client.js.map +1 -1
  8. package/build/lib/commands/clipboard.d.ts.map +1 -1
  9. package/build/lib/commands/clipboard.js +1 -1
  10. package/build/lib/commands/clipboard.js.map +1 -1
  11. package/build/lib/commands/jpeg-stream.d.ts +51 -0
  12. package/build/lib/commands/jpeg-stream.d.ts.map +1 -0
  13. package/build/lib/commands/jpeg-stream.js +152 -0
  14. package/build/lib/commands/jpeg-stream.js.map +1 -0
  15. package/build/lib/commands/media-projection.d.ts.map +1 -1
  16. package/build/lib/commands/media-projection.js.map +1 -1
  17. package/build/lib/commands/network.js +1 -1
  18. package/build/lib/commands/network.js.map +1 -1
  19. package/build/lib/commands/types.d.ts +65 -0
  20. package/build/lib/commands/types.d.ts.map +1 -1
  21. package/build/lib/commands/video-stream.d.ts +50 -0
  22. package/build/lib/commands/video-stream.d.ts.map +1 -0
  23. package/build/lib/commands/video-stream.js +160 -0
  24. package/build/lib/commands/video-stream.js.map +1 -0
  25. package/build/lib/constants.d.ts +7 -0
  26. package/build/lib/constants.d.ts.map +1 -1
  27. package/build/lib/constants.js +7 -0
  28. package/build/lib/constants.js.map +1 -1
  29. package/build/lib/index.js +1 -1
  30. package/build/lib/index.js.map +1 -1
  31. package/build/lib/{utils.d.ts → utils/apk-path.d.ts} +1 -1
  32. package/build/lib/utils/apk-path.d.ts.map +1 -0
  33. package/build/lib/{utils.js → utils/apk-path.js} +1 -1
  34. package/build/lib/utils/apk-path.js.map +1 -0
  35. package/build/lib/utils/index.d.ts +5 -0
  36. package/build/lib/utils/index.d.ts.map +1 -0
  37. package/build/lib/utils/index.js +4 -0
  38. package/build/lib/utils/index.js.map +1 -0
  39. package/build/lib/utils/streaming-protocol.d.ts +47 -0
  40. package/build/lib/utils/streaming-protocol.d.ts.map +1 -0
  41. package/build/lib/utils/streaming-protocol.js +67 -0
  42. package/build/lib/utils/streaming-protocol.js.map +1 -0
  43. package/build/lib/utils/streaming-transport.d.ts +142 -0
  44. package/build/lib/utils/streaming-transport.d.ts.map +1 -0
  45. package/build/lib/utils/streaming-transport.js +416 -0
  46. package/build/lib/utils/streaming-transport.js.map +1 -0
  47. package/lib/client.ts +5 -0
  48. package/lib/commands/clipboard.ts +1 -0
  49. package/lib/commands/jpeg-stream.ts +171 -0
  50. package/lib/commands/media-projection.ts +1 -5
  51. package/lib/commands/network.ts +1 -1
  52. package/lib/commands/types.ts +70 -0
  53. package/lib/commands/video-stream.ts +179 -0
  54. package/lib/constants.ts +10 -0
  55. package/lib/index.ts +1 -1
  56. package/lib/utils/index.ts +4 -0
  57. package/lib/utils/streaming-protocol.ts +93 -0
  58. package/lib/utils/streaming-transport.ts +450 -0
  59. package/package.json +1 -1
  60. package/build/lib/utils.d.ts.map +0 -1
  61. package/build/lib/utils.js.map +0 -1
  62. /package/lib/{utils.ts → utils/apk-path.ts} +0 -0
@@ -0,0 +1,160 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { waitForCondition } from 'asyncbox';
3
+ import { SETTINGS_HELPER_ID, STREAMING_ACTIVITY_NAME, VIDEO_STREAM_ACTION_START, VIDEO_STREAM_ACTION_STOP, VIDEO_STREAM_SERVICE_NAME, } from '../constants.js';
4
+ import { StreamTrack, StreamTransport, validateLocalPortOpts } from '../utils/index.js';
5
+ const STREAM_STARTUP_TIMEOUT_MS = 3 * 1000;
6
+ const STREAM_STOP_TIMEOUT_MS = 3 * 1000;
7
+ /**
8
+ * Creates a new instance of the live H.264/HEVC video streaming session.
9
+ * The stream only works since Android API 29+
10
+ *
11
+ * @returns The streaming session instance
12
+ */
13
+ export function makeVideoStreamSession() {
14
+ return new VideoStreamSession(this.adb);
15
+ }
16
+ function validateVideoStreamOpts(opts) {
17
+ const { codec, fps, bitrate } = opts;
18
+ if (codec !== undefined && codec !== 'h264' && codec !== 'hevc') {
19
+ throw new TypeError(`codec must be either 'h264' or 'hevc', got ${codec}`);
20
+ }
21
+ if (fps !== undefined && (!Number.isInteger(fps) || fps <= 0)) {
22
+ throw new TypeError(`fps must be a positive integer, got ${fps}`);
23
+ }
24
+ if (bitrate !== undefined && (!Number.isInteger(bitrate) || bitrate <= 0)) {
25
+ throw new TypeError(`bitrate must be a positive integer, got ${bitrate}`);
26
+ }
27
+ validateLocalPortOpts(opts);
28
+ }
29
+ /**
30
+ * Live H.264/HEVC video streaming session for the device screen, with an
31
+ * optional interleaved AAC audio track.
32
+ */
33
+ export class VideoStreamSession {
34
+ adb;
35
+ transport = null;
36
+ /**
37
+ * Creates a new VideoStreamSession instance.
38
+ *
39
+ * @param adb - ADB instance for device communication
40
+ */
41
+ constructor(adb) {
42
+ this.adb = adb;
43
+ }
44
+ /**
45
+ * Checks if the video stream is currently running.
46
+ */
47
+ async isRunning() {
48
+ const stdout = await this.adb.shell(['dumpsys', 'activity', 'services', VIDEO_STREAM_SERVICE_NAME]);
49
+ return stdout.includes(VIDEO_STREAM_SERVICE_NAME);
50
+ }
51
+ /**
52
+ * Starts the live video stream.
53
+ * If a stream is already running, this method returns false without starting a new one.
54
+ *
55
+ * @param opts Streaming options including codec, fps, bitrate, resolution, audio, and the local port to use
56
+ * @returns True if the stream was started successfully, false if already running
57
+ * @throws {Error} If the stream fails to start within the timeout period
58
+ */
59
+ async start(opts = {}) {
60
+ validateVideoStreamOpts(opts);
61
+ if (await this.isRunning()) {
62
+ return false;
63
+ }
64
+ const { codec, fps, bitrate, resolution, audio, localPort, localPortRange } = opts;
65
+ // Socket names are validated on-device against ^[a-zA-Z0-9._-]{1,200}$, so this
66
+ // must not contain a "/" - unlike VIDEO_STREAM_SERVICE_NAME.
67
+ const socketName = `${SETTINGS_HELPER_ID}.videostream.${randomUUID()}`;
68
+ const args = [
69
+ 'am',
70
+ 'start',
71
+ '-n',
72
+ STREAMING_ACTIVITY_NAME,
73
+ '-a',
74
+ VIDEO_STREAM_ACTION_START,
75
+ '--es',
76
+ 'socket_name',
77
+ socketName,
78
+ ];
79
+ if (codec) {
80
+ args.push('--es', 'codec', codec);
81
+ }
82
+ if (fps) {
83
+ args.push('--es', 'fps', `${fps}`);
84
+ }
85
+ if (bitrate) {
86
+ args.push('--es', 'bitrate', `${bitrate}`);
87
+ }
88
+ if (resolution) {
89
+ args.push('--es', 'resolution', resolution);
90
+ }
91
+ if (audio !== undefined) {
92
+ args.push('--es', 'audio', audio ? 'true' : 'false');
93
+ }
94
+ await this.adb.shell(args);
95
+ try {
96
+ await waitForCondition(async () => await this.isRunning(), {
97
+ waitMs: STREAM_STARTUP_TIMEOUT_MS,
98
+ intervalMs: 300,
99
+ });
100
+ }
101
+ catch {
102
+ throw new Error(`The video stream is not running after ${STREAM_STARTUP_TIMEOUT_MS}ms. ` +
103
+ `Please check the logcat output for more details.`);
104
+ }
105
+ this.transport = await StreamTransport.connect(this.adb, socketName, { localPort, localPortRange });
106
+ return true;
107
+ }
108
+ /**
109
+ * Yields access units (video NAL units and, if enabled, AAC audio units) as
110
+ * they arrive from the device. `start()` must be called before iterating.
111
+ */
112
+ async *accessUnits() {
113
+ if (!this.transport) {
114
+ throw new Error('The video stream has not been started. Call start() first.');
115
+ }
116
+ for await (const frame of this.transport.frames()) {
117
+ yield {
118
+ track: frame.track === StreamTrack.Audio ? 'audio' : 'video',
119
+ data: frame.data,
120
+ sequence: Number(frame.sequence),
121
+ timestampMicros: Number(frame.timestampMicros),
122
+ isKeyFrame: frame.isKeyFrame,
123
+ isConfig: frame.isConfig,
124
+ };
125
+ }
126
+ }
127
+ /**
128
+ * Stops the currently running video stream.
129
+ *
130
+ * @returns True if the stream was stopped successfully, false if it was not running
131
+ * @throws {Error} If the stream fails to stop within the timeout period
132
+ */
133
+ async stop() {
134
+ try {
135
+ if (!(await this.isRunning())) {
136
+ // The on-device service may have already stopped itself (e.g. the client
137
+ // disconnected), leaving a local transport/adb-forward that still needs closing.
138
+ return false;
139
+ }
140
+ await this.adb.shell(['am', 'start', '-n', STREAMING_ACTIVITY_NAME, '-a', VIDEO_STREAM_ACTION_STOP]);
141
+ try {
142
+ await waitForCondition(async () => !(await this.isRunning()), {
143
+ waitMs: STREAM_STOP_TIMEOUT_MS,
144
+ intervalMs: 300,
145
+ });
146
+ }
147
+ catch {
148
+ throw new Error(`The attempt to stop the current video stream timed out after ${STREAM_STOP_TIMEOUT_MS}ms`);
149
+ }
150
+ return true;
151
+ }
152
+ finally {
153
+ if (this.transport) {
154
+ await this.transport.close();
155
+ this.transport = null;
156
+ }
157
+ }
158
+ }
159
+ }
160
+ //# sourceMappingURL=video-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-stream.js","sourceRoot":"","sources":["../../../lib/commands/video-stream.ts"],"names":[],"mappings":"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"}
@@ -30,4 +30,11 @@ export declare const RECORDING_SERVICE_NAME = "io.appium.settings/.recorder.Reco
30
30
  export declare const RECORDING_ACTIVITY_NAME = "io.appium.settings/io.appium.settings.Settings";
31
31
  export declare const RECORDING_ACTION_START = "io.appium.settings.recording.ACTION_START";
32
32
  export declare const RECORDING_ACTION_STOP = "io.appium.settings.recording.ACTION_STOP";
33
+ export declare const STREAMING_ACTIVITY_NAME = "io.appium.settings/io.appium.settings.Settings";
34
+ export declare const JPEG_STREAM_SERVICE_NAME = "io.appium.settings/.streaming.JpegStreamService";
35
+ export declare const JPEG_STREAM_ACTION_START = "io.appium.settings.streaming.jpeg.ACTION_START";
36
+ export declare const JPEG_STREAM_ACTION_STOP = "io.appium.settings.streaming.jpeg.ACTION_STOP";
37
+ export declare const VIDEO_STREAM_SERVICE_NAME = "io.appium.settings/.streaming.VideoStreamService";
38
+ export declare const VIDEO_STREAM_ACTION_START = "io.appium.settings.streaming.video.ACTION_START";
39
+ export declare const VIDEO_STREAM_ACTION_STOP = "io.appium.settings.streaming.video.ACTION_STOP";
33
40
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,6BAA6B,cAAc,CAAC;AAIzD,eAAO,MAAM,kBAAkB,oDAAuC,CAAC;AACvE,eAAO,MAAM,0BAA0B,qCAAwC,CAAC;AAEhF,eAAO,MAAM,UAAU,kCAAqC,CAAC;AAC7D,eAAO,MAAM,WAAW,mCAAsC,CAAC;AAC/D,eAAO,MAAM,SAAS,iCAAoC,CAAC;AAE3D,eAAO,MAAM,gCAAgC,gEAAmD,CAAC;AACjG,eAAO,MAAM,8BAA8B,4BAA+B,CAAC;AAC3E,eAAO,MAAM,0BAA0B,qEAAwD,CAAC;AAChG,eAAO,MAAM,wBAAwB,iCAAoC,CAAC;AAC1E,eAAO,MAAM,yBAAyB,iEAAoD,CAAC;AAC3F,eAAO,MAAM,uBAAuB,wCAA2C,CAAC;AAEhF,eAAO,MAAM,0BAA0B,2DAA8C,CAAC;AACtF,eAAO,MAAM,wBAAwB,iCAAoC,CAAC;AAE1E,eAAO,MAAM,uBAAuB,wDAA2C,CAAC;AAChF,eAAO,MAAM,qBAAqB,8BAAiC,CAAC;AAEpE,eAAO,MAAM,6BAA6B,gDAAmC,CAAC;AAC9E,eAAO,MAAM,2BAA2B,oCAAuC,CAAC;AAEhF,eAAO,MAAM,gBAAgB,wCAA2C,CAAC;AACzE,eAAO,MAAM,iBAAiB,uDAA0C,CAAC;AACzE,eAAO,MAAM,yBAAyB,gCAAmC,CAAC;AAE1E,eAAO,MAAM,iBAAiB,4CAA+B,CAAC;AAC9D,eAAO,MAAM,yBAAyB,gCAAmC,CAAC;AAE1E,eAAO,MAAM,mBAAmB,uDAA0C,CAAC;AAC3E,eAAO,MAAM,iBAAiB,kCAAqC,CAAC;AAEpE,eAAO,MAAM,sCAAsC,kCAAqC,CAAC;AACzF,eAAO,MAAM,8BAA8B,qCAAwC,CAAC;AAEpF,eAAO,MAAM,sBAAsB,iDAAoD,CAAC;AACxF,eAAO,MAAM,uBAAuB,mDAAsD,CAAC;AAC3F,eAAO,MAAM,sBAAsB,8CAAiD,CAAC;AACrF,eAAO,MAAM,qBAAqB,6CAAgD,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,6BAA6B,cAAc,CAAC;AAIzD,eAAO,MAAM,kBAAkB,oDAAuC,CAAC;AACvE,eAAO,MAAM,0BAA0B,qCAAwC,CAAC;AAEhF,eAAO,MAAM,UAAU,kCAAqC,CAAC;AAC7D,eAAO,MAAM,WAAW,mCAAsC,CAAC;AAC/D,eAAO,MAAM,SAAS,iCAAoC,CAAC;AAE3D,eAAO,MAAM,gCAAgC,gEAAmD,CAAC;AACjG,eAAO,MAAM,8BAA8B,4BAA+B,CAAC;AAC3E,eAAO,MAAM,0BAA0B,qEAAwD,CAAC;AAChG,eAAO,MAAM,wBAAwB,iCAAoC,CAAC;AAC1E,eAAO,MAAM,yBAAyB,iEAAoD,CAAC;AAC3F,eAAO,MAAM,uBAAuB,wCAA2C,CAAC;AAEhF,eAAO,MAAM,0BAA0B,2DAA8C,CAAC;AACtF,eAAO,MAAM,wBAAwB,iCAAoC,CAAC;AAE1E,eAAO,MAAM,uBAAuB,wDAA2C,CAAC;AAChF,eAAO,MAAM,qBAAqB,8BAAiC,CAAC;AAEpE,eAAO,MAAM,6BAA6B,gDAAmC,CAAC;AAC9E,eAAO,MAAM,2BAA2B,oCAAuC,CAAC;AAEhF,eAAO,MAAM,gBAAgB,wCAA2C,CAAC;AACzE,eAAO,MAAM,iBAAiB,uDAA0C,CAAC;AACzE,eAAO,MAAM,yBAAyB,gCAAmC,CAAC;AAE1E,eAAO,MAAM,iBAAiB,4CAA+B,CAAC;AAC9D,eAAO,MAAM,yBAAyB,gCAAmC,CAAC;AAE1E,eAAO,MAAM,mBAAmB,uDAA0C,CAAC;AAC3E,eAAO,MAAM,iBAAiB,kCAAqC,CAAC;AAEpE,eAAO,MAAM,sCAAsC,kCAAqC,CAAC;AACzF,eAAO,MAAM,8BAA8B,qCAAwC,CAAC;AAEpF,eAAO,MAAM,sBAAsB,iDAAoD,CAAC;AACxF,eAAO,MAAM,uBAAuB,mDAAsD,CAAC;AAC3F,eAAO,MAAM,sBAAsB,8CAAiD,CAAC;AACrF,eAAO,MAAM,qBAAqB,6CAAgD,CAAC;AAEnF,eAAO,MAAM,uBAAuB,mDAA0B,CAAC;AAE/D,eAAO,MAAM,wBAAwB,oDAAuD,CAAC;AAC7F,eAAO,MAAM,wBAAwB,mDAAsD,CAAC;AAC5F,eAAO,MAAM,uBAAuB,kDAAqD,CAAC;AAE1F,eAAO,MAAM,yBAAyB,qDAAwD,CAAC;AAC/F,eAAO,MAAM,yBAAyB,oDAAuD,CAAC;AAC9F,eAAO,MAAM,wBAAwB,mDAAsD,CAAC"}
@@ -31,4 +31,11 @@ export const RECORDING_SERVICE_NAME = `${SETTINGS_HELPER_ID}/.recorder.RecorderS
31
31
  export const RECORDING_ACTIVITY_NAME = `${SETTINGS_HELPER_ID}/io.appium.settings.Settings`;
32
32
  export const RECORDING_ACTION_START = `${SETTINGS_HELPER_ID}.recording.ACTION_START`;
33
33
  export const RECORDING_ACTION_STOP = `${SETTINGS_HELPER_ID}.recording.ACTION_STOP`;
34
+ export const STREAMING_ACTIVITY_NAME = RECORDING_ACTIVITY_NAME;
35
+ export const JPEG_STREAM_SERVICE_NAME = `${SETTINGS_HELPER_ID}/.streaming.JpegStreamService`;
36
+ export const JPEG_STREAM_ACTION_START = `${SETTINGS_HELPER_ID}.streaming.jpeg.ACTION_START`;
37
+ export const JPEG_STREAM_ACTION_STOP = `${SETTINGS_HELPER_ID}.streaming.jpeg.ACTION_STOP`;
38
+ export const VIDEO_STREAM_SERVICE_NAME = `${SETTINGS_HELPER_ID}/.streaming.VideoStreamService`;
39
+ export const VIDEO_STREAM_ACTION_START = `${SETTINGS_HELPER_ID}.streaming.video.ACTION_START`;
40
+ export const VIDEO_STREAM_ACTION_STOP = `${SETTINGS_HELPER_ID}.streaming.video.ACTION_STOP`;
34
41
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AACvD,MAAM,CAAC,MAAM,6BAA6B,GAAG,WAAW,CAAC;AAEzD,MAAM,aAAa,GAAG,GAAG,kBAAkB,aAAa,CAAC;AAEzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,aAAa,oBAAoB,CAAC;AACvE,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,kBAAkB,gBAAgB,CAAC;AAEhF,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,kBAAkB,aAAa,CAAC;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,kBAAkB,cAAc,CAAC;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,kBAAkB,YAAY,CAAC;AAE3D,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,aAAa,gCAAgC,CAAC;AACjG,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,kBAAkB,OAAO,CAAC;AAC3E,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,aAAa,qCAAqC,CAAC;AAChG,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,kBAAkB,YAAY,CAAC;AAC1E,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,aAAa,iCAAiC,CAAC;AAC3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,kBAAkB,mBAAmB,CAAC;AAEhF,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,aAAa,2BAA2B,CAAC;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,kBAAkB,YAAY,CAAC;AAE1E,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,aAAa,wBAAwB,CAAC;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,kBAAkB,SAAS,CAAC;AAEpE,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,aAAa,gBAAgB,CAAC;AAC9E,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,kBAAkB,eAAe,CAAC;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,kBAAkB,mBAAmB,CAAC;AACzE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,aAAa,uBAAuB,CAAC;AACzE,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,kBAAkB,WAAW,CAAC;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,aAAa,YAAY,CAAC;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,kBAAkB,WAAW,CAAC;AAE1E,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,aAAa,uBAAuB,CAAC;AAC3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,kBAAkB,aAAa,CAAC;AAEpE,MAAM,CAAC,MAAM,sCAAsC,GAAG,GAAG,kBAAkB,aAAa,CAAC;AACzF,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,kBAAkB,gBAAgB,CAAC;AAEpF,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,kBAAkB,4BAA4B,CAAC;AACxF,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,kBAAkB,8BAA8B,CAAC;AAC3F,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,kBAAkB,yBAAyB,CAAC;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,kBAAkB,wBAAwB,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { getSettingsApkPath } from './utils.js';
1
+ import { getSettingsApkPath } from './utils/index.js';
2
2
  export const path = getSettingsApkPath();
3
3
  export * from './constants.js';
4
4
  export { SettingsApp } from './client.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,YAAY,CAAC;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC"}
@@ -4,4 +4,4 @@
4
4
  * @returns Full path to the APK file
5
5
  */
6
6
  export declare function getSettingsApkPath(): string;
7
- //# sourceMappingURL=utils.d.ts.map
7
+ //# sourceMappingURL=apk-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apk-path.d.ts","sourceRoot":"","sources":["../../../lib/utils/apk-path.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
@@ -32,4 +32,4 @@ function getModuleRootSync() {
32
32
  }
33
33
  throw new Error(`Cannot find the root of the ${MODULE_NAME} Node.js module`);
34
34
  }
35
- //# sourceMappingURL=utils.js.map
35
+ //# sourceMappingURL=apk-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apk-path.js","sourceRoot":"","sources":["../../../lib/utils/apk-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,wBAAwB,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB;IACxB,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,OAAO,CAAC,UAAU,EAAE,CAAC;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAC3D,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC1G,OAAO,UAAU,CAAC;YACpB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,UAAU,GAAG,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IACpE,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,+BAA+B,WAAW,iBAAiB,CAAC,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { getSettingsApkPath } from './apk-path.js';
2
+ export { createParserState, parseFrames, StreamTrack } from './streaming-protocol.js';
3
+ export type { FrameParserState, StreamFrame } from './streaming-protocol.js';
4
+ export { BoundedFrameQueue, resolveLocalPort, StreamTransport, validateLocalPortOpts } from './streaming-transport.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,yBAAyB,CAAC;AACpF,YAAY,EAAC,gBAAgB,EAAE,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAC,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,qBAAqB,EAAC,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getSettingsApkPath } from './apk-path.js';
2
+ export { createParserState, parseFrames, StreamTrack } from './streaming-protocol.js';
3
+ export { BoundedFrameQueue, resolveLocalPort, StreamTransport, validateLocalPortOpts } from './streaming-transport.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAEpF,OAAO,EAAC,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,qBAAqB,EAAC,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Track discriminator for a streamed frame, matching the on-device
3
+ * `io.appium.settings.streaming.Frame.Track` enum ordinals.
4
+ */
5
+ export declare enum StreamTrack {
6
+ Jpeg = 0,
7
+ Video = 1,
8
+ Audio = 2
9
+ }
10
+ /**
11
+ * A single parsed frame/access-unit read off the streaming socket.
12
+ */
13
+ export interface StreamFrame {
14
+ track: StreamTrack;
15
+ sequence: bigint;
16
+ timestampMicros: bigint;
17
+ data: Buffer;
18
+ isConfig: boolean;
19
+ isKeyFrame: boolean;
20
+ isEndOfStream: boolean;
21
+ }
22
+ /**
23
+ * Incremental parser state, carried across chunk boundaries.
24
+ */
25
+ export interface FrameParserState {
26
+ buf: Buffer;
27
+ }
28
+ /**
29
+ * Creates a fresh, empty parser state for use with {@link parseFrames}.
30
+ *
31
+ * @returns A new, empty FrameParserState
32
+ */
33
+ export declare function createParserState(): FrameParserState;
34
+ /**
35
+ * Parses as many complete frames as are available in `state.buf` + `chunk`,
36
+ * carrying over any trailing partial frame in `state` for the next call.
37
+ *
38
+ * Wire format (big-endian, matches `io.appium.settings.streaming.StreamProtocol`):
39
+ * offset 0 (4 bytes): magic "APST"; offset 4 (1 byte): version;
40
+ * offset 5 (1 byte): track; offset 6 (1 byte): flags; offset 7: reserved;
41
+ * offset 8 (8 bytes): sequence; offset 16 (8 bytes): timestampMicros;
42
+ * offset 24 (4 bytes): payloadLength; followed by `payloadLength` payload bytes.
43
+ *
44
+ * @throws {Error} If the stream desynchronizes (unexpected magic bytes)
45
+ */
46
+ export declare function parseFrames(state: FrameParserState, chunk: Buffer): Generator<StreamFrame>;
47
+ //# sourceMappingURL=streaming-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-protocol.d.ts","sourceRoot":"","sources":["../../../lib/utils/streaming-protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oBAAY,WAAW;IACrB,IAAI,IAAI;IACR,KAAK,IAAI;IACT,KAAK,IAAI;CACV;AAMD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;CACxB;AAKD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,gBAAgB,CAEpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAiB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,CAkC3F"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Track discriminator for a streamed frame, matching the on-device
3
+ * `io.appium.settings.streaming.Frame.Track` enum ordinals.
4
+ */
5
+ export var StreamTrack;
6
+ (function (StreamTrack) {
7
+ StreamTrack[StreamTrack["Jpeg"] = 0] = "Jpeg";
8
+ StreamTrack[StreamTrack["Video"] = 1] = "Video";
9
+ StreamTrack[StreamTrack["Audio"] = 2] = "Audio";
10
+ })(StreamTrack || (StreamTrack = {}));
11
+ const FLAG_CONFIG = 0x01;
12
+ const FLAG_KEYFRAME = 0x02;
13
+ const FLAG_EOS = 0x04;
14
+ const HEADER_SIZE = 28;
15
+ const MAGIC = Buffer.from('APST', 'ascii');
16
+ /**
17
+ * Creates a fresh, empty parser state for use with {@link parseFrames}.
18
+ *
19
+ * @returns A new, empty FrameParserState
20
+ */
21
+ export function createParserState() {
22
+ return { buf: Buffer.alloc(0) };
23
+ }
24
+ /**
25
+ * Parses as many complete frames as are available in `state.buf` + `chunk`,
26
+ * carrying over any trailing partial frame in `state` for the next call.
27
+ *
28
+ * Wire format (big-endian, matches `io.appium.settings.streaming.StreamProtocol`):
29
+ * offset 0 (4 bytes): magic "APST"; offset 4 (1 byte): version;
30
+ * offset 5 (1 byte): track; offset 6 (1 byte): flags; offset 7: reserved;
31
+ * offset 8 (8 bytes): sequence; offset 16 (8 bytes): timestampMicros;
32
+ * offset 24 (4 bytes): payloadLength; followed by `payloadLength` payload bytes.
33
+ *
34
+ * @throws {Error} If the stream desynchronizes (unexpected magic bytes)
35
+ */
36
+ export function* parseFrames(state, chunk) {
37
+ state.buf = state.buf.length ? Buffer.concat([state.buf, chunk]) : chunk;
38
+ for (;;) {
39
+ if (state.buf.length < HEADER_SIZE) {
40
+ return;
41
+ }
42
+ if (!state.buf.subarray(0, 4).equals(MAGIC)) {
43
+ throw new Error('Stream desynchronized: unexpected magic bytes in the streaming protocol header');
44
+ }
45
+ const payloadLength = state.buf.readUInt32BE(24);
46
+ const totalLength = HEADER_SIZE + payloadLength;
47
+ if (state.buf.length < totalLength) {
48
+ return;
49
+ }
50
+ const track = state.buf.readUInt8(5);
51
+ const flags = state.buf.readUInt8(6);
52
+ const sequence = state.buf.readBigUInt64BE(8);
53
+ const timestampMicros = state.buf.readBigUInt64BE(16);
54
+ const data = Buffer.from(state.buf.subarray(HEADER_SIZE, totalLength));
55
+ state.buf = state.buf.subarray(totalLength);
56
+ yield {
57
+ track,
58
+ sequence,
59
+ timestampMicros,
60
+ data,
61
+ isConfig: (flags & FLAG_CONFIG) !== 0,
62
+ isKeyFrame: (flags & FLAG_KEYFRAME) !== 0,
63
+ isEndOfStream: (flags & FLAG_EOS) !== 0,
64
+ };
65
+ }
66
+ }
67
+ //# sourceMappingURL=streaming-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-protocol.js","sourceRoot":"","sources":["../../../lib/utils/streaming-protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,6CAAQ,CAAA;IACR,+CAAS,CAAA;IACT,+CAAS,CAAA;AACX,CAAC,EAJW,WAAW,KAAX,WAAW,QAItB;AAED,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC;AAetB,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAS3C;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,SAAS,CAAC,CAAC,WAAW,CAAC,KAAuB,EAAE,KAAa;IACjE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACzE,SAAS,CAAC;QACR,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAC;QACpG,CAAC;QAED,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC;QAChD,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAgB,CAAC;QACpD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;QAEvE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAE5C,MAAM;YACJ,KAAK;YACL,QAAQ;YACR,eAAe;YACf,IAAI;YACJ,QAAQ,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;YACrC,UAAU,EAAE,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC;YACzC,aAAa,EAAE,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;SACxC,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,142 @@
1
+ import type { ADB } from 'appium-adb';
2
+ import type { LocalPortOpts } from '../commands/types.js';
3
+ import { type StreamFrame } from './streaming-protocol.js';
4
+ /**
5
+ * Describes a decode-dependency chain within the queued items (e.g. H.264/HEVC video
6
+ * frames, where a delta frame is undecodable without every frame back to its last
7
+ * keyframe). Items outside the chain (e.g. an interleaved audio track) are unaffected.
8
+ */
9
+ export interface DependencyChain<T> {
10
+ /** True for items that participate in the chain at all (e.g. non-CONFIG video frames). */
11
+ isChainMember: (item: T) => boolean;
12
+ /** True for a chain member that doesn't depend on earlier ones (e.g. a keyframe). */
13
+ isSyncPoint: (item: T) => boolean;
14
+ }
15
+ /**
16
+ * A bounded async-iterable queue that drops the oldest buffered item once its
17
+ * capacity is exceeded, so a slow consumer never causes unbounded memory growth.
18
+ * An optional `isProtected` predicate can shield items (e.g. video CONFIG frames)
19
+ * from eviction as long as any non-protected item remains to drop instead. An
20
+ * optional `dependencyChain` additionally makes eviction dependency-aware: dropping
21
+ * any chain member cascades to every following chain member up to (not including)
22
+ * the next sync point, and further chain-member pushes are discarded until a fresh
23
+ * sync point arrives - since anything in between is undecodable, buffering it only
24
+ * to have the consumer choke on it later isn't useful.
25
+ */
26
+ export declare class BoundedFrameQueue<T> {
27
+ private readonly capacity;
28
+ private readonly isProtected?;
29
+ private readonly dependencyChain?;
30
+ private readonly items;
31
+ private readonly waiters;
32
+ private readonly errorWaiters;
33
+ private ended;
34
+ private endError;
35
+ private awaitingSyncPoint;
36
+ constructor(capacity?: number, isProtected?: ((item: T) => boolean) | undefined, dependencyChain?: DependencyChain<T> | undefined);
37
+ /**
38
+ * Enqueues an item. If a consumer is already awaiting the next item, it is
39
+ * delivered directly; otherwise it is buffered, dropping the oldest droppable
40
+ * (non-protected) buffered item first if `capacity` would be exceeded. If a
41
+ * `dependencyChain` was given and a prior eviction broke it without a later sync
42
+ * point already buffered, chain-member items are silently discarded here until a
43
+ * fresh sync point item is pushed.
44
+ *
45
+ * @param item - The item to enqueue
46
+ */
47
+ push(item: T): void;
48
+ /**
49
+ * Marks the dependency chain (if configured) as broken by something outside this
50
+ * queue's own eviction - e.g. a producer detecting a sequence gap in items it never
51
+ * even offered here. The next chain-member item pushed is discarded unless it is
52
+ * itself a sync point, exactly as if a local eviction had cascaded off the end of
53
+ * the buffer. A no-op if no `dependencyChain` was configured.
54
+ */
55
+ notifyGap(): void;
56
+ /**
57
+ * Evicts one item to bring the queue back under capacity: the oldest non-protected
58
+ * item, or (if every buffered item is protected, which should not happen in
59
+ * practice) the true oldest one regardless. If the evicted item was a
60
+ * `dependencyChain` member, cascades to drop every following chain member up to
61
+ * the next sync point, setting {@link awaitingSyncPoint} if none is found.
62
+ */
63
+ private evictOnce;
64
+ /**
65
+ * Starting at `index`, removes chain-member items up to (not including) the next
66
+ * sync point, skipping over non-chain-member items (e.g. an interleaved audio
67
+ * track) in place without disturbing them.
68
+ *
69
+ * @returns True if a sync point was found (and kept), false if the scan reached
70
+ * the end of the buffer first
71
+ */
72
+ private dropDependentsFrom;
73
+ /**
74
+ * Ends the queue. Any already-buffered items are still delivered first; once
75
+ * drained, the async iterator completes, rejecting with `error` if one is given.
76
+ * A no-op if the queue has already ended.
77
+ *
78
+ * @param error - Optional error to surface to the consumer once buffered items are drained
79
+ */
80
+ end(error?: Error): void;
81
+ private next;
82
+ /**
83
+ * Async-iterates the queue, yielding items as they are pushed until {@link end} is called.
84
+ */
85
+ [Symbol.asyncIterator](): AsyncGenerator<T>;
86
+ }
87
+ /**
88
+ * Validates local-port selection options for a live stream session.
89
+ *
90
+ * @param opts - Options containing an optional localPort and/or localPortRange
91
+ * @throws {TypeError} If both localPort and localPortRange are provided, or either is malformed
92
+ */
93
+ export declare function validateLocalPortOpts(opts: LocalPortOpts): void;
94
+ /**
95
+ * Resolves the local TCP port to use for the `adb forward` bridge: the exact
96
+ * `localPort` if given, the first free port in `localPortRange` if given, or an
97
+ * OS-assigned ephemeral port otherwise.
98
+ *
99
+ * @param opts - Port selection options; see {@link validateLocalPortOpts}
100
+ * @returns The bound, free local TCP port
101
+ * @throws {Error} If the requested port is busy, or no free port exists in the requested range
102
+ */
103
+ export declare function resolveLocalPort(opts: LocalPortOpts): Promise<number>;
104
+ /**
105
+ * Bridges the on-device local abstract socket to the host over `adb forward`,
106
+ * parses the streaming wire protocol, and exposes the result as a bounded
107
+ * async-iterable frame queue.
108
+ */
109
+ export declare class StreamTransport {
110
+ private readonly adb;
111
+ private readonly localPort;
112
+ private readonly socket;
113
+ private readonly queue;
114
+ private readonly parserState;
115
+ private closed;
116
+ private lastVideoSequence;
117
+ private constructor();
118
+ /**
119
+ * Resolves a local port, forwards it to the on-device local abstract socket via
120
+ * `adb forward`, and connects to it (retrying until the on-device session accepts).
121
+ * On failure, any port forward that was already set up is best-effort removed.
122
+ *
123
+ * @param adb - ADB instance for device communication
124
+ * @param socketName - Name of the on-device local abstract socket to forward
125
+ * @param portOpts - Optional local port selection options
126
+ * @returns A connected StreamTransport instance
127
+ * @throws {Error} If the local port cannot be resolved, or the connection fails
128
+ */
129
+ static connect(adb: ADB, socketName: string, portOpts?: LocalPortOpts): Promise<StreamTransport>;
130
+ private wire;
131
+ /**
132
+ * Returns an async generator yielding parsed frames as they arrive on the socket,
133
+ * until the connection closes or errors.
134
+ */
135
+ frames(): AsyncGenerator<StreamFrame>;
136
+ /**
137
+ * Destroys the client socket and best-effort removes the `adb forward` port
138
+ * mapping. Safe to call more than once.
139
+ */
140
+ close(): Promise<void>;
141
+ }
142
+ //# sourceMappingURL=streaming-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-transport.d.ts","sourceRoot":"","sources":["../../../lib/utils/streaming-transport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,YAAY,CAAC;AAGpC,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAA8C,KAAK,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAUtG;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,0FAA0F;IAC1F,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACpC,qFAAqF;IACrF,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAiB,CAAC,CAAC;IAS5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAVnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkD;IAC1E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;IAChE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,iBAAiB,CAAS;gBAGf,QAAQ,GAAE,MAA+B,EACzC,WAAW,CAAC,GAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,aAAA,EAClC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,YAAA;IAGvD;;;;;;;;;OASG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAwBnB;;;;;;OAMG;IACH,SAAS,IAAI,IAAI;IAMjB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAcjB;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAoBxB,OAAO,CAAC,IAAI;IAaZ;;OAEG;IACI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC;CASnD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAgB/D;AAgCD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B3E;AA+DD;;;;GAIG;AACH,qBAAa,eAAe;IAoBxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAfzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAGnB;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;IACnD,OAAO,CAAC,MAAM,CAAS;IAKvB,OAAO,CAAC,iBAAiB,CAAqB;IAE9C,OAAO;IAMP;;;;;;;;;;OAUG;WACU,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAkB,GAAG,OAAO,CAAC,eAAe,CAAC;IAe1G,OAAO,CAAC,IAAI;IAqBZ;;;OAGG;IACH,MAAM,IAAI,cAAc,CAAC,WAAW,CAAC;IAIrC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}