@yume-chan/adb 0.0.24 → 1.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 (171) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +4 -1
  3. package/esm/adb.d.ts +13 -7
  4. package/esm/adb.d.ts.map +1 -1
  5. package/esm/adb.js +3 -0
  6. package/esm/adb.js.map +1 -1
  7. package/esm/banner.d.ts +7 -6
  8. package/esm/banner.d.ts.map +1 -1
  9. package/esm/banner.js +6 -7
  10. package/esm/banner.js.map +1 -1
  11. package/esm/commands/framebuffer.d.ts +63 -34
  12. package/esm/commands/framebuffer.d.ts.map +1 -1
  13. package/esm/commands/framebuffer.js +35 -33
  14. package/esm/commands/framebuffer.js.map +1 -1
  15. package/esm/commands/reverse.d.ts +12 -12
  16. package/esm/commands/reverse.d.ts.map +1 -1
  17. package/esm/commands/reverse.js +39 -30
  18. package/esm/commands/reverse.js.map +1 -1
  19. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  20. package/esm/commands/subprocess/protocols/none.js +3 -5
  21. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  22. package/esm/commands/subprocess/protocols/shell.d.ts +20 -12
  23. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  24. package/esm/commands/subprocess/protocols/shell.js +16 -21
  25. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  26. package/esm/commands/subprocess/protocols/types.d.ts +6 -6
  27. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  28. package/esm/commands/sync/list.d.ts +49 -27
  29. package/esm/commands/sync/list.d.ts.map +1 -1
  30. package/esm/commands/sync/list.js +9 -9
  31. package/esm/commands/sync/list.js.map +1 -1
  32. package/esm/commands/sync/pull.d.ts +7 -6
  33. package/esm/commands/sync/pull.d.ts.map +1 -1
  34. package/esm/commands/sync/pull.js +3 -5
  35. package/esm/commands/sync/pull.js.map +1 -1
  36. package/esm/commands/sync/push.d.ts +22 -16
  37. package/esm/commands/sync/push.d.ts.map +1 -1
  38. package/esm/commands/sync/push.js +12 -16
  39. package/esm/commands/sync/push.js.map +1 -1
  40. package/esm/commands/sync/request.d.ts +19 -17
  41. package/esm/commands/sync/request.d.ts.map +1 -1
  42. package/esm/commands/sync/request.js +14 -18
  43. package/esm/commands/sync/request.js.map +1 -1
  44. package/esm/commands/sync/response.d.ts +18 -18
  45. package/esm/commands/sync/response.d.ts.map +1 -1
  46. package/esm/commands/sync/response.js +20 -19
  47. package/esm/commands/sync/response.js.map +1 -1
  48. package/esm/commands/sync/socket.d.ts +1 -1
  49. package/esm/commands/sync/socket.js +2 -2
  50. package/esm/commands/sync/socket.js.map +1 -1
  51. package/esm/commands/sync/stat.d.ts +75 -51
  52. package/esm/commands/sync/stat.d.ts.map +1 -1
  53. package/esm/commands/sync/stat.js +73 -67
  54. package/esm/commands/sync/stat.js.map +1 -1
  55. package/esm/commands/sync/sync.d.ts +14 -14
  56. package/esm/commands/sync/sync.d.ts.map +1 -1
  57. package/esm/commands/sync/sync.js +4 -7
  58. package/esm/commands/sync/sync.js.map +1 -1
  59. package/esm/commands/tcpip.d.ts +0 -1
  60. package/esm/commands/tcpip.d.ts.map +1 -1
  61. package/esm/commands/tcpip.js +8 -8
  62. package/esm/commands/tcpip.js.map +1 -1
  63. package/esm/daemon/auth.d.ts +8 -7
  64. package/esm/daemon/auth.d.ts.map +1 -1
  65. package/esm/daemon/auth.js +7 -8
  66. package/esm/daemon/auth.js.map +1 -1
  67. package/esm/daemon/crypto.d.ts +1 -1
  68. package/esm/daemon/crypto.d.ts.map +1 -1
  69. package/esm/daemon/crypto.js +1 -0
  70. package/esm/daemon/crypto.js.map +1 -1
  71. package/esm/daemon/device.d.ts +2 -2
  72. package/esm/daemon/device.d.ts.map +1 -1
  73. package/esm/daemon/dispatcher.js +6 -6
  74. package/esm/daemon/dispatcher.js.map +1 -1
  75. package/esm/daemon/packet.d.ts +46 -30
  76. package/esm/daemon/packet.d.ts.map +1 -1
  77. package/esm/daemon/packet.js +24 -21
  78. package/esm/daemon/packet.js.map +1 -1
  79. package/esm/daemon/socket.d.ts +1 -6
  80. package/esm/daemon/socket.d.ts.map +1 -1
  81. package/esm/daemon/socket.js +4 -27
  82. package/esm/daemon/socket.js.map +1 -1
  83. package/esm/daemon/transport.d.ts +14 -14
  84. package/esm/daemon/transport.d.ts.map +1 -1
  85. package/esm/daemon/transport.js +6 -8
  86. package/esm/daemon/transport.js.map +1 -1
  87. package/esm/device-observer.d.ts +10 -0
  88. package/esm/device-observer.d.ts.map +1 -0
  89. package/esm/device-observer.js +2 -0
  90. package/esm/device-observer.js.map +1 -0
  91. package/esm/features.d.ts +12 -11
  92. package/esm/features.d.ts.map +1 -1
  93. package/esm/features.js +11 -12
  94. package/esm/features.js.map +1 -1
  95. package/esm/index.d.ts +1 -0
  96. package/esm/index.d.ts.map +1 -1
  97. package/esm/index.js +1 -0
  98. package/esm/index.js.map +1 -1
  99. package/esm/server/client.d.ts +33 -35
  100. package/esm/server/client.d.ts.map +1 -1
  101. package/esm/server/client.js +136 -201
  102. package/esm/server/client.js.map +1 -1
  103. package/esm/server/index.d.ts +2 -0
  104. package/esm/server/index.d.ts.map +1 -1
  105. package/esm/server/index.js +2 -0
  106. package/esm/server/index.js.map +1 -1
  107. package/esm/server/observer.d.ts +8 -0
  108. package/esm/server/observer.d.ts.map +1 -0
  109. package/esm/server/observer.js +106 -0
  110. package/esm/server/observer.js.map +1 -0
  111. package/esm/server/stream.d.ts +19 -0
  112. package/esm/server/stream.d.ts.map +1 -0
  113. package/esm/server/stream.js +77 -0
  114. package/esm/server/stream.js.map +1 -0
  115. package/esm/server/transport.d.ts +3 -4
  116. package/esm/server/transport.d.ts.map +1 -1
  117. package/esm/server/transport.js +16 -16
  118. package/esm/server/transport.js.map +1 -1
  119. package/esm/utils/base64.d.ts.map +1 -1
  120. package/esm/utils/base64.js +19 -16
  121. package/esm/utils/base64.js.map +1 -1
  122. package/esm/utils/index.d.ts +1 -0
  123. package/esm/utils/index.d.ts.map +1 -1
  124. package/esm/utils/index.js +1 -0
  125. package/esm/utils/index.js.map +1 -1
  126. package/esm/utils/no-op.d.ts.map +1 -1
  127. package/esm/utils/no-op.js +1 -0
  128. package/esm/utils/no-op.js.map +1 -1
  129. package/esm/utils/ref.d.ts +18 -0
  130. package/esm/utils/ref.d.ts.map +1 -0
  131. package/esm/utils/ref.js +29 -0
  132. package/esm/utils/ref.js.map +1 -0
  133. package/package.json +13 -16
  134. package/src/adb.ts +13 -7
  135. package/src/banner.ts +8 -6
  136. package/src/commands/framebuffer.ts +44 -35
  137. package/src/commands/reverse.ts +49 -31
  138. package/src/commands/subprocess/protocols/none.ts +3 -5
  139. package/src/commands/subprocess/protocols/shell.ts +26 -24
  140. package/src/commands/subprocess/protocols/types.ts +6 -6
  141. package/src/commands/sync/list.ts +20 -13
  142. package/src/commands/sync/pull.ts +8 -7
  143. package/src/commands/sync/push.ts +20 -16
  144. package/src/commands/sync/request.ts +18 -19
  145. package/src/commands/sync/response.ts +28 -29
  146. package/src/commands/sync/socket.ts +2 -2
  147. package/src/commands/sync/stat.ts +93 -71
  148. package/src/commands/sync/sync.ts +4 -8
  149. package/src/commands/tcpip.ts +8 -8
  150. package/src/daemon/auth.ts +11 -9
  151. package/src/daemon/crypto.ts +2 -0
  152. package/src/daemon/device.ts +2 -2
  153. package/src/daemon/dispatcher.ts +6 -6
  154. package/src/daemon/packet.ts +37 -25
  155. package/src/daemon/socket.ts +4 -27
  156. package/src/daemon/transport.ts +36 -35
  157. package/src/device-observer.ts +10 -0
  158. package/src/features.ts +13 -11
  159. package/src/index.ts +1 -0
  160. package/src/server/client.ts +181 -242
  161. package/src/server/index.ts +2 -0
  162. package/src/server/observer.ts +144 -0
  163. package/src/server/stream.ts +100 -0
  164. package/src/server/transport.ts +18 -17
  165. package/src/utils/base64.ts +26 -18
  166. package/src/utils/index.ts +1 -0
  167. package/src/utils/no-op.ts +1 -0
  168. package/src/utils/ref.ts +37 -0
  169. package/tsconfig.build.json +1 -12
  170. package/tsconfig.build.tsbuildinfo +1 -1
  171. package/CHANGELOG.json +0 -298
