@yume-chan/adb 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/CHANGELOG.json +26 -0
  2. package/CHANGELOG.md +15 -1
  3. package/LICENSE +1 -1
  4. package/README.md +56 -43
  5. package/esm/adb.d.ts +48 -0
  6. package/esm/adb.d.ts.map +1 -0
  7. package/esm/adb.js +141 -146
  8. package/esm/adb.js.map +1 -1
  9. package/{dts → esm}/auth.d.ts +8 -8
  10. package/esm/auth.d.ts.map +1 -0
  11. package/esm/auth.js +68 -108
  12. package/esm/auth.js.map +1 -1
  13. package/esm/backend.d.ts +9 -0
  14. package/esm/backend.d.ts.map +1 -0
  15. package/{dts → esm}/commands/base.d.ts +1 -1
  16. package/esm/commands/base.d.ts.map +1 -0
  17. package/esm/commands/base.js +1 -0
  18. package/esm/commands/base.js.map +1 -1
  19. package/{dts → esm}/commands/framebuffer.d.ts +3 -3
  20. package/esm/commands/framebuffer.d.ts.map +1 -0
  21. package/esm/commands/framebuffer.js +15 -18
  22. package/esm/commands/framebuffer.js.map +1 -1
  23. package/esm/commands/index.d.ts +9 -0
  24. package/esm/commands/index.d.ts.map +1 -0
  25. package/esm/commands/index.js +8 -8
  26. package/esm/commands/index.js.map +1 -1
  27. package/esm/commands/install.d.ts +4 -0
  28. package/esm/commands/install.d.ts.map +1 -0
  29. package/esm/commands/install.js +21 -13
  30. package/esm/commands/install.js.map +1 -1
  31. package/esm/commands/power.d.ts +23 -0
  32. package/esm/commands/power.d.ts.map +1 -0
  33. package/esm/commands/power.js +45 -0
  34. package/esm/commands/power.js.map +1 -0
  35. package/{dts → esm}/commands/reverse.d.ts +3 -3
  36. package/esm/commands/reverse.d.ts.map +1 -0
  37. package/esm/commands/reverse.js +49 -60
  38. package/esm/commands/reverse.js.map +1 -1
  39. package/esm/commands/subprocess/index.d.ts +57 -0
  40. package/esm/commands/subprocess/index.d.ts.map +1 -0
  41. package/esm/commands/subprocess/index.js +83 -0
  42. package/esm/commands/subprocess/index.js.map +1 -0
  43. package/esm/commands/subprocess/legacy.d.ts +28 -0
  44. package/esm/commands/subprocess/legacy.d.ts.map +1 -0
  45. package/esm/commands/subprocess/legacy.js +44 -0
  46. package/esm/commands/subprocess/legacy.js.map +1 -0
  47. package/esm/commands/subprocess/protocol.d.ts +38 -0
  48. package/esm/commands/subprocess/protocol.d.ts.map +1 -0
  49. package/esm/commands/subprocess/protocol.js +155 -0
  50. package/esm/commands/subprocess/protocol.js.map +1 -0
  51. package/esm/commands/subprocess/types.d.ts +47 -0
  52. package/esm/commands/subprocess/types.d.ts.map +1 -0
  53. package/esm/commands/{shell → subprocess}/types.js +0 -0
  54. package/esm/commands/{shell → subprocess}/types.js.map +1 -1
  55. package/{dts/commands/shell → esm/commands/subprocess}/utils.d.ts +0 -0
  56. package/esm/commands/subprocess/utils.d.ts.map +1 -0
  57. package/esm/commands/{shell → subprocess}/utils.js +0 -0
  58. package/esm/commands/subprocess/utils.js.map +1 -0
  59. package/esm/commands/sync/index.d.ts +8 -0
  60. package/esm/commands/sync/index.d.ts.map +1 -0
  61. package/esm/commands/sync/index.js +7 -7
  62. package/esm/commands/sync/index.js.map +1 -1
  63. package/{dts → esm}/commands/sync/list.d.ts +4 -4
  64. package/esm/commands/sync/list.d.ts.map +1 -0
  65. package/esm/commands/sync/list.js +16 -19
  66. package/esm/commands/sync/list.js.map +1 -1
  67. package/esm/commands/sync/pull.d.ts +11 -0
  68. package/esm/commands/sync/pull.d.ts.map +1 -0
  69. package/esm/commands/sync/pull.js +17 -11
  70. package/esm/commands/sync/pull.js.map +1 -1
  71. package/esm/commands/sync/push.d.ts +8 -0
  72. package/esm/commands/sync/push.d.ts.map +1 -0
  73. package/esm/commands/sync/push.js +19 -37
  74. package/esm/commands/sync/push.js.map +1 -1
  75. package/{dts → esm}/commands/sync/request.d.ts +3 -3
  76. package/esm/commands/sync/request.d.ts.map +1 -0
  77. package/esm/commands/sync/request.js +24 -27
  78. package/esm/commands/sync/request.js.map +1 -1
  79. package/{dts → esm}/commands/sync/response.d.ts +2 -2
  80. package/esm/commands/sync/response.d.ts.map +1 -0
  81. package/esm/commands/sync/response.js +16 -20
  82. package/esm/commands/sync/response.js.map +1 -1
  83. package/{dts → esm}/commands/sync/stat.d.ts +4 -4
  84. package/esm/commands/sync/stat.d.ts.map +1 -0
  85. package/esm/commands/sync/stat.js +22 -27
  86. package/esm/commands/sync/stat.js.map +1 -1
  87. package/esm/commands/sync/sync.d.ts +83 -0
  88. package/esm/commands/sync/sync.d.ts.map +1 -0
  89. package/esm/commands/sync/sync.js +92 -89
  90. package/esm/commands/sync/sync.js.map +1 -1
  91. package/{dts → esm}/commands/tcpip.d.ts +1 -1
  92. package/{dts → esm}/commands/tcpip.d.ts.map +1 -1
  93. package/esm/commands/tcpip.js +14 -19
  94. package/esm/commands/tcpip.js.map +1 -1
  95. package/{dts → esm}/crypto.d.ts +7 -7
  96. package/esm/crypto.d.ts.map +1 -0
  97. package/esm/crypto.js +26 -29
  98. package/esm/crypto.js.map +1 -1
  99. package/{dts → esm}/features.d.ts +0 -0
  100. package/{dts → esm}/features.d.ts.map +0 -0
  101. package/esm/features.js +1 -1
  102. package/esm/features.js.map +1 -1
  103. package/esm/index.d.ts +11 -0
  104. package/esm/index.d.ts.map +1 -0
  105. package/esm/index.js +10 -10
  106. package/esm/index.js.map +1 -1
  107. package/esm/packet.d.ts +28 -0
  108. package/esm/packet.d.ts.map +1 -0
  109. package/esm/packet.js +26 -51
  110. package/esm/packet.js.map +1 -1
  111. package/esm/socket/controller.d.ts +37 -0
  112. package/esm/socket/controller.d.ts.map +1 -0
  113. package/esm/socket/controller.js +52 -66
  114. package/esm/socket/controller.js.map +1 -1
  115. package/{dts → esm}/socket/dispatcher.d.ts +10 -23
  116. package/esm/socket/dispatcher.d.ts.map +1 -0
  117. package/esm/socket/dispatcher.js +148 -164
  118. package/esm/socket/dispatcher.js.map +1 -1
  119. package/esm/socket/index.d.ts +3 -0
  120. package/esm/socket/index.d.ts.map +1 -0
  121. package/esm/socket/index.js +2 -6
  122. package/esm/socket/index.js.map +1 -1
  123. package/esm/socket/socket.d.ts +34 -0
  124. package/esm/socket/socket.d.ts.map +1 -0
  125. package/esm/socket/socket.js +69 -14
  126. package/esm/socket/socket.js.map +1 -1
  127. package/esm/stream/buffered.d.ts +35 -0
  128. package/esm/stream/buffered.d.ts.map +1 -0
  129. package/esm/stream/buffered.js +123 -0
  130. package/esm/stream/buffered.js.map +1 -0
  131. package/esm/stream/detect.bak.d.ts +240 -0
  132. package/esm/stream/detect.bak.d.ts.map +1 -0
  133. package/esm/stream/detect.bak.js +60 -0
  134. package/esm/stream/detect.bak.js.map +1 -0
  135. package/esm/stream/detect.d.ts +18 -0
  136. package/esm/stream/detect.d.ts.map +1 -0
  137. package/esm/stream/detect.js +6 -0
  138. package/esm/stream/detect.js.map +1 -0
  139. package/esm/stream/detect.native.d.ts +240 -0
  140. package/esm/stream/detect.native.d.ts.map +1 -0
  141. package/esm/stream/detect.native.js +60 -0
  142. package/esm/stream/detect.native.js.map +1 -0
  143. package/esm/stream/detect.polyfill.d.ts +18 -0
  144. package/esm/stream/detect.polyfill.d.ts.map +1 -0
  145. package/esm/stream/detect.polyfill.js +6 -0
  146. package/esm/stream/detect.polyfill.js.map +1 -0
  147. package/esm/stream/index.d.ts +4 -0
  148. package/esm/stream/index.d.ts.map +1 -0
  149. package/esm/stream/index.js +3 -2
  150. package/esm/stream/index.js.map +1 -1
  151. package/esm/stream/transform.d.ts +98 -0
  152. package/esm/stream/transform.d.ts.map +1 -0
  153. package/esm/stream/transform.js +352 -0
  154. package/esm/stream/transform.js.map +1 -0
  155. package/{dts → esm}/utils/auto-reset-event.d.ts +1 -1
  156. package/esm/utils/auto-reset-event.d.ts.map +1 -0
  157. package/esm/utils/auto-reset-event.js +2 -1
  158. package/esm/utils/auto-reset-event.js.map +1 -1
  159. package/esm/utils/base64.d.ts +5 -0
  160. package/esm/utils/base64.d.ts.map +1 -0
  161. package/esm/utils/base64.js +116 -80
  162. package/esm/utils/base64.js.map +1 -1
  163. package/esm/utils/encoding.d.ts +3 -0
  164. package/{dts → esm}/utils/encoding.d.ts.map +1 -1
  165. package/esm/utils/encoding.js +1 -1
  166. package/esm/utils/encoding.js.map +1 -1
  167. package/esm/utils/index.d.ts +4 -0
  168. package/esm/utils/index.d.ts.map +1 -0
  169. package/esm/utils/index.js +3 -5
  170. package/esm/utils/index.js.map +1 -1
  171. package/package.json +50 -44
  172. package/src/adb.ts +147 -143
  173. package/src/auth.ts +23 -19
  174. package/src/backend.ts +3 -12
  175. package/src/commands/base.ts +1 -1
  176. package/src/commands/framebuffer.ts +4 -4
  177. package/src/commands/index.ts +8 -8
  178. package/src/commands/install.ts +26 -15
  179. package/src/commands/power.ts +54 -0
  180. package/src/commands/reverse.ts +10 -8
  181. package/src/commands/subprocess/index.ts +124 -0
  182. package/src/commands/subprocess/legacy.ts +58 -0
  183. package/src/commands/subprocess/protocol.ts +185 -0
  184. package/src/commands/subprocess/types.ts +55 -0
  185. package/src/commands/{shell → subprocess}/utils.ts +0 -0
  186. package/src/commands/sync/index.ts +7 -7
  187. package/src/commands/sync/list.ts +7 -6
  188. package/src/commands/sync/pull.ts +27 -18
  189. package/src/commands/sync/push.ts +25 -30
  190. package/src/commands/sync/request.ts +7 -7
  191. package/src/commands/sync/response.ts +4 -4
  192. package/src/commands/sync/stat.ts +8 -6
  193. package/src/commands/sync/sync.ts +64 -32
  194. package/src/commands/tcpip.ts +3 -3
  195. package/src/crypto.ts +38 -43
  196. package/src/index.ts +11 -10
  197. package/src/packet.ts +37 -52
  198. package/src/socket/dispatcher.ts +90 -103
  199. package/src/socket/index.ts +2 -6
  200. package/src/socket/socket.ts +117 -16
  201. package/src/stream/buffered.ts +147 -0
  202. package/src/stream/detect.native.ts +362 -0
  203. package/src/stream/detect.polyfill.ts +25 -0
  204. package/src/stream/detect.ts +25 -0
  205. package/src/stream/index.ts +3 -2
  206. package/src/stream/transform.ts +427 -0
  207. package/src/utils/auto-reset-event.ts +1 -1
  208. package/src/utils/base64.ts +161 -129
  209. package/src/utils/encoding.ts +3 -3
  210. package/src/utils/index.ts +3 -5
  211. package/tsconfig.build.json +3 -0
  212. package/tsconfig.build.tsbuildinfo +1 -0
  213. package/tsconfig.test.json +10 -0
  214. package/dts/adb.d.ts +0 -46
  215. package/dts/adb.d.ts.map +0 -1
  216. package/dts/auth.d.ts.map +0 -1
  217. package/dts/backend.d.ts +0 -13
  218. package/dts/backend.d.ts.map +0 -1
  219. package/dts/commands/base.d.ts.map +0 -1
  220. package/dts/commands/demo-mode.d.ts +0 -41
  221. package/dts/commands/demo-mode.d.ts.map +0 -1
  222. package/dts/commands/framebuffer.d.ts.map +0 -1
  223. package/dts/commands/index.d.ts +0 -9
  224. package/dts/commands/index.d.ts.map +0 -1
  225. package/dts/commands/install.d.ts +0 -3
  226. package/dts/commands/install.d.ts.map +0 -1
  227. package/dts/commands/reverse.d.ts.map +0 -1
  228. package/dts/commands/shell/index.d.ts +0 -46
  229. package/dts/commands/shell/index.d.ts.map +0 -1
  230. package/dts/commands/shell/legacy.d.ts +0 -38
  231. package/dts/commands/shell/legacy.d.ts.map +0 -1
  232. package/dts/commands/shell/protocol.d.ts +0 -45
  233. package/dts/commands/shell/protocol.d.ts.map +0 -1
  234. package/dts/commands/shell/types.d.ts +0 -47
  235. package/dts/commands/shell/types.d.ts.map +0 -1
  236. package/dts/commands/shell/utils.d.ts.map +0 -1
  237. package/dts/commands/sync/index.d.ts +0 -8
  238. package/dts/commands/sync/index.d.ts.map +0 -1
  239. package/dts/commands/sync/list.d.ts.map +0 -1
  240. package/dts/commands/sync/pull.d.ts +0 -11
  241. package/dts/commands/sync/pull.d.ts.map +0 -1
  242. package/dts/commands/sync/push.d.ts +0 -8
  243. package/dts/commands/sync/push.d.ts.map +0 -1
  244. package/dts/commands/sync/request.d.ts.map +0 -1
  245. package/dts/commands/sync/response.d.ts.map +0 -1
  246. package/dts/commands/sync/stat.d.ts.map +0 -1
  247. package/dts/commands/sync/sync.d.ts +0 -68
  248. package/dts/commands/sync/sync.d.ts.map +0 -1
  249. package/dts/crypto.d.ts.map +0 -1
  250. package/dts/index.d.ts +0 -11
  251. package/dts/index.d.ts.map +0 -1
  252. package/dts/packet.d.ts +0 -27
  253. package/dts/packet.d.ts.map +0 -1
  254. package/dts/socket/close-event-emitter.d.ts +0 -8
  255. package/dts/socket/close-event-emitter.d.ts.map +0 -1
  256. package/dts/socket/controller.d.ts +0 -43
  257. package/dts/socket/controller.d.ts.map +0 -1
  258. package/dts/socket/data-event-emitter.d.ts +0 -10
  259. package/dts/socket/data-event-emitter.d.ts.map +0 -1
  260. package/dts/socket/dispatcher.d.ts.map +0 -1
  261. package/dts/socket/index.d.ts +0 -7
  262. package/dts/socket/index.d.ts.map +0 -1
  263. package/dts/socket/logger.d.ts +0 -9
  264. package/dts/socket/logger.d.ts.map +0 -1
  265. package/dts/socket/socket.d.ts +0 -22
  266. package/dts/socket/socket.d.ts.map +0 -1
  267. package/dts/stream/buffered-stream.d.ts +0 -28
  268. package/dts/stream/buffered-stream.d.ts.map +0 -1
  269. package/dts/stream/index.d.ts +0 -3
  270. package/dts/stream/index.d.ts.map +0 -1
  271. package/dts/stream/stream.d.ts +0 -15
  272. package/dts/stream/stream.d.ts.map +0 -1
  273. package/dts/utils/auto-reset-event.d.ts.map +0 -1
  274. package/dts/utils/base64.d.ts +0 -7
  275. package/dts/utils/base64.d.ts.map +0 -1
  276. package/dts/utils/chunk.d.ts +0 -3
  277. package/dts/utils/chunk.d.ts.map +0 -1
  278. package/dts/utils/encoding.d.ts +0 -3
  279. package/dts/utils/event-queue.d.ts +0 -35
  280. package/dts/utils/event-queue.d.ts.map +0 -1
  281. package/dts/utils/index.d.ts +0 -6
  282. package/dts/utils/index.d.ts.map +0 -1
  283. package/esm/commands/demo-mode.js +0 -170
  284. package/esm/commands/demo-mode.js.map +0 -1
  285. package/esm/commands/shell/index.js +0 -62
  286. package/esm/commands/shell/index.js.map +0 -1
  287. package/esm/commands/shell/legacy.js +0 -49
  288. package/esm/commands/shell/legacy.js.map +0 -1
  289. package/esm/commands/shell/protocol.js +0 -106
  290. package/esm/commands/shell/protocol.js.map +0 -1
  291. package/esm/commands/shell/utils.js.map +0 -1
  292. package/esm/socket/close-event-emitter.js +0 -28
  293. package/esm/socket/close-event-emitter.js.map +0 -1
  294. package/esm/socket/data-event-emitter.js +0 -25
  295. package/esm/socket/data-event-emitter.js.map +0 -1
  296. package/esm/socket/logger.js +0 -2
  297. package/esm/socket/logger.js.map +0 -1
  298. package/esm/stream/buffered-stream.js +0 -67
  299. package/esm/stream/buffered-stream.js.map +0 -1
  300. package/esm/stream/stream.js +0 -41
  301. package/esm/stream/stream.js.map +0 -1
  302. package/esm/utils/chunk.js +0 -70
  303. package/esm/utils/chunk.js.map +0 -1
  304. package/esm/utils/event-queue.js +0 -104
  305. package/esm/utils/event-queue.js.map +0 -1
  306. package/src/commands/demo-mode.ts +0 -160
  307. package/src/commands/shell/index.ts +0 -87
  308. package/src/commands/shell/legacy.ts +0 -59
  309. package/src/commands/shell/protocol.ts +0 -121
  310. package/src/commands/shell/types.ts +0 -55
  311. package/src/socket/close-event-emitter.ts +0 -28
  312. package/src/socket/controller.ts +0 -105
  313. package/src/socket/data-event-emitter.ts +0 -27
  314. package/src/socket/logger.ts +0 -12
  315. package/src/stream/buffered-stream.ts +0 -92
  316. package/src/stream/stream.ts +0 -50
  317. package/src/utils/chunk.ts +0 -70
  318. package/src/utils/event-queue.ts +0 -145
