@yume-chan/adb 0.0.10 → 0.0.13

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 (342) hide show
  1. package/CHANGELOG.json +50 -0
  2. package/CHANGELOG.md +29 -1
  3. package/LICENSE +1 -1
  4. package/README.md +71 -51
  5. package/esm/adb.d.ts +48 -0
  6. package/esm/adb.d.ts.map +1 -0
  7. package/esm/adb.js +149 -136
  8. package/esm/adb.js.map +1 -1
  9. package/{dts → esm}/auth.d.ts +11 -11
  10. package/esm/auth.d.ts.map +1 -0
  11. package/esm/auth.js +72 -110
  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 +19 -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 +56 -0
  40. package/esm/commands/subprocess/index.d.ts.map +1 -0
  41. package/esm/commands/subprocess/index.js +88 -0
  42. package/esm/commands/subprocess/index.js.map +1 -0
  43. package/esm/commands/subprocess/legacy.d.ts +35 -0
  44. package/esm/commands/subprocess/legacy.d.ts.map +1 -0
  45. package/esm/commands/subprocess/legacy.js +53 -0
  46. package/esm/commands/subprocess/legacy.js.map +1 -0
  47. package/esm/commands/subprocess/protocol.d.ts +39 -0
  48. package/esm/commands/subprocess/protocol.d.ts.map +1 -0
  49. package/esm/commands/subprocess/protocol.js +157 -0
  50. package/esm/commands/subprocess/protocol.js.map +1 -0
  51. package/esm/commands/subprocess/protocols/index.d.ts +4 -0
  52. package/esm/commands/subprocess/protocols/index.d.ts.map +1 -0
  53. package/esm/commands/subprocess/protocols/index.js +4 -0
  54. package/esm/commands/subprocess/protocols/index.js.map +1 -0
  55. package/esm/commands/subprocess/protocols/none.d.ts +35 -0
  56. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -0
  57. package/esm/commands/subprocess/protocols/none.js +53 -0
  58. package/esm/commands/subprocess/protocols/none.js.map +1 -0
  59. package/esm/commands/subprocess/protocols/shell.d.ts +39 -0
  60. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -0
  61. package/esm/commands/subprocess/protocols/shell.js +155 -0
  62. package/esm/commands/subprocess/protocols/shell.js.map +1 -0
  63. package/esm/commands/subprocess/protocols/types.d.ts +50 -0
  64. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -0
  65. package/esm/commands/{shell → subprocess/protocols}/types.js +0 -0
  66. package/esm/commands/subprocess/protocols/types.js.map +1 -0
  67. package/esm/commands/subprocess/types.d.ts +50 -0
  68. package/esm/commands/subprocess/types.d.ts.map +1 -0
  69. package/esm/commands/subprocess/types.js +2 -0
  70. package/esm/commands/{shell → subprocess}/types.js.map +1 -1
  71. package/{dts/commands/shell → esm/commands/subprocess}/utils.d.ts +0 -0
  72. package/esm/commands/subprocess/utils.d.ts.map +1 -0
  73. package/esm/commands/{shell → subprocess}/utils.js +0 -0
  74. package/esm/commands/subprocess/utils.js.map +1 -0
  75. package/esm/commands/sync/index.d.ts +8 -0
  76. package/esm/commands/sync/index.d.ts.map +1 -0
  77. package/esm/commands/sync/index.js +7 -7
  78. package/esm/commands/sync/index.js.map +1 -1
  79. package/esm/commands/sync/list.d.ts +41 -0
  80. package/esm/commands/sync/list.d.ts.map +1 -0
  81. package/esm/commands/sync/list.js +52 -20
  82. package/esm/commands/sync/list.js.map +1 -1
  83. package/esm/commands/sync/pull.d.ts +11 -0
  84. package/esm/commands/sync/pull.d.ts.map +1 -0
  85. package/esm/commands/sync/pull.js +17 -11
  86. package/esm/commands/sync/pull.js.map +1 -1
  87. package/esm/commands/sync/push.d.ts +8 -0
  88. package/esm/commands/sync/push.d.ts.map +1 -0
  89. package/esm/commands/sync/push.js +19 -37
  90. package/esm/commands/sync/push.js.map +1 -1
  91. package/{dts → esm}/commands/sync/request.d.ts +4 -3
  92. package/esm/commands/sync/request.d.ts.map +1 -0
  93. package/esm/commands/sync/request.js +25 -27
  94. package/esm/commands/sync/request.js.map +1 -1
  95. package/{dts → esm}/commands/sync/response.d.ts +4 -3
  96. package/esm/commands/sync/response.d.ts.map +1 -0
  97. package/esm/commands/sync/response.js +17 -20
  98. package/esm/commands/sync/response.js.map +1 -1
  99. package/{dts → esm}/commands/sync/stat.d.ts +16 -4
  100. package/esm/commands/sync/stat.d.ts.map +1 -0
  101. package/esm/commands/sync/stat.js +38 -30
  102. package/esm/commands/sync/stat.js.map +1 -1
  103. package/esm/commands/sync/sync.d.ts +61 -0
  104. package/esm/commands/sync/sync.d.ts.map +1 -0
  105. package/esm/commands/sync/sync.js +122 -89
  106. package/esm/commands/sync/sync.js.map +1 -1
  107. package/{dts → esm}/commands/tcpip.d.ts +1 -1
  108. package/{dts → esm}/commands/tcpip.d.ts.map +1 -1
  109. package/esm/commands/tcpip.js +14 -19
  110. package/esm/commands/tcpip.js.map +1 -1
  111. package/esm/crypto.d.ts +37 -0
  112. package/esm/crypto.d.ts.map +1 -0
  113. package/esm/crypto.js +77 -62
  114. package/esm/crypto.js.map +1 -1
  115. package/esm/features.d.ts +8 -0
  116. package/esm/features.d.ts.map +1 -0
  117. package/esm/features.js +7 -3
  118. package/esm/features.js.map +1 -1
  119. package/esm/index.d.ts +11 -0
  120. package/esm/index.d.ts.map +1 -0
  121. package/esm/index.js +10 -10
  122. package/esm/index.js.map +1 -1
  123. package/esm/packet.d.ts +47 -0
  124. package/esm/packet.d.ts.map +1 -0
  125. package/esm/packet.js +27 -52
  126. package/esm/packet.js.map +1 -1
  127. package/esm/socket/controller.d.ts +37 -0
  128. package/esm/socket/controller.d.ts.map +1 -0
  129. package/esm/socket/controller.js +52 -66
  130. package/esm/socket/controller.js.map +1 -1
  131. package/esm/socket/dispatcher.d.ts +44 -0
  132. package/esm/socket/dispatcher.d.ts.map +1 -0
  133. package/esm/socket/dispatcher.js +146 -165
  134. package/esm/socket/dispatcher.js.map +1 -1
  135. package/esm/socket/index.d.ts +3 -0
  136. package/esm/socket/index.d.ts.map +1 -0
  137. package/esm/socket/index.js +2 -6
  138. package/esm/socket/index.js.map +1 -1
  139. package/esm/socket/socket.d.ts +46 -0
  140. package/esm/socket/socket.d.ts.map +1 -0
  141. package/esm/socket/socket.js +77 -13
  142. package/esm/socket/socket.js.map +1 -1
  143. package/esm/stream/buffered.d.ts +35 -0
  144. package/esm/stream/buffered.d.ts.map +1 -0
  145. package/esm/stream/buffered.js +123 -0
  146. package/esm/stream/buffered.js.map +1 -0
  147. package/esm/stream/detect.bak.d.ts +240 -0
  148. package/esm/stream/detect.bak.d.ts.map +1 -0
  149. package/esm/stream/detect.bak.js +60 -0
  150. package/esm/stream/detect.bak.js.map +1 -0
  151. package/esm/stream/detect.d.ts +2 -0
  152. package/esm/stream/detect.d.ts.map +1 -0
  153. package/esm/stream/detect.js +5 -0
  154. package/esm/stream/detect.js.map +1 -0
  155. package/esm/stream/detect.native.d.ts +240 -0
  156. package/esm/stream/detect.native.d.ts.map +1 -0
  157. package/esm/stream/detect.native.js +60 -0
  158. package/esm/stream/detect.native.js.map +1 -0
  159. package/esm/stream/detect.polyfill.d.ts +18 -0
  160. package/esm/stream/detect.polyfill.d.ts.map +1 -0
  161. package/esm/stream/detect.polyfill.js +9 -0
  162. package/esm/stream/detect.polyfill.js.map +1 -0
  163. package/esm/stream/index.d.ts +4 -0
  164. package/esm/stream/index.d.ts.map +1 -0
  165. package/esm/stream/index.js +3 -2
  166. package/esm/stream/index.js.map +1 -1
  167. package/esm/stream/transform.d.ts +98 -0
  168. package/esm/stream/transform.d.ts.map +1 -0
  169. package/esm/stream/transform.js +402 -0
  170. package/esm/stream/transform.js.map +1 -0
  171. package/{dts → esm}/utils/auto-reset-event.d.ts +1 -1
  172. package/esm/utils/auto-reset-event.d.ts.map +1 -0
  173. package/esm/utils/auto-reset-event.js +2 -1
  174. package/esm/utils/auto-reset-event.js.map +1 -1
  175. package/esm/utils/base64.d.ts +5 -0
  176. package/esm/utils/base64.d.ts.map +1 -0
  177. package/esm/utils/base64.js +116 -80
  178. package/esm/utils/base64.js.map +1 -1
  179. package/esm/utils/encoding.d.ts +3 -0
  180. package/esm/utils/encoding.d.ts.map +1 -0
  181. package/esm/utils/encoding.js +1 -1
  182. package/esm/utils/encoding.js.map +1 -1
  183. package/esm/utils/index.d.ts +4 -0
  184. package/esm/utils/index.d.ts.map +1 -0
  185. package/esm/utils/index.js +3 -5
  186. package/esm/utils/index.js.map +1 -1
  187. package/package.json +50 -44
  188. package/src/adb.ts +177 -150
  189. package/src/auth.ts +37 -30
  190. package/src/backend.ts +3 -12
  191. package/src/commands/base.ts +1 -1
  192. package/src/commands/framebuffer.ts +4 -4
  193. package/src/commands/index.ts +8 -8
  194. package/src/commands/install.ts +24 -15
  195. package/src/commands/power.ts +54 -0
  196. package/src/commands/reverse.ts +10 -8
  197. package/src/commands/subprocess/index.ts +139 -0
  198. package/src/commands/subprocess/protocols/index.ts +3 -0
  199. package/src/commands/subprocess/protocols/none.ts +68 -0
  200. package/src/commands/subprocess/protocols/shell.ts +190 -0
  201. package/src/commands/subprocess/protocols/types.ts +59 -0
  202. package/src/commands/{shell → subprocess}/utils.ts +0 -0
  203. package/src/commands/sync/index.ts +7 -7
  204. package/src/commands/sync/list.ts +56 -9
  205. package/src/commands/sync/pull.ts +27 -18
  206. package/src/commands/sync/push.ts +25 -30
  207. package/src/commands/sync/request.ts +8 -7
  208. package/src/commands/sync/response.ts +12 -6
  209. package/src/commands/sync/stat.ts +43 -14
  210. package/src/commands/sync/sync.ts +102 -34
  211. package/src/commands/tcpip.ts +3 -3
  212. package/src/crypto.ts +95 -84
  213. package/src/features.ts +6 -2
  214. package/src/index.ts +11 -10
  215. package/src/packet.ts +49 -53
  216. package/src/socket/dispatcher.ts +110 -109
  217. package/src/socket/index.ts +2 -6
  218. package/src/socket/socket.ts +125 -17
  219. package/src/stream/buffered.ts +147 -0
  220. package/src/stream/detect.native.ts +362 -0
  221. package/src/stream/detect.polyfill.ts +28 -0
  222. package/src/stream/detect.ts +5 -0
  223. package/src/stream/index.ts +3 -2
  224. package/src/stream/transform.ts +483 -0
  225. package/src/utils/auto-reset-event.ts +1 -1
  226. package/src/utils/base64.ts +161 -129
  227. package/src/utils/index.ts +3 -5
  228. package/tsconfig.build.json +3 -0
  229. package/tsconfig.build.tsbuildinfo +1 -0
  230. package/tsconfig.test.json +10 -0
  231. package/dts/adb.d.ts +0 -46
  232. package/dts/adb.d.ts.map +0 -1
  233. package/dts/auth.d.ts.map +0 -1
  234. package/dts/backend.d.ts +0 -13
  235. package/dts/backend.d.ts.map +0 -1
  236. package/dts/commands/base.d.ts.map +0 -1
  237. package/dts/commands/demo-mode.d.ts +0 -41
  238. package/dts/commands/demo-mode.d.ts.map +0 -1
  239. package/dts/commands/framebuffer.d.ts.map +0 -1
  240. package/dts/commands/index.d.ts +0 -9
  241. package/dts/commands/index.d.ts.map +0 -1
  242. package/dts/commands/install.d.ts +0 -3
  243. package/dts/commands/install.d.ts.map +0 -1
  244. package/dts/commands/reverse.d.ts.map +0 -1
  245. package/dts/commands/shell/index.d.ts +0 -46
  246. package/dts/commands/shell/index.d.ts.map +0 -1
  247. package/dts/commands/shell/legacy.d.ts +0 -38
  248. package/dts/commands/shell/legacy.d.ts.map +0 -1
  249. package/dts/commands/shell/protocol.d.ts +0 -45
  250. package/dts/commands/shell/protocol.d.ts.map +0 -1
  251. package/dts/commands/shell/types.d.ts +0 -47
  252. package/dts/commands/shell/types.d.ts.map +0 -1
  253. package/dts/commands/shell/utils.d.ts.map +0 -1
  254. package/dts/commands/sync/index.d.ts +0 -8
  255. package/dts/commands/sync/index.d.ts.map +0 -1
  256. package/dts/commands/sync/list.d.ts +0 -17
  257. package/dts/commands/sync/list.d.ts.map +0 -1
  258. package/dts/commands/sync/pull.d.ts +0 -11
  259. package/dts/commands/sync/pull.d.ts.map +0 -1
  260. package/dts/commands/sync/push.d.ts +0 -8
  261. package/dts/commands/sync/push.d.ts.map +0 -1
  262. package/dts/commands/sync/request.d.ts.map +0 -1
  263. package/dts/commands/sync/response.d.ts.map +0 -1
  264. package/dts/commands/sync/stat.d.ts.map +0 -1
  265. package/dts/commands/sync/sync.d.ts +0 -68
  266. package/dts/commands/sync/sync.d.ts.map +0 -1
  267. package/dts/crypto.d.ts +0 -24
  268. package/dts/crypto.d.ts.map +0 -1
  269. package/dts/features.d.ts +0 -6
  270. package/dts/features.d.ts.map +0 -1
  271. package/dts/index.d.ts +0 -11
  272. package/dts/index.d.ts.map +0 -1
  273. package/dts/packet.d.ts +0 -27
  274. package/dts/packet.d.ts.map +0 -1
  275. package/dts/socket/close-event-emitter.d.ts +0 -8
  276. package/dts/socket/close-event-emitter.d.ts.map +0 -1
  277. package/dts/socket/controller.d.ts +0 -43
  278. package/dts/socket/controller.d.ts.map +0 -1
  279. package/dts/socket/data-event-emitter.d.ts +0 -10
  280. package/dts/socket/data-event-emitter.d.ts.map +0 -1
  281. package/dts/socket/dispatcher.d.ts +0 -53
  282. package/dts/socket/dispatcher.d.ts.map +0 -1
  283. package/dts/socket/index.d.ts +0 -7
  284. package/dts/socket/index.d.ts.map +0 -1
  285. package/dts/socket/logger.d.ts +0 -9
  286. package/dts/socket/logger.d.ts.map +0 -1
  287. package/dts/socket/socket.d.ts +0 -22
  288. package/dts/socket/socket.d.ts.map +0 -1
  289. package/dts/stream/buffered-stream.d.ts +0 -28
  290. package/dts/stream/buffered-stream.d.ts.map +0 -1
  291. package/dts/stream/index.d.ts +0 -3
  292. package/dts/stream/index.d.ts.map +0 -1
  293. package/dts/stream/stream.d.ts +0 -15
  294. package/dts/stream/stream.d.ts.map +0 -1
  295. package/dts/utils/auto-reset-event.d.ts.map +0 -1
  296. package/dts/utils/base64.d.ts +0 -7
  297. package/dts/utils/base64.d.ts.map +0 -1
  298. package/dts/utils/chunk.d.ts +0 -3
  299. package/dts/utils/chunk.d.ts.map +0 -1
  300. package/dts/utils/encoding.d.ts +0 -3
  301. package/dts/utils/encoding.d.ts.map +0 -1
  302. package/dts/utils/event-queue.d.ts +0 -35
  303. package/dts/utils/event-queue.d.ts.map +0 -1
  304. package/dts/utils/index.d.ts +0 -6
  305. package/dts/utils/index.d.ts.map +0 -1
  306. package/esm/commands/demo-mode.js +0 -170
  307. package/esm/commands/demo-mode.js.map +0 -1
  308. package/esm/commands/shell/index.js +0 -62
  309. package/esm/commands/shell/index.js.map +0 -1
  310. package/esm/commands/shell/legacy.js +0 -49
  311. package/esm/commands/shell/legacy.js.map +0 -1
  312. package/esm/commands/shell/protocol.js +0 -106
  313. package/esm/commands/shell/protocol.js.map +0 -1
  314. package/esm/commands/shell/utils.js.map +0 -1
  315. package/esm/socket/close-event-emitter.js +0 -28
  316. package/esm/socket/close-event-emitter.js.map +0 -1
  317. package/esm/socket/data-event-emitter.js +0 -25
  318. package/esm/socket/data-event-emitter.js.map +0 -1
  319. package/esm/socket/logger.js +0 -2
  320. package/esm/socket/logger.js.map +0 -1
  321. package/esm/stream/buffered-stream.js +0 -67
  322. package/esm/stream/buffered-stream.js.map +0 -1
  323. package/esm/stream/stream.js +0 -41
  324. package/esm/stream/stream.js.map +0 -1
  325. package/esm/utils/chunk.js +0 -70
  326. package/esm/utils/chunk.js.map +0 -1
  327. package/esm/utils/event-queue.js +0 -104
  328. package/esm/utils/event-queue.js.map +0 -1
  329. package/src/commands/demo-mode.ts +0 -160
  330. package/src/commands/shell/index.ts +0 -87
  331. package/src/commands/shell/legacy.ts +0 -59
  332. package/src/commands/shell/protocol.ts +0 -121
  333. package/src/commands/shell/types.ts +0 -55
  334. package/src/socket/close-event-emitter.ts +0 -28
  335. package/src/socket/controller.ts +0 -105
  336. package/src/socket/data-event-emitter.ts +0 -27
  337. package/src/socket/logger.ts +0 -12
  338. package/src/stream/buffered-stream.ts +0 -92
  339. package/src/stream/stream.ts +0 -50
  340. package/src/utils/chunk.ts +0 -70
  341. package/src/utils/encoding.ts +0 -13
  342. package/src/utils/event-queue.ts +0 -145