package/src/adb.ts CHANGED
@@ -1,9 +1,9 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
1
2
  import type {
2
3
  MaybeConsumable,
3
4
  ReadableWritablePair,
4
5
  } from "@yume-chan/stream-extra";
5
6
  import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra";
6
- import type { ValueOrPromise } from "@yume-chan/struct";
7
7
 
8
8
  import type { AdbBanner } from "./banner.js";
9
9
  import type { AdbFrameBuffer } from "./commands/index.js";
@@ -19,9 +19,12 @@ import {
19
19
  import type { AdbFeature } from "./features.js";
20
20
 
21
21
  export interface Closeable {
22
- close(): ValueOrPromise<void>;
22
+ close(): MaybePromiseLike<void>;
23
23
  }
24
24
 
25
+ /**
26
+ * Represents an ADB socket.
27
+ */
25
28
  export interface AdbSocket
26
29
  extends ReadableWritablePair<Uint8Array, MaybeConsumable<Uint8Array>>,
27
30
  Closeable {
@@ -32,7 +35,7 @@ export interface AdbSocket
32
35
 
33
36
  export type AdbIncomingSocketHandler = (
34
37
  socket: AdbSocket,
35
- ) => ValueOrPromise<void>;
38
+ ) => MaybePromiseLike<void>;
36
39
 
37
40
  export interface AdbTransport extends Closeable {
38
41
  readonly serial: string;
@@ -45,16 +48,16 @@ export interface AdbTransport extends Closeable {
45
48
 
46
49
  readonly clientFeatures: readonly AdbFeature[];
47
50
 
48
- connect(service: string): ValueOrPromise<AdbSocket>;
51
+ connect(service: string): MaybePromiseLike<AdbSocket>;
49
52
 
50
53
  addReverseTunnel(
51
54
  handler: AdbIncomingSocketHandler,
52
55
  address?: string,
53
- ): ValueOrPromise<string>;
56
+ ): MaybePromiseLike<string>;
54
57
 
55
- removeReverseTunnel(address: string): ValueOrPromise<void>;
58
+ removeReverseTunnel(address: string): MaybePromiseLike<void>;
56
59
 
57
- clearReverseTunnels(): ValueOrPromise<void>;
60
+ clearReverseTunnels(): MaybePromiseLike<void>;
58
61
  }
59
62
 
60
63
  export class Adb implements Closeable {
@@ -105,6 +108,9 @@ export class Adb implements Closeable {
105
108
  );
106
109
  }
107
110
 
111
+ /**
112
+ * Creates a new ADB Socket to the specified service or socket address.
113
+ */
108
114
  async createSocket(service: string): Promise<AdbSocket> {
109
115
  return this.transport.connect(service);
110
116
  }
package/src/banner.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import type { AdbFeature } from "./features.js";
2
2
 
3
- export enum AdbBannerKey {
4
- Product = "ro.product.name",
5
- Model = "ro.product.model",
6
- Device = "ro.product.device",
7
- Features = "features",
8
- }
3
+ export const AdbBannerKey = {
4
+ Product: "ro.product.name",
5
+ Model: "ro.product.model",
6
+ Device: "ro.product.device",
7
+ Features: "features",
8
+ } as const;
9
+
10
+ export type AdbBannerKey = (typeof AdbBannerKey)[keyof typeof AdbBannerKey];
9
11
 
10
12
  export class AdbBanner {
11
13
  static parse(banner: string) {
@@ -1,44 +1,53 @@
1
1
  import { BufferedReadableStream } from "@yume-chan/stream-extra";
2
- import Struct, { StructEmptyError } from "@yume-chan/struct";
2
+ import type { StructValue } from "@yume-chan/struct";
3
+ import { buffer, struct, StructEmptyError, u32 } from "@yume-chan/struct";
3
4
 
4
5
  import type { Adb } from "../adb.js";
5
6
 
6
- const Version = new Struct({ littleEndian: true }).uint32("version");
7
+ const Version = struct({ version: u32 }, { littleEndian: true });
7
8
 
8
- export const AdbFrameBufferV1 = new Struct({ littleEndian: true })
9
- .uint32("bpp")
10
- .uint32("size")
11
- .uint32("width")
12
- .uint32("height")
13
- .uint32("red_offset")
14
- .uint32("red_length")
15
- .uint32("blue_offset")
16
- .uint32("blue_length")
17
- .uint32("green_offset")
18
- .uint32("green_length")
19
- .uint32("alpha_offset")
20
- .uint32("alpha_length")
21
- .uint8Array("data", { lengthField: "size" });
9
+ export const AdbFrameBufferV1 = struct(
10
+ {
11
+ bpp: u32,
12
+ size: u32,
13
+ width: u32,
14
+ height: u32,
15
+ red_offset: u32,
16
+ red_length: u32,
17
+ blue_offset: u32,
18
+ blue_length: u32,
19
+ green_offset: u32,
20
+ green_length: u32,
21
+ alpha_offset: u32,
22
+ alpha_length: u32,
23
+ data: buffer("size"),
24
+ },
25
+ { littleEndian: true },
26
+ );
22
27
 
23
- export type AdbFrameBufferV1 = (typeof AdbFrameBufferV1)["TDeserializeResult"];
28
+ export type AdbFrameBufferV1 = StructValue<typeof AdbFrameBufferV1>;
24
29
 
25
- export const AdbFrameBufferV2 = new Struct({ littleEndian: true })
26
- .uint32("bpp")
27
- .uint32("colorSpace")
28
- .uint32("size")
29
- .uint32("width")
30
- .uint32("height")
31
- .uint32("red_offset")
32
- .uint32("red_length")
33
- .uint32("blue_offset")
34
- .uint32("blue_length")
35
- .uint32("green_offset")
36
- .uint32("green_length")
37
- .uint32("alpha_offset")
38
- .uint32("alpha_length")
39
- .uint8Array("data", { lengthField: "size" });
30
+ export const AdbFrameBufferV2 = struct(
31
+ {
32
+ bpp: u32,
33
+ colorSpace: u32,
34
+ size: u32,
35
+ width: u32,
36
+ height: u32,
37
+ red_offset: u32,
38
+ red_length: u32,
39
+ blue_offset: u32,
40
+ blue_length: u32,
41
+ green_offset: u32,
42
+ green_length: u32,
43
+ alpha_offset: u32,
44
+ alpha_length: u32,
45
+ data: buffer("size"),
46
+ },
47
+ { littleEndian: true },
48
+ );
40
49
 
41
- export type AdbFrameBufferV2 = (typeof AdbFrameBufferV2)["TDeserializeResult"];
50
+ export type AdbFrameBufferV2 = StructValue<typeof AdbFrameBufferV2>;
42
51
 
43
52
  /**
44
53
  * ADB uses 8 int32 fields to describe bit depths
@@ -93,9 +102,9 @@ export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
93
102
  switch (version) {
94
103
  case 1:
95
104
  // TODO: AdbFrameBuffer: does all v1 responses uses the same color space? Add it so the command returns same format for all versions.
96
- return AdbFrameBufferV1.deserialize(stream);
105
+ return await AdbFrameBufferV1.deserialize(stream);
97
106
  case 2:
98
- return AdbFrameBufferV2.deserialize(stream);
107
+ return await AdbFrameBufferV2.deserialize(stream);
99
108
  default:
100
109
  throw new AdbFrameBufferUnsupportedVersionError(version);
101
110
  }
@@ -1,8 +1,12 @@
1
1
  // cspell: ignore killforward
2
2
 
3
- import { AutoDisposable } from "@yume-chan/event";
4
3
  import { BufferedReadableStream } from "@yume-chan/stream-extra";
5
- import Struct, { ExactReadableEndedError, encodeUtf8 } from "@yume-chan/struct";
4
+ import {
5
+ encodeUtf8,
6
+ ExactReadableEndedError,
7
+ string,
8
+ struct,
9
+ } from "@yume-chan/struct";
6
10
 
7
11
  import type { Adb, AdbIncomingSocketHandler } from "../adb.js";
8
12
  import { hexToNumber, sequenceEqual } from "../utils/index.js";
@@ -15,14 +19,25 @@ export interface AdbForwardListener {
15
19
  remoteName: string;
16
20
  }
17
21
 
18
- const AdbReverseStringResponse = new Struct()
19
- .string("length", { length: 4 })
20
- .string("content", { lengthField: "length", lengthFieldRadix: 16 });
22
+ const AdbReverseStringResponse = struct(
23
+ {
24
+ length: string(4),
25
+ content: string({
26
+ field: "length",
27
+ convert(value: string) {
28
+ return Number.parseInt(value, 16);
29
+ },
30
+ back(value) {
31
+ return value.toString(16).padStart(4, "0");
32
+ },
33
+ }),
34
+ },
35
+ { littleEndian: true },
36
+ );
21
37
 
22
38
  export class AdbReverseError extends Error {
23
39
  constructor(message: string) {
24
40
  super(message);
25
- Object.setPrototypeOf(this, new.target.prototype);
26
41
  }
27
42
  }
28
43
 
@@ -34,18 +49,22 @@ export class AdbReverseNotSupportedError extends AdbReverseError {
34
49
  }
35
50
  }
36
51
 
37
- const AdbReverseErrorResponse = new Struct()
38
- .concat(AdbReverseStringResponse)
39
- .postDeserialize((value) => {
40
- // https://issuetracker.google.com/issues/37066218
41
- // ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
42
- // and returns this confusing "more than one device/emulator" error.
43
- if (value.content === "more than one device/emulator") {
44
- throw new AdbReverseNotSupportedError();
45
- } else {
46
- throw new AdbReverseError(value.content);
47
- }
48
- });
52
+ const AdbReverseErrorResponse = struct(
53
+ /* #__PURE__ */ (() => AdbReverseStringResponse.fields)(),
54
+ {
55
+ littleEndian: true,
56
+ postDeserialize: (value) => {
57
+ // https://issuetracker.google.com/issues/37066218
58
+ // ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
59
+ // and returns this confusing "more than one device/emulator" error.
60
+ if (value.content === "more than one device/emulator") {
61
+ throw new AdbReverseNotSupportedError();
62
+ } else {
63
+ throw new AdbReverseError(value.content);
64
+ }
65
+ },
66
+ },
67
+ );
49
68
 
50
69
  // Like `hexToNumber`, it's much faster than first converting `buffer` to a string
51
70
  function decimalToNumber(buffer: Uint8Array) {
@@ -62,14 +81,12 @@ function decimalToNumber(buffer: Uint8Array) {
62
81
 
63
82
  const OKAY = encodeUtf8("OKAY");
64
83
 
65
- export class AdbReverseCommand extends AutoDisposable {
84
+ export class AdbReverseCommand {
66
85
  protected adb: Adb;
67
86
 
68
87
  readonly #deviceAddressToLocalAddress = new Map<string, string>();
69
88
 
70
89
  constructor(adb: Adb) {
71
- super();
72
-
73
90
  this.adb = adb;
74
91
  }
75
92
 
@@ -89,6 +106,9 @@ export class AdbReverseCommand extends AutoDisposable {
89
106
  return stream;
90
107
  }
91
108
 
109
+ /**
110
+ * Get a list of all reverse port forwarding on the device.
111
+ */
92
112
  async list(): Promise<AdbForwardListener[]> {
93
113
  const stream = await this.createBufferedStream("reverse:list-forward");
94
114
 
@@ -107,10 +127,7 @@ export class AdbReverseCommand extends AutoDisposable {
107
127
  }
108
128
 
109
129
  /**
110
- * Add an already existing reverse tunnel. Depends on the transport type, this may not do anything.
111
- * @param deviceAddress The address to be listened on device by ADB daemon. Or `tcp:0` to choose an available TCP port.
112
- * @param localAddress The address that listens on the local machine.
113
- * @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
130
+ * Add a reverse port forwarding for a program that already listens on a port.
114
131
  */
115
132
  async addExternal(deviceAddress: string, localAddress: string) {
116
133
  const stream = await this.sendRequest(
@@ -143,12 +160,7 @@ export class AdbReverseCommand extends AutoDisposable {
143
160
  }
144
161
 
145
162
  /**
146
- * @param deviceAddress The address to be listened on device by ADB daemon. Or `tcp:0` to choose an available TCP port.
147
- * @param handler A callback to handle incoming connections.
148
- * @param localAddressThe The address that listens on the local machine. May be `undefined` to let the transport choose an appropriate one.
149
- * @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
150
- * @throws {AdbReverseNotSupportedError} If ADB reverse tunnel is not supported on this device when connected wirelessly.
151
- * @throws {AdbReverseError} If ADB daemon returns an error.
163
+ * Add a reverse port forwarding.
152
164
  */
153
165
  async add(
154
166
  deviceAddress: string,
@@ -170,6 +182,9 @@ export class AdbReverseCommand extends AutoDisposable {
170
182
  }
171
183
  }
172
184
 
185
+ /**
186
+ * Remove a reverse port forwarding.
187
+ */
173
188
  async remove(deviceAddress: string): Promise<void> {
174
189
  const localAddress =
175
190
  this.#deviceAddressToLocalAddress.get(deviceAddress);
@@ -182,6 +197,9 @@ export class AdbReverseCommand extends AutoDisposable {
182
197
  // No need to close the stream, device will close it
183
198
  }
184
199
 
200
+ /**
201
+ * Remove all reverse port forwarding, including the ones added by other programs.
202
+ */
185
203
  async removeAll(): Promise<void> {
186
204
  await this.adb.transport.clearReverseTunnels();
187
205
  this.#deviceAddressToLocalAddress.clear();
@@ -2,7 +2,6 @@ import type { MaybeConsumable, WritableStream } from "@yume-chan/stream-extra";
2
2
  import { ReadableStream } from "@yume-chan/stream-extra";
3
3
 
4
4
  import type { Adb, AdbSocket } from "../../../adb.js";
5
- import { unreachable } from "../../../utils/index.js";
6
5
 
7
6
  import type { AdbSubprocessProtocol } from "./types.js";
8
7
 
@@ -64,10 +63,9 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
64
63
  this.#socket = socket;
65
64
 
66
65
  this.#stderr = new ReadableStream({
67
- start: (controller) => {
68
- this.#socket.closed
69
- .then(() => controller.close())
70
- .catch(unreachable);
66
+ start: async (controller) => {
67
+ await this.#socket.closed;
68
+ controller.close();
71
69
  },
72
70
  });
73
71
  this.#exit = socket.closed.then(() => 0);
@@ -10,8 +10,8 @@ import {
10
10
  StructDeserializeStream,
11
11
  WritableStream,
12
12
  } from "@yume-chan/stream-extra";
13
- import type { StructValueType } from "@yume-chan/struct";
14
- import Struct, { placeholder } from "@yume-chan/struct";
13
+ import type { StructValue } from "@yume-chan/struct";
14
+ import { buffer, struct, u32, u8 } from "@yume-chan/struct";
15
15
 
16
16
  import type { Adb, AdbSocket } from "../../../adb.js";
17
17
  import { AdbFeature } from "../../../features.js";
@@ -19,22 +19,28 @@ import { encodeUtf8 } from "../../../utils/index.js";
19
19
 
20
20
  import type { AdbSubprocessProtocol } from "./types.js";
21
21
 
22
- export enum AdbShellProtocolId {
23
- Stdin,
24
- Stdout,
25
- Stderr,
26
- Exit,
27
- CloseStdin,
28
- WindowSizeChange,
29
- }
30
-
31
- // This packet format is used in both direction.
32
- const AdbShellProtocolPacket = new Struct({ littleEndian: true })
33
- .uint8("id", placeholder<AdbShellProtocolId>())
34
- .uint32("length")
35
- .uint8Array("data", { lengthField: "length" });
36
-
37
- type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
22
+ export const AdbShellProtocolId = {
23
+ Stdin: 0,
24
+ Stdout: 1,
25
+ Stderr: 2,
26
+ Exit: 3,
27
+ CloseStdin: 4,
28
+ WindowSizeChange: 5,
29
+ } as const;
30
+
31
+ export type AdbShellProtocolId =
32
+ (typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
33
+
34
+ // This packet format is used in both directions.
35
+ export const AdbShellProtocolPacket = struct(
36
+ {
37
+ id: u8<AdbShellProtocolId>(),
38
+ data: buffer(u32),
39
+ },
40
+ { littleEndian: true },
41
+ );
42
+
43
+ type AdbShellProtocolPacket = StructValue<typeof AdbShellProtocolPacket>;
38
44
 
39
45
  /**
40
46
  * Shell v2 a.k.a Shell Protocol
@@ -107,14 +113,10 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
107
113
  this.#exit.resolve(chunk.data[0]!);
108
114
  break;
109
115
  case AdbShellProtocolId.Stdout:
110
- if (!stdoutController.abortSignal.aborted) {
111
- await stdoutController.enqueue(chunk.data);
112
- }
116
+ await stdoutController.enqueue(chunk.data);
113
117
  break;
114
118
  case AdbShellProtocolId.Stderr:
115
- if (!stderrController.abortSignal.aborted) {
116
- await stderrController.enqueue(chunk.data);
117
- }
119
+ await stderrController.enqueue(chunk.data);
118
120
  break;
119
121
  }
120
122
  },
@@ -1,9 +1,9 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
1
2
  import type {
2
3
  MaybeConsumable,
3
4
  ReadableStream,
4
5
  WritableStream,
5
6
  } from "@yume-chan/stream-extra";
6
- import type { ValueOrPromise } from "@yume-chan/struct";
7
7
 
8
8
  import type { Adb, AdbSocket } from "../../../adb.js";
9
9
 
@@ -40,23 +40,23 @@ export interface AdbSubprocessProtocol {
40
40
  * Some `AdbSubprocessProtocol`s may not support resizing
41
41
  * and will ignore calls to this method.
42
42
  */
43
- resize(rows: number, cols: number): ValueOrPromise<void>;
43
+ resize(rows: number, cols: number): MaybePromiseLike<void>;
44
44
 
45
45
  /**
46
46
  * Kills the current process.
47
47
  */
48
- kill(): ValueOrPromise<void>;
48
+ kill(): MaybePromiseLike<void>;
49
49
  }
50
50
 
51
51
  export interface AdbSubprocessProtocolConstructor {
52
52
  /** Returns `true` if the `adb` instance supports this shell */
53
- isSupported(adb: Adb): ValueOrPromise<boolean>;
53
+ isSupported(adb: Adb): MaybePromiseLike<boolean>;
54
54
 
55
55
  /** Spawns an executable in PTY (interactive) mode. */
56
- pty(adb: Adb, command: string): ValueOrPromise<AdbSubprocessProtocol>;
56
+ pty(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
57
57
 
58
58
  /** Spawns an executable and pipe the output. */
59
- raw(adb: Adb, command: string): ValueOrPromise<AdbSubprocessProtocol>;
59
+ raw(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
60
60
 
61
61
  /** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */
62
62
  new (socket: AdbSocket): AdbSubprocessProtocol;
@@ -1,4 +1,5 @@
1
- import Struct from "@yume-chan/struct";
1
+ import type { StructValue } from "@yume-chan/struct";
2
+ import { string, struct, u32 } from "@yume-chan/struct";
2
3
 
3
4
  import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
4
5
  import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
@@ -14,21 +15,27 @@ export interface AdbSyncEntry extends AdbSyncStat {
14
15
  name: string;
15
16
  }
16
17
 
17
- export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
18
- .concat(AdbSyncLstatResponse)
19
- .uint32("nameLength")
20
- .string("name", { lengthField: "nameLength" });
18
+ export const AdbSyncEntryResponse = /* #__PURE__ */ (() =>
19
+ struct(
20
+ {
21
+ ...AdbSyncLstatResponse.fields,
22
+ name: string(u32),
23
+ },
24
+ { littleEndian: true, extra: AdbSyncLstatResponse.extra },
25
+ ))();
21
26
 
22
- export type AdbSyncEntryResponse =
23
- (typeof AdbSyncEntryResponse)["TDeserializeResult"];
27
+ export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
24
28
 
25
- export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
26
- .concat(AdbSyncStatResponse)
27
- .uint32("nameLength")
28
- .string("name", { lengthField: "nameLength" });
29
+ export const AdbSyncEntry2Response = /* #__PURE__ */ (() =>
30
+ struct(
31
+ {
32
+ ...AdbSyncStatResponse.fields,
33
+ name: string(u32),
34
+ },
35
+ { littleEndian: true, extra: AdbSyncStatResponse.extra },
36
+ ))();
29
37
 
30
- export type AdbSyncEntry2Response =
31
- (typeof AdbSyncEntry2Response)["TDeserializeResult"];
38
+ export type AdbSyncEntry2Response = StructValue<typeof AdbSyncEntry2Response>;
32
39
 
33
40
  export async function* adbSyncOpenDirV2(
34
41
  socket: AdbSyncSocket,
@@ -1,17 +1,18 @@
1
1
  import type { ReadableStream } from "@yume-chan/stream-extra";
2
2
  import { PushReadableStream } from "@yume-chan/stream-extra";
3
- import Struct from "@yume-chan/struct";
3
+ import type { StructValue } from "@yume-chan/struct";
4
+ import { buffer, struct, u32 } from "@yume-chan/struct";
4
5
 
5
6
  import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
6
- import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
7
+ import { adbSyncReadResponses, AdbSyncResponseId } from "./response.js";
7
8
  import type { AdbSyncSocket } from "./socket.js";
8
9
 
9
- export const AdbSyncDataResponse = new Struct({ littleEndian: true })
10
- .uint32("dataLength")
11
- .uint8Array("data", { lengthField: "dataLength" });
10
+ export const AdbSyncDataResponse = struct(
11
+ { data: buffer(u32) },
12
+ { littleEndian: true },
13
+ );
12
14
 
13
- export type AdbSyncDataResponse =
14
- (typeof AdbSyncDataResponse)["TDeserializeResult"];
15
+ export type AdbSyncDataResponse = StructValue<typeof AdbSyncDataResponse>;
15
16
 
16
17
  export async function* adbSyncPullGenerator(
17
18
  socket: AdbSyncSocket,
@@ -4,7 +4,7 @@ import {
4
4
  DistributionStream,
5
5
  MaybeConsumable,
6
6
  } from "@yume-chan/stream-extra";
7
- import Struct, { placeholder } from "@yume-chan/struct";
7
+ import { struct, u32 } from "@yume-chan/struct";
8
8
 
9
9
  import { NOOP } from "../../utils/index.js";
10
10
 
@@ -25,8 +25,9 @@ export interface AdbSyncPushV1Options {
25
25
  packetSize?: number;
26
26
  }
27
27
 
28
- export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
29
- "unused",
28
+ export const AdbSyncOkResponse = struct(
29
+ { unused: u32 },
30
+ { littleEndian: true },
30
31
  );
31
32
 
32
33
  async function pipeFileData(
@@ -41,8 +42,8 @@ async function pipeFileData(
41
42
  file.pipeThrough(new DistributionStream(packetSize, true))
42
43
  .pipeTo(
43
44
  new MaybeConsumable.WritableStream({
44
- write: async (chunk) => {
45
- await adbSyncWriteRequest(
45
+ write(chunk) {
46
+ return adbSyncWriteRequest(
46
47
  locked,
47
48
  AdbSyncRequestId.Data,
48
49
  chunk,
@@ -86,19 +87,22 @@ export async function adbSyncPushV1({
86
87
  }
87
88
  }
88
89
 
89
- export enum AdbSyncSendV2Flags {
90
- None = 0,
91
- Brotli = 1,
90
+ export const AdbSyncSendV2Flags = {
91
+ None: 0,
92
+ Brotli: 1,
92
93
  /**
93
94
  * 2
94
95
  */
95
- Lz4 = 1 << 1,
96
+ Lz4: 1 << 1,
96
97
  /**
97
98
  * 4
98
99
  */
99
- Zstd = 1 << 2,
100
- DryRun = 0x80000000,
101
- }
100
+ Zstd: 1 << 2,
101
+ DryRun: 0x80000000,
102
+ } as const;
103
+
104
+ export type AdbSyncSendV2Flags =
105
+ (typeof AdbSyncSendV2Flags)[keyof typeof AdbSyncSendV2Flags];
102
106
 
103
107
  export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
104
108
  /**
@@ -110,10 +114,10 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
110
114
  dryRun?: boolean;
111
115
  }
112
116
 
113
- export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
114
- .uint32("id")
115
- .uint32("mode")
116
- .uint32("flags", placeholder<AdbSyncSendV2Flags>());
117
+ export const AdbSyncSendV2Request = struct(
118
+ { id: u32, mode: u32, flags: u32<AdbSyncSendV2Flags>() },
119
+ { littleEndian: true },
120
+ );
117
121
 
118
122
  export async function adbSyncPushV2({
119
123
  socket,
@@ -1,25 +1,24 @@
1
- import Struct from "@yume-chan/struct";
2
-
3
- import { encodeUtf8 } from "../../utils/index.js";
1
+ import { encodeUtf8, struct, u32 } from "@yume-chan/struct";
4
2
 
5
3
  import { adbSyncEncodeId } from "./response.js";
6
4
 
7
- export namespace AdbSyncRequestId {
8
- export const List = adbSyncEncodeId("LIST");
9
- export const ListV2 = adbSyncEncodeId("LIS2");
10
- export const Send = adbSyncEncodeId("SEND");
11
- export const SendV2 = adbSyncEncodeId("SND2");
12
- export const Lstat = adbSyncEncodeId("STAT");
13
- export const Stat = adbSyncEncodeId("STA2");
14
- export const LstatV2 = adbSyncEncodeId("LST2");
15
- export const Data = adbSyncEncodeId("DATA");
16
- export const Done = adbSyncEncodeId("DONE");
17
- export const Receive = adbSyncEncodeId("RECV");
18
- }
19
-
20
- export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
21
- .uint32("id")
22
- .uint32("arg");
5
+ export const AdbSyncRequestId = {
6
+ List: adbSyncEncodeId("LIST"),
7
+ ListV2: adbSyncEncodeId("LIS2"),
8
+ Send: adbSyncEncodeId("SEND"),
9
+ SendV2: adbSyncEncodeId("SND2"),
10
+ Lstat: adbSyncEncodeId("STAT"),
11
+ Stat: adbSyncEncodeId("STA2"),
12
+ LstatV2: adbSyncEncodeId("LST2"),
13
+ Data: adbSyncEncodeId("DATA"),
14
+ Done: adbSyncEncodeId("DONE"),
15
+ Receive: adbSyncEncodeId("RECV"),
16
+ } as const;
17
+
18
+ export const AdbSyncNumberRequest = struct(
19
+ { id: u32, arg: u32 },
20
+ { littleEndian: true },
21
+ );
23
22
 
24
23
  export interface AdbSyncWritable {
25
24
  write(buffer: Uint8Array): Promise<void>;