package/src/adb.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import { PromiseResolver } from '@yume-chan/async';
2
- import { DisposableList } from '@yume-chan/event';
3
- import { AdbAuthenticationHandler, AdbCredentialStore, AdbDefaultAuthenticators } from './auth';
4
- import { AdbBackend } from './backend';
5
- import { AdbChildProcess, AdbDemoMode, AdbFrameBuffer, AdbReverseCommand, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install } from './commands';
6
- import { AdbFeatures } from './features';
7
- import { AdbCommand } from './packet';
8
- import { AdbLogger, AdbPacketDispatcher, AdbSocket } from './socket';
9
- import { decodeUtf8 } from "./utils";
2
+ import { AdbAuthenticationHandler, AdbDefaultAuthenticators, type AdbCredentialStore } from './auth.js';
3
+ import { AdbPower, AdbReverseCommand, AdbSubprocess, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install, type AdbFrameBuffer } from './commands/index.js';
4
+ import { AdbFeatures } from './features.js';
5
+ import { AdbCommand, AdbPacket, calculateChecksum, type AdbPacketCore, type AdbPacketInit } from './packet.js';
6
+ import { AdbPacketDispatcher, AdbSocket } from './socket/index.js';
7
+ import { AbortController, DecodeUtf8Stream, GatherStringStream, WritableStream, type ReadableWritablePair } from "./stream/index.js";
8
+ import { decodeUtf8, encodeUtf8 } from "./utils/index.js";
10
9
 