@@ -1,8 +1,12 @@
1
1
  import Struct from '@yume-chan/struct';
2
- import { AdbBufferedStream } from '../../stream';
3
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request';
4
- import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response';
5
- import { AdbSyncLstatResponse } from './stat';
2
+ import type { AdbBufferedStream, WritableStreamDefaultWriter } from '../../stream/index.js';
3
+ import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
4
+ import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response.js';
5
+ import { AdbSyncLstatResponse, AdbSyncStatResponse, type AdbSyncStat } from './stat.js';
6
+
7
+ export interface AdbSyncEntry extends AdbSyncStat {
8
+ name: string;
9
+ }
6
10
 
7
11
  export const AdbSyncEntryResponse =
8
12
  new Struct({ littleEndian: true })
@@ -13,21 +17,64 @@ export const AdbSyncEntryResponse =
13
17
 
14
18
  export type AdbSyncEntryResponse = typeof AdbSyncEntryResponse['TDeserializeResult'];
15
19
 
16
- const ResponseTypes = {
20
+ export const AdbSyncEntry2Response =
21
+ new Struct({ littleEndian: true })
22
+ .fields(AdbSyncStatResponse)
23
+ .uint32('nameLength')
24
+ .string('name', { lengthField: 'nameLength' })
25
+ .extra({ id: AdbSyncResponseId.Entry2 as const });
26
+
27
+ export type AdbSyncEntry2Response = typeof AdbSyncEntry2Response['TDeserializeResult'];
28
+
29
+ const LIST_V1_RESPONSE_TYPES = {
17
30
  [AdbSyncResponseId.Entry]: AdbSyncEntryResponse,
18
31
  [AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncEntryResponse.size),
19
32
  };
20
33
 
34
+ const LIST_V2_RESPONSE_TYPES = {
35
+ [AdbSyncResponseId.Entry2]: AdbSyncEntry2Response,
36
+ [AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncEntry2Response.size),
37
+ };
38
+
21
39
  export async function* adbSyncOpenDir(
22
40
  stream: AdbBufferedStream,
23
- path: string
24
- ): AsyncGenerator<AdbSyncEntryResponse, void, void> {
25
- await adbSyncWriteRequest(stream, AdbSyncRequestId.List, path);
41
+ writer: WritableStreamDefaultWriter<Uint8Array>,
42
+ path: string,
43
+ v2: boolean,
44
+ ): AsyncGenerator<AdbSyncEntry, void, void> {
45
+ let requestId: AdbSyncRequestId.List | AdbSyncRequestId.List2;
46
+ let responseType: typeof LIST_V1_RESPONSE_TYPES | typeof LIST_V2_RESPONSE_TYPES;
47
+
48
+ if (v2) {
49
+ requestId = AdbSyncRequestId.List2;
50
+ responseType = LIST_V2_RESPONSE_TYPES;
51
+ } else {
52
+ requestId = AdbSyncRequestId.List;
53
+ responseType = LIST_V1_RESPONSE_TYPES;
54
+ }
55
+
56
+ await adbSyncWriteRequest(writer, requestId, path);
26
57
 
27
58
  while (true) {
28
- const response = await adbSyncReadResponse(stream, ResponseTypes);
59
+ const response = await adbSyncReadResponse(stream, responseType);
29
60
  switch (response.id) {
30
61
  case AdbSyncResponseId.Entry:
62
+ yield {
63
+ mode: response.mode,
64
+ size: BigInt(response.size),
65
+ mtime: BigInt(response.mtime),
66
+ get type() { return response.type; },
67
+ get permission() { return response.permission; },
68
+ name: response.name,
69
+ };
70
+ break;
71
+ case AdbSyncResponseId.Entry2:
72
+ // `LST2` can return error codes for failed `lstat` calls.
73
+ // `LIST` just ignores them.
74
+ // But they only contain `name` so still pretty useless.
75
+ if (response.error !== 0) {
76
+ continue;
77
+ }
31
78
  yield response;
32
79
  break;
33
80
  case AdbSyncResponseId.Done:
@@ -1,12 +1,12 @@
1
1
  import Struct from '@yume-chan/struct';
2
- import { AdbBufferedStream } from '../../stream';
3
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request';
4
- import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response';
2
+ import { AdbBufferedStream, ReadableStream, WritableStreamDefaultWriter } from '../../stream/index.js';
3
+ import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
4
+ import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response.js';
5
5
 
6
6
  export const AdbSyncDataResponse =
7
7
  new Struct({ littleEndian: true })
8
8
  .uint32('dataLength')
9
- .arrayBuffer('data', { lengthField: 'dataLength' })
9
+ .uint8Array('data', { lengthField: 'dataLength' })
10
10
  .extra({ id: AdbSyncResponseId.Data as const });
11
11
 
12
12
  const ResponseTypes = {
@@ -14,21 +14,30 @@ const ResponseTypes = {
14
14
  [AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncDataResponse.size),
15
15
  };
16
16
 
17
- export async function* adbSyncPull(
17
+ export function adbSyncPull(
18
18
  stream: AdbBufferedStream,
19
+ writer: WritableStreamDefaultWriter<Uint8Array>,
19
20
  path: string,
20
- ): AsyncGenerator<ArrayBuffer, void, void> {
21
- await adbSyncWriteRequest(stream, AdbSyncRequestId.Receive, path);
22
- while (true) {
23
- const response = await adbSyncReadResponse(stream, ResponseTypes);
24
- switch (response.id) {
25
- case AdbSyncResponseId.Data:
26
- yield response.data!;
27
- break;
28
- case AdbSyncResponseId.Done:
29
- return;
30
- default:
31
- throw new Error('Unexpected response id');
21
+ ): ReadableStream<Uint8Array> {
22
+ return new ReadableStream<Uint8Array>({
23
+ async start() {
24
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Receive, path);
25
+ },
26
+ async pull(controller) {
27
+ const response = await adbSyncReadResponse(stream, ResponseTypes);
28
+ switch (response.id) {
29
+ case AdbSyncResponseId.Data:
30
+ controller.enqueue(response.data!);
31
+ break;
32
+ case AdbSyncResponseId.Done:
33
+ controller.close();
34
+ break;
35
+ default:
36
+ throw new Error('Unexpected response id');
37
+ }
32
38
  }
33
- }
39
+ }, {
40
+ highWaterMark: 16 * 1024,
41
+ size(chunk) { return chunk.byteLength; }
42
+ });
34
43
  }
@@ -1,9 +1,8 @@
1
1
  import Struct from '@yume-chan/struct';
2
- import { AdbBufferedStream } from '../../stream';
3
- import { chunkArrayLike, chunkAsyncIterable } from '../../utils';
4
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request';
5
- import { adbSyncReadResponse, AdbSyncResponseId } from './response';
6
- import { LinuxFileType } from './stat';
2
+ import { AdbBufferedStream, ChunkStream, pipeFrom, WritableStream, WritableStreamDefaultWriter } from '../../stream/index.js';
3
+ import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
4
+ import { adbSyncReadResponse, AdbSyncResponseId } from './response.js';
5
+ import { LinuxFileType } from './stat.js';
7
6
 
8
7
  export const AdbSyncOkResponse =
9
8
  new Struct({ littleEndian: true })
@@ -13,34 +12,30 @@ const ResponseTypes = {
13
12
  [AdbSyncResponseId.Ok]: AdbSyncOkResponse,
14
13
  };
15
14
 
16
- export const AdbSyncMaxPacketSize = 64 * 1024;
15
+ export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
17
16
 
18
- export async function adbSyncPush(
17
+ export function adbSyncPush(
19
18
  stream: AdbBufferedStream,
19
+ writer: WritableStreamDefaultWriter<Uint8Array>,
20
20
  filename: string,
21
- content: ArrayLike<number> | ArrayBufferLike | AsyncIterable<ArrayBuffer>,
22
21
  mode: number = (LinuxFileType.File << 12) | 0o666,
23
22
  mtime: number = (Date.now() / 1000) | 0,
24
- packetSize: number = AdbSyncMaxPacketSize,
25
- onProgress?: (uploaded: number) => void,
26
- ): Promise<void> {
27
- const pathAndMode = `${filename},${mode.toString()}`;
28
- await adbSyncWriteRequest(stream, AdbSyncRequestId.Send, pathAndMode);
29
-
30
- let chunkReader: Iterable<ArrayBuffer> | AsyncIterable<ArrayBuffer>;
31
- if ('length' in content || 'byteLength' in content) {
32
- chunkReader = chunkArrayLike(content, packetSize);
33
- } else {
34
- chunkReader = chunkAsyncIterable(content, packetSize);
35
- }
36
-
37
- let uploaded = 0;
38
- for await (const buffer of chunkReader) {
39
- await adbSyncWriteRequest(stream, AdbSyncRequestId.Data, buffer);
40
- uploaded += buffer.byteLength;
41
- onProgress?.(uploaded);
42
- }
43
-
44
- await adbSyncWriteRequest(stream, AdbSyncRequestId.Done, mtime);
45
- await adbSyncReadResponse(stream, ResponseTypes);
23
+ packetSize: number = ADB_SYNC_MAX_PACKET_SIZE,
24
+ ): WritableStream<Uint8Array> {
25
+ return pipeFrom(
26
+ new WritableStream<Uint8Array>({
27
+ async start() {
28
+ const pathAndMode = `${filename},${mode.toString()}`;
29
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Send, pathAndMode);
30
+ },
31
+ async write(chunk) {
32
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk);
33
+ },
34
+ async close() {
35
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime);
36
+ await adbSyncReadResponse(stream, ResponseTypes);
37
+ },
38
+ }),
39
+ new ChunkStream(packetSize)
40
+ );
46
41
  }
@@ -1,9 +1,10 @@
1
1
  import Struct from '@yume-chan/struct';
2
- import type { AdbBufferedStream } from '../../stream';
3
- import { encodeUtf8 } from "../../utils";
2
+ import type { WritableStreamDefaultWriter } from "../../stream/index.js";
3
+ import { encodeUtf8 } from "../../utils/index.js";
4
4
 
5
5
  export enum AdbSyncRequestId {
6
6
  List = 'LIST',
7
+ List2 = 'LIS2',
7
8
  Send = 'SEND',
8
9
  Lstat = 'STAT',
9
10
  Stat = 'STA2',
@@ -21,14 +22,14 @@ export const AdbSyncNumberRequest =
21
22
  export const AdbSyncDataRequest =
22
23
  new Struct({ littleEndian: true })
23
24
  .fields(AdbSyncNumberRequest)
24
- .arrayBuffer('data', { lengthField: 'arg' });
25
+ .uint8Array('data', { lengthField: 'arg' });
25
26
 
26
27
  export async function adbSyncWriteRequest(
27
- stream: AdbBufferedStream,
28
+ writer: WritableStreamDefaultWriter<Uint8Array>,
28
29
  id: AdbSyncRequestId | string,
29
- value: number | string | ArrayBuffer
30
+ value: number | string | Uint8Array
30
31
  ): Promise<void> {
31
- let buffer: ArrayBuffer;
32
+ let buffer: Uint8Array;
32
33
  if (typeof value === 'number') {
33
34
  buffer = AdbSyncNumberRequest.serialize({
34
35
  id,
@@ -45,5 +46,5 @@ export async function adbSyncWriteRequest(
45
46
  data: value,
46
47
  });
47
48
  }
48
- await stream.write(buffer);
49
+ await writer.write(buffer);
49
50
  }
@@ -1,9 +1,10 @@
1
- import Struct, { StructAsyncDeserializeStream, StructLike, StructValueType } from '@yume-chan/struct';
2
- import { AdbBufferedStream } from '../../stream';
3
- import { decodeUtf8 } from "../../utils";
1
+ import Struct, { type StructAsyncDeserializeStream, type StructLike, type StructValueType } from '@yume-chan/struct';
2
+ import type { AdbBufferedStream } from '../../stream/index.js';
3
+ import { decodeUtf8 } from "../../utils/index.js";
4
4
 
5
5
  export enum AdbSyncResponseId {
6
6
  Entry = 'DENT',
7
+ Entry2 = 'DNT2',
7
8
  Lstat = 'STAT',
8
9
  Stat = 'STA2',
9
10
  Lstat2 = 'LST2',
@@ -43,7 +44,12 @@ export const AdbSyncFailResponse =
43
44
  export async function adbSyncReadResponse<T extends Record<string, StructLike<any>>>(
44
45
  stream: AdbBufferedStream,
45
46
  types: T,
46
- ): Promise<StructValueType<T[keyof T]>> {
47
+ // When `T` is a union type, `T[keyof T]` only includes their common keys.
48
+ // For example, let `type T = { a: string, b: string } | { a: string, c: string}`,
49
+ // `keyof T` is `'a'`, not `'a' | 'b' | 'c'`.
50
+ // However, `T extends unknown ? keyof T : never` will distribute `T`,
51
+ // so returns all keys.
52
+ ): Promise<StructValueType<T extends unknown ? T[keyof T] : never>> {
47
53
  const id = decodeUtf8(await stream.read(4));
48
54
 
49
55
  if (id === AdbSyncResponseId.Fail) {
@@ -51,8 +57,8 @@ export async function adbSyncReadResponse<T extends Record<string, StructLike<an
51
57
  }
52
58
 
53
59
  if (types[id]) {
54
- return types[id].deserialize(stream);
60
+ return types[id]!.deserialize(stream);
55
61
  }
56
62
 
57
- throw new Error('Unexpected response id');
63
+ throw new Error(`Expected '${Object.keys(types).join(', ')}', but got '${id}'`);
58
64
  }
@@ -1,7 +1,7 @@
1
1
  import Struct, { placeholder } from '@yume-chan/struct';
2
- import { AdbBufferedStream } from '../../stream';
3
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request';
4
- import { adbSyncReadResponse, AdbSyncResponseId } from './response';
2
+ import type { AdbBufferedStream, WritableStreamDefaultWriter } from '../../stream/index.js';
3
+ import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
4
+ import { adbSyncReadResponse, AdbSyncResponseId } from './response.js';
5
5
 
6
6
  // https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
7
7
  export enum LinuxFileType {
@@ -10,6 +10,19 @@ export enum LinuxFileType {
10
10
  Link = 0o12,
11
11
  }
12
12
 
13
+ export interface AdbSyncStat {
14
+ mode: number;
15
+ size: bigint;
16
+ mtime: bigint;
17
+ get type(): LinuxFileType;
18
+ get permission(): number;
19
+
20
+ uid?: number;
21
+ gid?: number;
22
+ atime?: bigint;
23
+ ctime?: bigint;
24
+ }
25
+
13
26
  export const AdbSyncLstatResponse =
14
27
  new Struct({ littleEndian: true })
15
28
  .int32('mode')
@@ -32,6 +45,7 @@ export const AdbSyncLstatResponse =
32
45
  export type AdbSyncLstatResponse = typeof AdbSyncLstatResponse['TDeserializeResult'];
33
46
 
34
47
  export enum AdbSyncStatErrorCode {
48
+ SUCCESS = 0,
35
49
  EACCES = 13,
36
50
  EEXIST = 17,
37
51
  EFAULT = 14,
@@ -80,42 +94,57 @@ export const AdbSyncStatResponse =
80
94
 
81
95
  export type AdbSyncStatResponse = typeof AdbSyncStatResponse['TDeserializeResult'];
82
96
 
83
- const StatResponseType = {
97
+ const STAT_RESPONSE_TYPES = {
84
98
  [AdbSyncResponseId.Stat]: AdbSyncStatResponse,
85
99
  };
86
100
 
87
- const LstatResponseType = {
101
+ const LSTAT_RESPONSE_TYPES = {
88
102
  [AdbSyncResponseId.Lstat]: AdbSyncLstatResponse,
89
103
  };
90
104
 
91
- const Lstat2ResponseType = {
105
+ const LSTAT_V2_RESPONSE_TYPES = {
92
106
  [AdbSyncResponseId.Lstat2]: AdbSyncStatResponse,
93
107
  };
94
108
 
95
109
  export async function adbSyncLstat(
96
110
  stream: AdbBufferedStream,
111
+ writer: WritableStreamDefaultWriter<Uint8Array>,
97
112
  path: string,
98
113
  v2: boolean,
99
- ): Promise<AdbSyncLstatResponse | AdbSyncStatResponse> {
114
+ ): Promise<AdbSyncStat> {
100
115
  let requestId: AdbSyncRequestId.Lstat | AdbSyncRequestId.Lstat2;
101
- let responseType: typeof LstatResponseType | typeof Lstat2ResponseType;
116
+ let responseType: typeof LSTAT_RESPONSE_TYPES | typeof LSTAT_V2_RESPONSE_TYPES;
102
117
 
103
118
  if (v2) {
104
119
  requestId = AdbSyncRequestId.Lstat2;
105
- responseType = Lstat2ResponseType;
120
+ responseType = LSTAT_V2_RESPONSE_TYPES;
106
121
  } else {
107
122
  requestId = AdbSyncRequestId.Lstat;
108
- responseType = LstatResponseType;
123
+ responseType = LSTAT_RESPONSE_TYPES;
109
124
  }
110
125
 
111
- await adbSyncWriteRequest(stream, requestId, path);
112
- return adbSyncReadResponse(stream, responseType);
126
+ await adbSyncWriteRequest(writer, requestId, path);
127
+ const response = await adbSyncReadResponse(stream, responseType);
128
+
129
+ switch (response.id) {
130
+ case AdbSyncResponseId.Lstat:
131
+ return {
132
+ mode: response.mode,
133
+ size: BigInt(response.size),
134
+ mtime: BigInt(response.mtime),
135
+ get type() { return response.type; },
136
+ get permission() { return response.permission; },
137
+ };
138
+ default:
139
+ return response;
140
+ }
113
141
  }
114
142
 
115
143
  export async function adbSyncStat(
116
144
  stream: AdbBufferedStream,
145
+ writer: WritableStreamDefaultWriter<Uint8Array>,
117
146
  path: string,
118
147
  ): Promise<AdbSyncStatResponse> {
119
- await adbSyncWriteRequest(stream, AdbSyncRequestId.Stat, path);
120
- return adbSyncReadResponse(stream, StatResponseType);
148
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Stat, path);
149
+ return await adbSyncReadResponse(stream, STAT_RESPONSE_TYPES);
121
150
  }
@@ -1,37 +1,70 @@
1
1
  import { AutoDisposable } from '@yume-chan/event';
2
- import { Adb } from '../../adb';
3
- import { AdbFeatures } from '../../features';
4
- import { AdbSocket } from '../../socket';
5
- import { AdbBufferedStream } from '../../stream';
6
- import { AutoResetEvent } from '../../utils';
7
- import { AdbSyncEntryResponse, adbSyncOpenDir } from './list';
8
- import { adbSyncPull } from './pull';
9
- import { adbSyncPush } from './push';
10
- import { adbSyncLstat, adbSyncStat } from './stat';
2
+ import type { Adb } from '../../adb.js';
3
+ import { AdbFeatures } from '../../features.js';
4
+ import type { AdbSocket } from '../../socket/index.js';
5
+ import { AdbBufferedStream, ReadableStream, WrapReadableStream, WrapWritableStream, WritableStream, WritableStreamDefaultWriter } from '../../stream/index.js';
6
+ import { AutoResetEvent } from '../../utils/index.js';
7
+ import { escapeArg } from "../index.js";
8
+ import { adbSyncOpenDir, type AdbSyncEntry } from './list.js';
9
+ import { adbSyncPull } from './pull.js';
10
+ import { adbSyncPush } from './push.js';
11
+ import { adbSyncLstat, adbSyncStat } from './stat.js';
12
+
13
+ /**
14
+ * A simplified `dirname` function that only handles absolute unix paths.
15
+ * @param path an absolute unix path
16
+ * @returns the directory name of the input path
17
+ */
18
+ export function dirname(path: string): string {
19
+ const end = path.lastIndexOf('/');
20
+ if (end === -1) {
21
+ throw new Error(`Invalid path`);
22
+ }
23
+ if (end === 0) {
24
+ return '/';
25
+ }
26
+ return path.substring(0, end);
27
+ }
11
28
 
12
29
  export class AdbSync extends AutoDisposable {
13
30
  protected adb: Adb;
14
31
 
15
32
  protected stream: AdbBufferedStream;
16
33
 
34
+ protected writer: WritableStreamDefaultWriter<Uint8Array>;
35
+
17
36
  protected sendLock = this.addDisposable(new AutoResetEvent());
18
37
 
19
38
  public get supportsStat(): boolean {
20
39
  return this.adb.features!.includes(AdbFeatures.StatV2);
21
40
  }
22
41
 
42
+ public get supportsList2(): boolean {
43
+ return this.adb.features!.includes(AdbFeatures.ListV2);
44
+ }
45
+
46
+ public get fixedPushMkdir(): boolean {
47
+ return this.adb.features!.includes(AdbFeatures.FixedPushMkdir);
48
+ }
49
+
50
+ public get needPushMkdirWorkaround(): boolean {
51
+ // https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
52
+ return this.adb.features!.includes(AdbFeatures.ShellV2) && !this.fixedPushMkdir;
53
+ }
54
+
23
55
  public constructor(adb: Adb, socket: AdbSocket) {
24
56
  super();
25
57
 
26
58
  this.adb = adb;
27
59
  this.stream = new AdbBufferedStream(socket);
60
+ this.writer = socket.writable.getWriter();
28
61
  }
29
62
 
30
63
  public async lstat(path: string) {
31
64
  await this.sendLock.wait();
32
65
 
33
66
  try {
34
- return adbSyncLstat(this.stream, path, this.supportsStat);
67
+ return adbSyncLstat(this.stream, this.writer, path, this.supportsStat);
35
68
  } finally {
36
69
  this.sendLock.notify();
37
70
  }
@@ -45,7 +78,7 @@ export class AdbSync extends AutoDisposable {
45
78
  await this.sendLock.wait();
46
79
 
47
80
  try {
48
- return adbSyncStat(this.stream, path);
81
+ return adbSyncStat(this.stream, this.writer, path);
49
82
  } finally {
50
83
  this.sendLock.notify();
51
84
  }
@@ -62,52 +95,87 @@ export class AdbSync extends AutoDisposable {
62
95
 
63
96
  public async *opendir(
64
97
  path: string
65
- ): AsyncGenerator<AdbSyncEntryResponse, void, void> {
98
+ ): AsyncGenerator<AdbSyncEntry, void, void> {
66
99
  await this.sendLock.wait();
67
100
 
68
101
  try {
69
- yield* adbSyncOpenDir(this.stream, path);
102
+ yield* adbSyncOpenDir(this.stream, this.writer, path, this.supportsList2);
70
103
  } finally {
71
104
  this.sendLock.notify();
72
105
  }
73
106
  }
74
107
 
75
108
  public async readdir(path: string) {
76
- const results: AdbSyncEntryResponse[] = [];
109
+ const results: AdbSyncEntry[] = [];
77
110
  for await (const entry of this.opendir(path)) {
78
111
  results.push(entry);
79
112
  }
80
113
  return results;
81
114
  }
82
115
 
83
- public async *read(filename: string): AsyncGenerator<ArrayBuffer, void, void> {
84
- await this.sendLock.wait();
85
-
86
- try {
87
- yield* adbSyncPull(this.stream, filename);
88
- } finally {
89
- this.sendLock.notify();
90
- }
116
+ /**
117
+ * Read the content of a file on device.
118
+ *
119
+ * @param filename The full path of the file on device to read.
120
+ * @returns A `ReadableStream` that reads from the file.
121
+ */
122
+ public read(filename: string): ReadableStream<Uint8Array> {
123
+ return new WrapReadableStream({
124
+ start: async () => {
125
+ await this.sendLock.wait();
126
+ return adbSyncPull(this.stream, this.writer, filename);
127
+ },
128
+ close: async () => {
129
+ this.sendLock.notify();
130
+ },
131
+ });
91
132
  }
92
133
 
93
- public async write(
134
+ /**
135
+ * Write (or overwrite) a file on device.
136
+ *
137
+ * @param filename The full path of the file on device to write.
138
+ * @param mode The unix permissions of the file.
139
+ * @param mtime The modified time of the file.
140
+ * @returns A `WritableStream` that writes to the file.
141
+ */
142
+ public write(
94
143
  filename: string,
95
- content: ArrayLike<number> | ArrayBufferLike | AsyncIterable<ArrayBuffer>,
96
144
  mode?: number,
97
145
  mtime?: number,
98
- onProgress?: (uploaded: number) => void,
99
- ): Promise<void> {
100
- await this.sendLock.wait();
101
-
102
- try {
103
- await adbSyncPush(this.stream, filename, content, mode, mtime, undefined, onProgress);
104
- } finally {
105
- this.sendLock.notify();
106
- }
146
+ ): WritableStream<Uint8Array> {
147
+ return new WrapWritableStream({
148
+ start: async () => {
149
+ await this.sendLock.wait();
150
+
151
+ if (this.needPushMkdirWorkaround) {
152
+ // It may fail if the path is already existed.
153
+ // Ignore the result.
154
+ // TODO: sync: test this
155
+ await this.adb.subprocess.spawnAndWait([
156
+ 'mkdir',
157
+ '-p',
158
+ escapeArg(dirname(filename)),
159
+ ]);
160
+ }
161
+
162
+ return adbSyncPush(
163
+ this.stream,
164
+ this.writer,
165
+ filename,
166
+ mode,
167
+ mtime,
168
+ );
169
+ },
170
+ close: async () => {
171
+ this.sendLock.notify();
172
+ }
173
+ });
107
174
  }
108
175
 
109
- public override dispose() {
176
+ public override async dispose() {
110
177
  super.dispose();
111
178
  this.stream.close();
179
+ await this.writer.close();
112
180
  }
113
181
  }
@@ -1,4 +1,4 @@
1
- import { AdbCommandBase } from './base';
1
+ import { AdbCommandBase } from './base.js';
2
2
 
3
3
  export class AdbTcpIpCommand extends AdbCommandBase {
4
4
  public async setPort(port: number): Promise<void> {
@@ -6,14 +6,14 @@ export class AdbTcpIpCommand extends AdbCommandBase {
6
6
  throw new Error(`Invalid port ${port}`);
7
7
  }
8
8
 
9
- const output = await this.adb.createSocketAndReadAll(`tcpip:${port}`);
9
+ const output = await this.adb.createSocketAndWait(`tcpip:${port}`);
10
10
  if (output !== `restarting in TCP mode port: ${port}\n`) {
11
11
  throw new Error('Invalid response');
12
12
  }
13
13
  }
14
14
 
15
15
  public async disable(): Promise<void> {
16
- const output = await this.adb.createSocketAndReadAll('usb:');
16
+ const output = await this.adb.createSocketAndWait('usb:');
17
17
  if (output !== 'restarting in USB mode\n') {
18
18
  throw new Error('Invalid response');
19
19
  }