11
10
  export enum AdbPropKey {
12
11
  Product = 'ro.product.name',
@@ -15,68 +14,21 @@ export enum AdbPropKey {
15
14
  Features = 'features',
16
15
  }
17
16
 
18
- export class Adb {
19
- private readonly _backend: AdbBackend;
20
-
21
- public get backend(): AdbBackend { return this._backend; }
22
-
23
- private readonly packetDispatcher: AdbPacketDispatcher;
24
-
25
- public get onDisconnected() { return this.backend.onDisconnected; }
26
-
27
- private _connected = false;
28
- public get connected() { return this._connected; }
29
-
30
- public get name() { return this.backend.name; }
31
-
32
- private _protocolVersion: number | undefined;
33
- public get protocolVersion() { return this._protocolVersion; }
34
-
35
- private _product: string | undefined;
36
- public get product() { return this._product; }
37
-
38
- private _model: string | undefined;
39
- public get model() { return this._model; }
40
-
41
- private _device: string | undefined;
42
- public get device() { return this._device; }
43
-
44
- private _features: AdbFeatures[] | undefined;
45
- public get features() { return this._features; }
46
-
47
- public readonly tcpip: AdbTcpIpCommand;
48
-
49
- public readonly reverse: AdbReverseCommand;
50
-
51
- public readonly demoMode: AdbDemoMode;
52
-
53
- public readonly childProcess: AdbChildProcess;
54
-
55
- public constructor(backend: AdbBackend, logger?: AdbLogger) {
56
- this._backend = backend;
57
- this.packetDispatcher = new AdbPacketDispatcher(backend, logger);
58
-
59
- this.tcpip = new AdbTcpIpCommand(this);
60
- this.reverse = new AdbReverseCommand(this.packetDispatcher);
61
- this.demoMode = new AdbDemoMode(this);
62
- this.childProcess = new AdbChildProcess(this);
17
+ export const VERSION_OMIT_CHECKSUM = 0x01000001;
63
18
 
64
- backend.onDisconnected(this.dispose, this);
65
- }
66
-
67
- public async connect(
19
+ export class Adb {
20
+ /**
21
+ * It's possible to call `authenticate` multiple times on a single connection,
22
+ * every time the device receives a `CNXN` packet, it resets its internal state,
23
+ * and starts a new authentication process.
24
+ */
25
+ public static async authenticate(
26
+ connection: ReadableWritablePair<AdbPacketCore, AdbPacketCore>,
68
27
  credentialStore: AdbCredentialStore,
69
- authenticators = AdbDefaultAuthenticators
70
- ): Promise<void> {
71
- await this.backend.connect?.();
72
- this.packetDispatcher.maxPayloadSize = 0x1000;
73
- this.packetDispatcher.calculateChecksum = true;
74
- this.packetDispatcher.appendNullToServiceString = true;
75
- this.packetDispatcher.start();
76
-
77
- const version = 0x01000001;
78
- const versionNoChecksum = 0x01000001;
79
- const maxPayloadSize = 0x100000;
28
+ authenticators = AdbDefaultAuthenticators,
29
+ ): Promise<Adb> {
30
+ let version = 0x01000001;
31
+ let maxPayloadSize = 0x100000;
80
32
 
81
33
  const features = [
82
34
  'shell_v2',
@@ -97,76 +49,129 @@ export class Adb {
97
49
  'sendrecv_v2_dry_run_send',
98
50
  ].join(',');
99
51
 
100
- const resolver = new PromiseResolver<void>();
52
+ const resolver = new PromiseResolver<string>();
101
53
  const authHandler = new AdbAuthenticationHandler(authenticators, credentialStore);
102
- const disposableList = new DisposableList();
103
- disposableList.add(this.packetDispatcher.onPacket(async (e) => {
104
- e.handled = true;
105
-
106
- const { packet } = e;
107
- try {
108
- switch (packet.command) {
109
- case AdbCommand.Connect:
110
- this.packetDispatcher.maxPayloadSize = Math.min(maxPayloadSize, packet.arg1);
111
-
112
- const finalVersion = Math.min(version, packet.arg0);
113
- this._protocolVersion = finalVersion;
114
-
115
- if (finalVersion >= versionNoChecksum) {
116
- this.packetDispatcher.calculateChecksum = false;
117
- // Android prior to 9.0.0 uses char* to parse service string
118
- // thus requires an extra null character
119
- this.packetDispatcher.appendNullToServiceString = false;
120
- }
121
-
122
- this.parseBanner(decodeUtf8(packet.payload!));
123
- resolver.resolve();
124
- break;
125
- case AdbCommand.Auth:
126
- const authPacket = await authHandler.handle(e.packet);
127
- await this.packetDispatcher.sendPacket(authPacket);
128
- break;
129
- case AdbCommand.Close:
130
- // Last connection was interrupted
131
- // Ignore this packet, device will recover
132
- break;
133
- default:
134
- throw new Error('Device not in correct state. Reconnect your device and try again');
54
+
55
+ const abortController = new AbortController();
56
+ const pipe = connection.readable
57
+ .pipeTo(new WritableStream({
58
+ async write(packet: AdbPacket) {
59
+ switch (packet.command) {
60
+ case AdbCommand.Connect:
61
+ version = Math.min(version, packet.arg0);
62
+ maxPayloadSize = Math.min(maxPayloadSize, packet.arg1);
63
+ resolver.resolve(decodeUtf8(packet.payload));
64
+ break;
65
+ case AdbCommand.Auth:
66
+ const response = await authHandler.handle(packet);
67
+ await sendPacket(response);
68
+ break;
69
+ case AdbCommand.Close:
70
+ // Last connection was interrupted
71
+ // Ignore this packet, device will recover
72
+ break;
73
+ default:
74
+ throw new Error('Device not in correct state. Reconnect your device and try again');
75
+ }
135
76
  }
136
- } catch (e) {
137
- resolver.reject(e);
138
- }
139
- }));
140
-
141
- disposableList.add(this.packetDispatcher.onError(e => {
142
- resolver.reject(e);
143
- }));
144
-
145
- // Android prior 9.0.0 requires the null character
146
- // Newer versions can also handle the null character
147
- // The terminating `;` is required in formal definition
148
- // But ADB daemon can also work without it
149
- await this.packetDispatcher.sendPacket(
150
- AdbCommand.Connect,
151
- version,
152
- maxPayloadSize,
153
- `host::features=${features};\0`
154
- );
77
+ }), {
78
+ preventCancel: true,
79
+ signal: abortController.signal,
80
+ })
81
+ .catch((e) => { resolver.reject(e); });
82
+
83
+ const writer = connection.writable.getWriter();
84
+ async function sendPacket(init: AdbPacketCore) {
85
+ // Always send checksum in auth steps
86
+ // Because we don't know if the device will ignore it yet.
87
+ await writer.write(calculateChecksum(init));
88
+ }
89
+
90
+ await sendPacket({
91
+ command: AdbCommand.Connect,
92
+ arg0: version,
93
+ arg1: maxPayloadSize,
94
+ // The terminating `;` is required in formal definition
95
+ // But ADB daemon (all versions) can still work without it
96
+ payload: encodeUtf8(`host::features=${features};`),
97
+ });
155
98
 
156
99
  try {
157
- await resolver.promise;
158
- this._connected = true;
100
+ const banner = await resolver.promise;
101
+
102
+ // Stop piping before creating Adb object
103
+ // Because AdbPacketDispatcher will try to lock the streams when initializing
104
+ abortController.abort();
105
+ await pipe;
106
+
107
+ writer.releaseLock();
108
+
109
+ return new Adb(
110
+ connection,
111
+ version,
112
+ maxPayloadSize,
113
+ banner,
114
+ );
159
115
  } finally {
160
- disposableList.dispose();
116
+ abortController.abort();
117
+ writer.releaseLock();
161
118
  }
162
119
  }
163
120
 
121
+ private readonly packetDispatcher: AdbPacketDispatcher;
122
+
123
+ public get disconnected() { return this.packetDispatcher.disconnected; }
124
+
125
+ private _protocolVersion: number | undefined;
126
+ public get protocolVersion() { return this._protocolVersion; }
127
+
128
+ private _product: string | undefined;
129
+ public get product() { return this._product; }
130
+
131
+ private _model: string | undefined;
132
+ public get model() { return this._model; }
133
+
134
+ private _device: string | undefined;
135
+ public get device() { return this._device; }
136
+
137
+ private _features: AdbFeatures[] | undefined;
138
+ public get features() { return this._features; }
139
+
140
+ public readonly subprocess: AdbSubprocess;
141
+ public readonly power: AdbPower;
142
+ public readonly reverse: AdbReverseCommand;
143
+ public readonly tcpip: AdbTcpIpCommand;
144
+
145
+ public constructor(
146
+ connection: ReadableWritablePair<AdbPacketCore, AdbPacketInit>,
147
+ version: number,
148
+ maxPayloadSize: number,
149
+ banner: string,
150
+ ) {
151
+ this.parseBanner(banner);
152
+ this.packetDispatcher = new AdbPacketDispatcher(connection);
153
+
154
+ this._protocolVersion = version;
155
+ if (version >= VERSION_OMIT_CHECKSUM) {
156
+ this.packetDispatcher.calculateChecksum = false;
157
+ // Android prior to 9.0.0 uses char* to parse service string
158
+ // thus requires an extra null character
159
+ this.packetDispatcher.appendNullToServiceString = false;
160
+ }
161
+ this.packetDispatcher.maxPayloadSize = maxPayloadSize;
162
+
163
+ this.subprocess = new AdbSubprocess(this);
164
+ this.power = new AdbPower(this);
165
+ this.reverse = new AdbReverseCommand(this.packetDispatcher);
166
+ this.tcpip = new AdbTcpIpCommand(this);
167
+ }
168
+
164
169
  private parseBanner(banner: string): void {
165
170
  this._features = [];
166
171
 
167
172
  const pieces = banner.split('::');
168
173
  if (pieces.length > 1) {
169
- const props = pieces[1];
174
+ const props = pieces[1]!;
170
175
  for (const prop of props.split(';')) {
171
176
  if (!prop) {
172
177
  continue;
@@ -189,7 +194,7 @@ export class Adb {
189
194
  this._device = value;
190
195
  break;
191
196
  case AdbPropKey.Features:
192
- this._features = value.split(',') as AdbFeatures[];
197
+ this._features = value!.split(',') as AdbFeatures[];
193
198
  break;
194
199
  }
195
200
  }
@@ -197,19 +202,21 @@ export class Adb {
197
202
  }
198
203
 
199
204
  public async getProp(key: string): Promise<string> {
200
- const output = await this.childProcess.exec('getprop', key);
201
- return output.trim();
205
+ const stdout = await this.subprocess.spawnAndWaitLegacy(
206
+ ['getprop', key]
207
+ );
208
+ return stdout.trim();
202
209
  }
203
210
 
204
211
  public async rm(...filenames: string[]): Promise<string> {
205
- return await this.childProcess.exec('rm', '-rf', ...filenames.map(arg => escapeArg(arg)));
212
+ const stdout = await this.subprocess.spawnAndWaitLegacy(
213
+ ['rm', '-rf', ...filenames.map(arg => escapeArg(arg))],
214
+ );
215
+ return stdout;
206
216
  }
207
217
 
208
- public async install(
209
- apk: ArrayLike<number> | ArrayBufferLike | AsyncIterable<ArrayBuffer>,
210
- onProgress?: (uploaded: number) => void,
211
- ): Promise<void> {
212
- return await install(this, apk, onProgress);
218
+ public install() {
219
+ return install(this);
213
220
  }
214
221
 
215
222
  public async sync(): Promise<AdbSync> {
@@ -225,19 +232,16 @@ export class Adb {
225
232
  return this.packetDispatcher.createSocket(service);
226
233
  }
227
234
 
228
- public async createSocketAndReadAll(service: string): Promise<string> {
235
+ public async createSocketAndWait(service: string): Promise<string> {
229
236
  const socket = await this.createSocket(service);
230
- const resolver = new PromiseResolver<string>();
231
- let result = '';
232
- socket.onData(buffer => {
233
- result += decodeUtf8(buffer);
234
- });
235
- socket.onClose(() => resolver.resolve(result));
236
- return resolver.promise;
237
+ const gatherStream = new GatherStringStream();
238
+ await socket.readable
239
+ .pipeThrough(new DecodeUtf8Stream())
240
+ .pipeTo(gatherStream.writable);
241
+ return gatherStream.result;
237
242
  }
238
243
 
239
244
  public async dispose(): Promise<void> {
240
245
  this.packetDispatcher.dispose();
241
- await this.backend.dispose();
242
246
  }
243
247
  }
package/src/auth.ts CHANGED
@@ -1,19 +1,19 @@
1
1
  import { PromiseResolver } from '@yume-chan/async';
2
- import { Disposable } from '@yume-chan/event';
3
- import { ValueOrPromise } from '@yume-chan/struct';
4
- import { calculatePublicKey, calculatePublicKeyLength, sign } from './crypto';
5
- import { AdbCommand, AdbPacket, AdbPacketInit } from './packet';
6
- import { calculateBase64EncodedLength, encodeBase64 } from './utils';
2
+ import type { Disposable } from '@yume-chan/event';
3
+ import type { ValueOrPromise } from '@yume-chan/struct';
4
+ import { calculatePublicKey, calculatePublicKeyLength, sign } from './crypto.js';
5
+ import { AdbCommand, AdbPacket, type AdbPacketCore } from './packet.js';
6
+ import { calculateBase64EncodedLength, encodeBase64 } from './utils/index.js';
7
7
 
8
- export type AdbKeyIterable = Iterable<ArrayBuffer> | AsyncIterable<ArrayBuffer>;
8
+ export type AdbKeyIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
9
9
 
10
10
  export interface AdbCredentialStore {
11
11
  /**
12
12
  * Generate and store a RSA private key with modulus length `2048` and public exponent `65537`.
13
13
  *
14
- * The returned `ArrayBuffer` is the private key in PKCS #8 format.
14
+ * The returned `Uint8Array` is the private key in PKCS #8 format.
15
15
  */
16
- generateKey(): ValueOrPromise<ArrayBuffer>;
16
+ generateKey(): ValueOrPromise<Uint8Array>;
17
17
 
18
18
  /**
19
19
  * Synchronously or asynchronously iterate through all stored RSA private keys.
@@ -44,13 +44,13 @@ export interface AdbAuthenticator {
44
44
  (
45
45
  credentialStore: AdbCredentialStore,
46
46
  getNextRequest: () => Promise<AdbPacket>
47
- ): AsyncIterable<AdbPacketInit>;
47
+ ): AsyncIterable<AdbPacketCore>;
48
48
  }
49
49
 
50
50
  export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
51
51
  credentialStore: AdbCredentialStore,
52
52
  getNextRequest: () => Promise<AdbPacket>,
53
- ): AsyncIterable<AdbPacketInit> {
53
+ ): AsyncIterable<AdbPacketCore> {
54
54
  for await (const key of credentialStore.iterateKeys()) {
55
55
  const packet = await getNextRequest();
56
56
 
@@ -58,12 +58,12 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
58
58
  return;
59
59
  }
60
60
 
61
- const signature = sign(key, packet.payload!);
61
+ const signature = sign(key, packet.payload);
62
62
  yield {
63
63
  command: AdbCommand.Auth,
64
64
  arg0: AdbAuthType.Signature,
65
65
  arg1: 0,
66
- payload: signature,
66
+ payload: new Uint8Array(signature),
67
67
  };
68
68
  }
69
69
  };
@@ -71,19 +71,20 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
71
71
  export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
72
72
  credentialStore: AdbCredentialStore,
73
73
  getNextRequest: () => Promise<AdbPacket>,
74
- ): AsyncIterable<AdbPacketInit> {
74
+ ): AsyncIterable<AdbPacketCore> {
75
75
  const packet = await getNextRequest();
76
76
 
77
77
  if (packet.arg0 !== AdbAuthType.Token) {
78
78
  return;
79
79
  }
80
80
 
81
- let privateKey: ArrayBuffer | undefined;
81
+ let privateKey: Uint8Array | undefined;
82
82
  for await (const key of credentialStore.iterateKeys()) {
83
83
  privateKey = key;
84
84
  break;
85
85
  }
86
86
 
87
+
87
88
  if (!privateKey) {
88
89
  privateKey = await credentialStore.generateKey();
89
90
  }
@@ -93,10 +94,13 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
93
94
 
94
95
  // The public key is null terminated,
95
96
  // So we allocate the buffer with one extra byte.
96
- const publicKeyBuffer = new ArrayBuffer(publicKeyBase64Length + 1);
97
+ const publicKeyBuffer = new Uint8Array(publicKeyBase64Length + 1);
97
98
 
98
99
  calculatePublicKey(privateKey, publicKeyBuffer);
99
- encodeBase64(publicKeyBuffer, 0, publicKeyLength, publicKeyBuffer);
100
+ encodeBase64(
101
+ publicKeyBuffer.subarray(0, publicKeyLength),
102
+ publicKeyBuffer
103
+ );
100
104
 
101
105
  yield {
102
106
  command: AdbCommand.Auth,
@@ -118,7 +122,7 @@ export class AdbAuthenticationHandler implements Disposable {
118
122
 
119
123
  private pendingRequest = new PromiseResolver<AdbPacket>();
120
124
 
121
- private iterator: AsyncIterator<AdbPacketInit> | undefined;
125
+ private iterator: AsyncIterator<AdbPacketCore> | undefined;
122
126
 
123
127
  public constructor(
124
128
  authenticators: readonly AdbAuthenticator[],
@@ -132,7 +136,7 @@ export class AdbAuthenticationHandler implements Disposable {
132
136
  return this.pendingRequest.promise;
133
137
  };
134
138
 
135
- private async* runAuthenticator(): AsyncGenerator<AdbPacketInit> {
139
+ private async* runAuthenticator(): AsyncGenerator<AdbPacketCore> {
136
140
  for (const authenticator of this.authenticators) {
137
141
  for await (const packet of authenticator(this.credentialStore, this.getNextRequest)) {
138
142
  // If the authenticator yielded a response
@@ -150,7 +154,7 @@ export class AdbAuthenticationHandler implements Disposable {
150
154
  throw new Error('Cannot authenticate with device');
151
155
  }
152
156
 
153
- public async handle(packet: AdbPacket): Promise<AdbPacketInit> {
157
+ public async handle(packet: AdbPacket): Promise<AdbPacketCore> {
154
158
  if (!this.iterator) {
155
159
  this.iterator = this.runAuthenticator();
156
160
  }
package/src/backend.ts CHANGED
@@ -1,20 +1,11 @@
1
- import type { Event } from '@yume-chan/event';
2
1
  import type { ValueOrPromise } from '@yume-chan/struct';
2
+ import type { AdbPacketCore, AdbPacketInit } from "./packet.js";
3
+ import type { ReadableWritablePair } from "./stream/index.js";
3
4
 
4
5
  export interface AdbBackend {
5
6
  readonly serial: string;
6
7
 
7
8
  readonly name: string | undefined;
8
9
 
9
- readonly connected: boolean;
10
-
11
- readonly onDisconnected: Event<void>;
12
-
13
- connect?(): ValueOrPromise<void>;
14
-
15
- read(length: number): ValueOrPromise<ArrayBuffer>;
16
-
17
- write(buffer: ArrayBuffer): ValueOrPromise<void>;
18
-
19
- dispose(): ValueOrPromise<void>;
10
+ connect(): ValueOrPromise<ReadableWritablePair<AdbPacketCore, AdbPacketInit>>;
20
11
  }
@@ -1,5 +1,5 @@
1
1
  import { AutoDisposable } from '@yume-chan/event';
2
- import { Adb } from '../adb';
2
+ import type { Adb } from '../adb.js';
3
3
 
4
4
  export class AdbCommandBase extends AutoDisposable {
5
5
  protected adb: Adb;
@@ -1,6 +1,6 @@
1
1
  import Struct from "@yume-chan/struct";
2
- import { Adb } from '../adb';
3
- import { AdbBufferedStream } from '../stream';
2
+ import type { Adb } from '../adb.js';
3
+ import { AdbBufferedStream } from '../stream/index.js';
4
4
 
5
5
  const Version =
6
6
  new Struct({ littleEndian: true })
@@ -33,7 +33,7 @@ export const AdbFrameBufferV1 =
33
33
  .uint32('green_length')
34
34
  .uint32('alpha_offset')
35
35
  .uint32('alpha_length')
36
- .uint8ClampedArray('data', { lengthField: 'size' });
36
+ .uint8Array('data', { lengthField: 'size' });
37
37
 
38
38
  export type AdbFrameBufferV1 = typeof AdbFrameBufferV1['TDeserializeResult'];
39
39
 
@@ -52,7 +52,7 @@ export const AdbFrameBufferV2 =
52
52
  .uint32('green_length')
53
53
  .uint32('alpha_offset')
54
54
  .uint32('alpha_length')
55
- .uint8ClampedArray('data', { lengthField: 'size' });
55
+ .uint8Array('data', { lengthField: 'size' });
56
56
 
57
57
  export type AdbFrameBufferV2 = typeof AdbFrameBufferV2['TDeserializeResult'];
58
58
 
@@ -1,8 +1,8 @@
1
- export * from './base';
2
- export * from './demo-mode';
3
- export * from './framebuffer';
4
- export * from './install';
5
- export * from './reverse';
6
- export * from './shell';
7
- export * from './sync';
8
- export * from './tcpip';
1
+ export * from './base.js';
2
+ export * from './framebuffer.js';
3
+ export * from './install.js';
4
+ export * from './power.js';
5
+ export * from './reverse.js';
6
+ export * from './subprocess/index.js';
7
+ export * from './sync/index.js';
8
+ export * from './tcpip.js';
@@ -1,21 +1,32 @@
1
- import { Adb } from "../adb";
2
- import { escapeArg } from "./shell";
1
+ import type { Adb } from "../adb.js";
2
+ import { WrapWritableStream, WritableStream } from "../stream/index.js";
3
+ import { escapeArg } from "./subprocess/index.js";
4
+ import type { AdbSync } from "./sync/index.js";
3
5
 
4
- export async function install(
6
+ export function install(
5
7
  adb: Adb,
6
- apk: ArrayLike<number> | ArrayBufferLike | AsyncIterable<ArrayBuffer>,
7
- onProgress?: (uploaded: number) => void,
8
- ): Promise<void> {
9
- const filename = `/data/local/tmp/${Math.random().toString().substr(2)}.apk`;
8
+ ): WritableStream<Uint8Array> {
9
+ const filename = `/data/local/tmp/${Math.random().toString().substring(2)}.apk`;
10
10
 
11
- // Upload apk file to tmp folder
12
- const sync = await adb.sync();
13
- await sync.write(filename, apk, undefined, undefined, onProgress);
14
- sync.dispose();
11
+ return new WrapWritableStream<Uint8Array, WritableStream<Uint8Array>, AdbSync>({
12
+ async start() {
13
+ // Upload apk file to tmp folder
14
+ const sync = await adb.sync();
15
+ const writable = sync.write(filename, undefined, undefined);
15
16
 
16
- // Invoke `pm install` to install it
17
- await adb.childProcess.exec('pm', 'install', escapeArg(filename));
17
+ return {
18
+ writable,
19
+ state: sync,
20
+ };
21
+ },
22
+ async close(sync) {
23
+ sync.dispose();
18
24
 
19
- // Remove the temp file
20
- await adb.rm(filename);
25
+ // Invoke `pm install` to install it
26
+ await adb.subprocess.spawnAndWaitLegacy(['pm', 'install', escapeArg(filename)]);
27
+
28
+ // Remove the temp file
29
+ await adb.rm(filename);
30
+ }
31
+ });
21
32
  }
@@ -0,0 +1,54 @@
1
+ // cspell: ignore bootloader
2
+ // cspell: ignore fastboot
3
+ // cspell: ignore keyevent
4
+ // cspell: ignore longpress
5
+
6
+ import { AdbCommandBase } from "./base.js";
7
+
8
+ export class AdbPower extends AdbCommandBase {
9
+ public reboot(name: string = '') {
10
+ return this.adb.createSocketAndWait(`reboot:${name}`);
11
+ }
12
+
13
+ public bootloader() {
14
+ return this.reboot('bootloader');
15
+ }
16
+
17
+ public fastboot() {
18
+ return this.reboot('fastboot');
19
+ }
20
+
21
+ public recovery() {
22
+ return this.reboot('recovery');
23
+ }
24
+
25
+ public sideload() {
26
+ return this.reboot('sideload');
27
+ }
28
+
29
+ /**
30
+ * Reboot to Qualcomm Emergency Download (EDL) Mode.
31
+ *
32
+ * Only works on some Qualcomm devices.
33
+ */
34
+ public qualcommEdlMode() {
35
+ return this.reboot('edl');
36
+ }
37
+
38
+ public powerOff() {
39
+ return this.adb.subprocess.spawnAndWaitLegacy(['reboot', '-p']);
40
+ }
41
+
42
+ public powerButton(longPress: boolean = false) {
43
+ return this.adb.subprocess.spawnAndWaitLegacy(['input', 'keyevent', longPress ? '--longpress POWER' : 'POWER']);
44
+ }
45
+
46
+ /**
47
+ * Reboot to Samsung Odin download mode.
48
+ *
49
+ * Only works on Samsung devices.
50
+ */
51
+ public samsungOdin() {
52
+ return this.reboot('download');
53
+ }
54
+ }