@yume-chan/android-bin 0.0.23 → 1.0.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 (56) hide show
  1. package/CHANGELOG.md +40 -2
  2. package/LICENSE +1 -1
  3. package/README.md +5 -2
  4. package/esm/am.d.ts.map +1 -1
  5. package/esm/am.js +2 -2
  6. package/esm/am.js.map +1 -1
  7. package/esm/bu.d.ts +2 -2
  8. package/esm/bu.d.ts.map +1 -1
  9. package/esm/bu.js +2 -2
  10. package/esm/bu.js.map +1 -1
  11. package/esm/bug-report.d.ts.map +1 -1
  12. package/esm/bug-report.js +27 -29
  13. package/esm/bug-report.js.map +1 -1
  14. package/esm/cmd.d.ts +12 -0
  15. package/esm/cmd.d.ts.map +1 -1
  16. package/esm/cmd.js +15 -3
  17. package/esm/cmd.js.map +1 -1
  18. package/esm/dumpsys.d.ts +55 -26
  19. package/esm/dumpsys.d.ts.map +1 -1
  20. package/esm/dumpsys.js +66 -69
  21. package/esm/dumpsys.js.map +1 -1
  22. package/esm/intent.d.ts +1 -0
  23. package/esm/intent.d.ts.map +1 -1
  24. package/esm/intent.js +8 -0
  25. package/esm/intent.js.map +1 -1
  26. package/esm/logcat.d.ts +59 -46
  27. package/esm/logcat.d.ts.map +1 -1
  28. package/esm/logcat.js +82 -81
  29. package/esm/logcat.js.map +1 -1
  30. package/esm/overlay-display.d.ts.map +1 -1
  31. package/esm/overlay-display.js +1 -1
  32. package/esm/overlay-display.js.map +1 -1
  33. package/esm/pm.d.ts +5 -5
  34. package/esm/pm.d.ts.map +1 -1
  35. package/esm/pm.js +51 -28
  36. package/esm/pm.js.map +1 -1
  37. package/esm/settings.d.ts.map +1 -1
  38. package/esm/string-format.d.ts +9 -6
  39. package/esm/string-format.d.ts.map +1 -1
  40. package/esm/string-format.js +3 -4
  41. package/esm/string-format.js.map +1 -1
  42. package/package.json +12 -16
  43. package/src/am.ts +5 -3
  44. package/src/bu.ts +4 -4
  45. package/src/bug-report.ts +40 -44
  46. package/src/cmd.ts +19 -7
  47. package/src/dumpsys.ts +100 -66
  48. package/src/intent.ts +10 -0
  49. package/src/logcat.ts +117 -105
  50. package/src/overlay-display.ts +2 -2
  51. package/src/pm.ts +81 -52
  52. package/src/settings.ts +1 -1
  53. package/src/string-format.ts +3 -5
  54. package/tsconfig.build.json +1 -1
  55. package/tsconfig.build.tsbuildinfo +1 -1
  56. package/CHANGELOG.json +0 -175
package/src/logcat.ts CHANGED
@@ -5,42 +5,50 @@ import { AdbCommandBase, AdbSubprocessNoneProtocol } from "@yume-chan/adb";
5
5
  import type { ReadableStream } from "@yume-chan/stream-extra";
6
6
  import {
7
7
  BufferedTransformStream,
8
- DecodeUtf8Stream,
9
8
  SplitStringStream,
9
+ TextDecoderStream,
10
10
  WrapReadableStream,
11
- WritableStream,
12
11
  } from "@yume-chan/stream-extra";
13
- import type { AsyncExactReadable } from "@yume-chan/struct";
14
- import Struct, { decodeUtf8 } from "@yume-chan/struct";
12
+ import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
13
+ import { decodeUtf8, struct, u16, u32 } from "@yume-chan/struct";
15
14
 
16
15
  // `adb logcat` is an alias to `adb shell logcat`
17
16
  // so instead of adding to core library, it's implemented here
18
17
 
19
18
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=141;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
20
- export enum LogId {
21
- All = -1,
22
- Main,
23
- Radio,
24
- Events,
25
- System,
26
- Crash,
27
- Stats,
28
- Security,
29
- Kernel,
30
- }
19
+ export const LogId = {
20
+ All: -1,
21
+ Main: 0,
22
+ Radio: 1,
23
+ Events: 2,
24
+ System: 3,
25
+ Crash: 4,
26
+ Stats: 5,
27
+ Security: 6,
28
+ Kernel: 7,
29
+ } as const;
30
+
31
+ export type LogId = (typeof LogId)[keyof typeof LogId];
32
+
33
+ const LogIdName =
34
+ /* #__PURE__ */
35
+ (() => Object.fromEntries(Object.entries(LogId).map(([k, v]) => [v, k])))();
31
36
 
32
37
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
33
- export enum AndroidLogPriority {
34
- Unknown,
35
- Default,
36
- Verbose,
37
- Debug,
38
- Info,
39
- Warn,
40
- Error,
41
- Fatal,
42
- Silent,
43
- }
38
+ export const AndroidLogPriority = {
39
+ Unknown: 0,
40
+ Default: 1,
41
+ Verbose: 2,
42
+ Debug: 3,
43
+ Info: 4,
44
+ Warn: 5,
45
+ Error: 6,
46
+ Fatal: 7,
47
+ Silent: 8,
48
+ } as const;
49
+
50
+ export type AndroidLogPriority =
51
+ (typeof AndroidLogPriority)[keyof typeof AndroidLogPriority];
44
52
 
45
53
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=140;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
46
54
  export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
@@ -56,16 +64,18 @@ export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
56
64
  [AndroidLogPriority.Silent]: "S",
57
65
  };
58
66
 
59
- export enum LogcatFormat {
60
- Brief,
61
- Process,
62
- Tag,
63
- Thread,
64
- Raw,
65
- Time,
66
- ThreadTime,
67
- Long,
68
- }
67
+ export const LogcatFormat = {
68
+ Brief: 0,
69
+ Process: 1,
70
+ Tag: 2,
71
+ Thread: 3,
72
+ Raw: 4,
73
+ Time: 5,
74
+ ThreadTime: 6,
75
+ Long: 7,
76
+ } as const;
77
+
78
+ export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat];
69
79
 
70
80
  export interface LogcatFormatModifiers {
71
81
  microseconds?: boolean;
@@ -85,28 +95,34 @@ export interface LogcatOptions {
85
95
  ids?: LogId[];
86
96
  }
87
97
 
88
- const NANOSECONDS_PER_SECOND = BigInt(1e9);
98
+ const NANOSECONDS_PER_SECOND = /* #__PURE__ */ BigInt(1e9);
89
99
 
90
100
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
91
- export const LoggerEntry = new Struct({ littleEndian: true })
92
- .uint16("payloadSize")
93
- .uint16("headerSize")
94
- .int32("pid")
95
- .uint32("tid")
96
- .uint32("seconds")
97
- .uint32("nanoseconds")
98
- .uint32("logId")
99
- .uint32("uid")
100
- .extra({
101
- get timestamp() {
102
- return (
103
- BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
104
- BigInt(this.nanoseconds)
105
- );
101
+ export const LoggerEntry = struct(
102
+ {
103
+ payloadSize: u16,
104
+ headerSize: u16,
105
+ pid: u32,
106
+ tid: u32,
107
+ seconds: u32,
108
+ nanoseconds: u32,
109
+ logId: u32,
110
+ uid: u32,
111
+ },
112
+ {
113
+ littleEndian: true,
114
+ extra: {
115
+ get timestamp(): bigint {
116
+ return (
117
+ BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
118
+ BigInt(this.nanoseconds)
119
+ );
120
+ },
106
121
  },
107
- });
122
+ },
123
+ );
108
124
 
109
- export type LoggerEntry = (typeof LoggerEntry)["TDeserializeResult"];
125
+ export type LoggerEntry = StructValue<typeof LoggerEntry>;
110
126
 
111
127
  // https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6;bpv=0
112
128
  export interface AndroidLogEntry extends LoggerEntry {
@@ -353,6 +369,7 @@ export async function deserializeAndroidLogEntry(
353
369
  ): Promise<AndroidLogEntry> {
354
370
  const entry = (await LoggerEntry.deserialize(stream)) as AndroidLogEntry;
355
371
  if (entry.headerSize !== LoggerEntry.size) {
372
+ // Skip unknown fields
356
373
  await stream.readExactly(entry.headerSize - LoggerEntry.size);
357
374
  }
358
375
 
@@ -384,7 +401,7 @@ export interface LogSize {
384
401
 
385
402
  export class Logcat extends AdbCommandBase {
386
403
  static logIdToName(id: LogId): string {
387
- return LogId[id];
404
+ return LogIdName[id]!;
388
405
  }
389
406
 
390
407
  static logNameToId(name: string): LogId {
@@ -403,12 +420,12 @@ export class Logcat extends AdbCommandBase {
403
420
 
404
421
  // TODO: logcat: Support output format before Android 10
405
422
  // ref https://android-review.googlesource.com/c/platform/system/core/+/748128
406
- static readonly LOG_SIZE_REGEX_10 =
423
+ static readonly LOG_SIZE_REGEX_10: RegExp =
407
424
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed\), max entry is (.*) B, max payload is (.*) B/;
408
425
 
409
426
  // Android 11 added `readable` part
410
427
  // ref https://android-review.googlesource.com/c/platform/system/core/+/1390940
411
- static readonly LOG_SIZE_REGEX_11 =
428
+ static readonly LOG_SIZE_REGEX_11: RegExp =
412
429
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed, (.*) (.*)B readable\), max entry is (.*) B, max payload is (.*) B/;
413
430
 
414
431
  async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
@@ -419,58 +436,53 @@ export class Logcat extends AdbCommandBase {
419
436
  ]);
420
437
 
421
438
  const result: LogSize[] = [];
422
- await stdout
423
- .pipeThrough(new DecodeUtf8Stream())
424
- .pipeThrough(new SplitStringStream("\n"))
425
- .pipeTo(
426
- new WritableStream({
427
- write(chunk) {
428
- let match = chunk.match(Logcat.LOG_SIZE_REGEX_11);
429
- if (match) {
430
- result.push({
431
- id: Logcat.logNameToId(match[1]!),
432
- size: Logcat.parseSize(
433
- Number.parseInt(match[2]!, 10),
434
- match[3]!,
435
- ),
436
- readable: Logcat.parseSize(
437
- Number.parseInt(match[6]!, 10),
438
- match[7]!,
439
- ),
440
- consumed: Logcat.parseSize(
441
- Number.parseInt(match[4]!, 10),
442
- match[5]!,
443
- ),
444
- maxEntrySize: parseInt(match[8]!, 10),
445
- maxPayloadSize: parseInt(match[9]!, 10),
446
- });
447
- return;
448
- }
449
-
450
- match = chunk.match(Logcat.LOG_SIZE_REGEX_10);
451
- if (match) {
452
- result.push({
453
- id: Logcat.logNameToId(match[1]!),
454
- size: Logcat.parseSize(
455
- Number.parseInt(match[2]!, 10),
456
- match[3]!,
457
- ),
458
- consumed: Logcat.parseSize(
459
- Number.parseInt(match[4]!, 10),
460
- match[5]!,
461
- ),
462
- maxEntrySize: parseInt(match[6]!, 10),
463
- maxPayloadSize: parseInt(match[7]!, 10),
464
- });
465
- }
466
- },
467
- }),
468
- );
439
+ for await (const line of stdout
440
+ .pipeThrough(new TextDecoderStream())
441
+ .pipeThrough(new SplitStringStream("\n"))) {
442
+ let match = line.match(Logcat.LOG_SIZE_REGEX_11);
443
+ if (match) {
444
+ result.push({
445
+ id: Logcat.logNameToId(match[1]!),
446
+ size: Logcat.parseSize(
447
+ Number.parseInt(match[2]!, 10),
448
+ match[3]!,
449
+ ),
450
+ readable: Logcat.parseSize(
451
+ Number.parseInt(match[6]!, 10),
452
+ match[7]!,
453
+ ),
454
+ consumed: Logcat.parseSize(
455
+ Number.parseInt(match[4]!, 10),
456
+ match[5]!,
457
+ ),
458
+ maxEntrySize: parseInt(match[8]!, 10),
459
+ maxPayloadSize: parseInt(match[9]!, 10),
460
+ });
461
+ break;
462
+ }
463
+
464
+ match = line.match(Logcat.LOG_SIZE_REGEX_10);
465
+ if (match) {
466
+ result.push({
467
+ id: Logcat.logNameToId(match[1]!),
468
+ size: Logcat.parseSize(
469
+ Number.parseInt(match[2]!, 10),
470
+ match[3]!,
471
+ ),
472
+ consumed: Logcat.parseSize(
473
+ Number.parseInt(match[4]!, 10),
474
+ match[5]!,
475
+ ),
476
+ maxEntrySize: parseInt(match[6]!, 10),
477
+ maxPayloadSize: parseInt(match[7]!, 10),
478
+ });
479
+ }
480
+ }
469
481
 
470
482
  return result;
471
483
  }
472
484
 
473
- async clear(ids?: LogId[]) {
485
+ async clear(ids?: LogId[]): Promise<void> {
474
486
  const args = ["logcat", "-c"];
475
487
  if (ids && ids.length > 0) {
476
488
  args.push("-b", Logcat.joinLogId(ids));
@@ -36,7 +36,7 @@ export class OverlayDisplay extends AdbCommandBase {
36
36
  p.literal("/"),
37
37
  { name: "density", format: p.digits() },
38
38
  ),
39
- 1,
39
+ { min: 1 },
40
40
  ),
41
41
  },
42
42
  {
@@ -81,7 +81,7 @@ export class OverlayDisplay extends AdbCommandBase {
81
81
  }));
82
82
  }
83
83
 
84
- async set(devices: OverlayDisplayDevice[]) {
84
+ async set(devices: OverlayDisplayDevice[]): Promise<void> {
85
85
  await this.#settings.put(
86
86
  "global",
87
87
  OverlayDisplay.SETTING_KEY,
package/src/pm.ts CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  import type { Adb } from "@yume-chan/adb";
7
7
  import { AdbCommandBase, escapeArg } from "@yume-chan/adb";
8
- import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
8
+ import type { MaybeConsumable, ReadableStream } from "@yume-chan/stream-extra";
9
9
  import {
10
10
  ConcatStringStream,
11
- DecodeUtf8Stream,
12
11
  SplitStringStream,
12
+ TextDecoderStream,
13
13
  } from "@yume-chan/stream-extra";
14
14
 
15
15
  import { Cmd } from "./cmd.js";
@@ -255,6 +255,32 @@ const PACKAGE_MANAGER_RESOLVE_ACTIVITY_OPTIONS_MAP: Partial<
255
255
  user: "--user",
256
256
  };
257
257
 
258
+ function buildInstallArguments(
259
+ command: string,
260
+ options: Partial<PackageManagerInstallOptions> | undefined,
261
+ ): string[] {
262
+ const args = buildArguments(
263
+ ["pm", command],
264
+ options,
265
+ PACKAGE_MANAGER_INSTALL_OPTIONS_MAP,
266
+ );
267
+ if (!options?.skipExisting) {
268
+ /*
269
+ * | behavior | previous version | modern version |
270
+ * | -------------------- | -------------------- | -------------------- |
271
+ * | replace existing app | requires `-r` | default behavior [1] |
272
+ * | skip existing app | default behavior [2] | requires `-R` |
273
+ *
274
+ * [1]: `-r` recognized but ignored
275
+ * [2]: `-R` not recognized but ignored
276
+ *
277
+ * So add `-r` when `skipExisting` is `false` for compatibility.
278
+ */
279
+ args.push("-r");
280
+ }
281
+ return args;
282
+ }
283
+
258
284
  export class PackageManager extends AdbCommandBase {
259
285
  #cmd: Cmd;
260
286
 
@@ -263,22 +289,6 @@ export class PackageManager extends AdbCommandBase {
263
289
  this.#cmd = new Cmd(adb);
264
290
  }
265
291
 
266
- #buildInstallArguments(
267
- command: string,
268
- options: Partial<PackageManagerInstallOptions> | undefined,
269
- ): string[] {
270
- const args = buildArguments(
271
- ["pm", command],
272
- options,
273
- PACKAGE_MANAGER_INSTALL_OPTIONS_MAP,
274
- );
275
- if (!options?.skipExisting) {
276
- // Compatibility with old versions of pm
277
- args.push("-r");
278
- }
279
- return args;
280
- }
281
-
282
292
  /**
283
293
  * Install the apk file.
284
294
  *
@@ -288,14 +298,14 @@ export class PackageManager extends AdbCommandBase {
288
298
  apks: string[],
289
299
  options?: Partial<PackageManagerInstallOptions>,
290
300
  ): Promise<string> {
291
- const args = this.#buildInstallArguments("install", options);
301
+ const args = buildInstallArguments("install", options);
292
302
  // WIP: old version of pm doesn't support multiple apks
293
303
  args.push(...apks);
294
304
  return await this.adb.subprocess.spawnAndWaitLegacy(args);
295
305
  }
296
306
 
297
307
  async pushAndInstallStream(
298
- stream: ReadableStream<Consumable<Uint8Array>>,
308
+ stream: ReadableStream<MaybeConsumable<Uint8Array>>,
299
309
  options?: Partial<PackageManagerInstallOptions>,
300
310
  ): Promise<void> {
301
311
  const sync = await this.adb.sync();
@@ -312,11 +322,16 @@ export class PackageManager extends AdbCommandBase {
312
322
  await sync.dispose();
313
323
  }
314
324
 
315
- // Starting from Android 7, `pm` is only a wrapper for `cmd package`,
316
- // and `cmd package` launches faster than `pm`.
317
- // But `cmd package` can't read `/data/local/tmp` folder due to SELinux policy,
318
- // so installing a file must use `pm`.
319
- const args = this.#buildInstallArguments("install", options);
325
+ // Starting from Android 7, `pm` becomes a wrapper to `cmd package`.
326
+ // The benefit of `cmd package` is it starts faster than the old `pm`,
327
+ // because it connects to the already running `system` process,
328
+ // instead of initializing all system components from scratch.
329
+ //
330
+ // But launching `cmd package` directly causes it to not be able to
331
+ // read files in `/data/local/tmp` (and many other places) due to SELinux policies,
332
+ // so installing files must still use `pm`.
333
+ // (the starting executable file decides which SELinux policies to apply)
334
+ const args = buildInstallArguments("install", options);
320
335
  args.push(filePath);
321
336
 
322
337
  try {
@@ -334,25 +349,28 @@ export class PackageManager extends AdbCommandBase {
334
349
 
335
350
  async installStream(
336
351
  size: number,
337
- stream: ReadableStream<Consumable<Uint8Array>>,
352
+ stream: ReadableStream<MaybeConsumable<Uint8Array>>,
338
353
  options?: Partial<PackageManagerInstallOptions>,
339
354
  ): Promise<void> {
340
355
  // Android 7 added both `cmd` command and streaming install support,
341
- // we can't detect whether `pm` supports streaming install,
342
- // so we detect `cmd` command support instead.
356
+ // It's hard to detect whether `pm` supports streaming install (unless actually trying),
357
+ // so check for whether `cmd` is supported,
358
+ // and assume `pm` streaming install support status is same as that.
343
359
  if (!this.#cmd.supportsCmd) {
360
+ // Fall back to push file then install
344
361
  await this.pushAndInstallStream(stream, options);
345
362
  return;
346
363
  }
347
364
 
348
- const args = this.#buildInstallArguments("install", options);
349
- // Remove `pm` from args, final command will starts with `cmd package install`
365
+ const args = buildInstallArguments("install", options);
366
+ // Remove `pm` from args, `Cmd#spawn` will prepend `cmd <command>` so the final args
367
+ // will be `cmd package install <args>`
350
368
  args.shift();
351
369
  args.push("-S", size.toString());
352
370
  const process = await this.#cmd.spawn(false, "package", ...args);
353
371
 
354
372
  const output = process.stdout
355
- .pipeThrough(new DecodeUtf8Stream())
373
+ .pipeThrough(new TextDecoderStream())
356
374
  .pipeThrough(new ConcatStringStream())
357
375
  .then((output) => output.trim());
358
376
 
@@ -377,7 +395,7 @@ export class PackageManager extends AdbCommandBase {
377
395
  let installer: string | undefined;
378
396
  let uid: number | undefined;
379
397
 
380
- // Parse backwards
398
+ // The output format is easier to parse in backwards
381
399
  let index = line.indexOf(" uid:");
382
400
  if (index !== -1) {
383
401
  uid = Number.parseInt(line.substring(index + " uid:".length), 10);
@@ -399,7 +417,9 @@ export class PackageManager extends AdbCommandBase {
399
417
  line = line.substring(0, index);
400
418
  }
401
419
 
402
- // `sourceDir` may contain `=` so use `lastIndexOf`
420
+ // `sourceDir` may contain `=` characters
421
+ // (because in newer Android versions it's a base64 string of encrypted package name),
422
+ // so use `lastIndexOf`
403
423
  index = line.lastIndexOf("=");
404
424
  if (index !== -1) {
405
425
  sourceDir = line.substring(0, index);
@@ -440,7 +460,10 @@ export class PackageManager extends AdbCommandBase {
440
460
 
441
461
  const process = await this.#cmdOrSubprocess(args);
442
462
  const reader = process.stdout
443
- .pipeThrough(new DecodeUtf8Stream())
463
+ .pipeThrough(new TextDecoderStream())
464
+ // FIXME: `SplitStringStream` will throw away some data
465
+ // if it doesn't end with a separator. So each chunk of data
466
+ // must contain several complete lines.
444
467
  .pipeThrough(new SplitStringStream("\n"))
445
468
  .getReader();
446
469
  while (true) {
@@ -468,7 +491,7 @@ export class PackageManager extends AdbCommandBase {
468
491
 
469
492
  const process = await this.#cmdOrSubprocess(args);
470
493
  const output = await process.stdout
471
- .pipeThrough(new DecodeUtf8Stream())
494
+ .pipeThrough(new TextDecoderStream())
472
495
  .pipeThrough(new ConcatStringStream())
473
496
  .then((output) => output.trim());
474
497
  if (output !== "Success") {
@@ -489,7 +512,7 @@ export class PackageManager extends AdbCommandBase {
489
512
 
490
513
  const process = await this.#cmdOrSubprocess(args);
491
514
  const output = await process.stdout
492
- .pipeThrough(new DecodeUtf8Stream())
515
+ .pipeThrough(new TextDecoderStream())
493
516
  .pipeThrough(new ConcatStringStream())
494
517
  .then((output) => output.trim());
495
518
 
@@ -510,12 +533,14 @@ export class PackageManager extends AdbCommandBase {
510
533
  * @param options Options for the install session
511
534
  * @returns ID of the new install session
512
535
  */
513
- async sessionCreate(options?: Partial<PackageManagerInstallOptions>) {
514
- const args = this.#buildInstallArguments("install-create", options);
536
+ async sessionCreate(
537
+ options?: Partial<PackageManagerInstallOptions>,
538
+ ): Promise<number> {
539
+ const args = buildInstallArguments("install-create", options);
515
540
 
516
541
  const process = await this.#cmdOrSubprocess(args);
517
542
  const output = await process.stdout
518
- .pipeThrough(new DecodeUtf8Stream())
543
+ .pipeThrough(new TextDecoderStream())
519
544
  .pipeThrough(new ConcatStringStream())
520
545
  .then((output) => output.trim());
521
546
 
@@ -527,7 +552,11 @@ export class PackageManager extends AdbCommandBase {
527
552
  return Number.parseInt(sessionIdString[1]!, 10);
528
553
  }
529
554
 
530
- async sessionAddSplit(sessionId: number, splitName: string, path: string) {
555
+ async sessionAddSplit(
556
+ sessionId: number,
557
+ splitName: string,
558
+ path: string,
559
+ ): Promise<void> {
531
560
  const args: string[] = [
532
561
  "pm",
533
562
  "install-write",
@@ -548,8 +577,8 @@ export class PackageManager extends AdbCommandBase {
548
577
  sessionId: number,
549
578
  splitName: string,
550
579
  size: number,
551
- stream: ReadableStream<Consumable<Uint8Array>>,
552
- ) {
580
+ stream: ReadableStream<MaybeConsumable<Uint8Array>>,
581
+ ): Promise<void> {
553
582
  const args: string[] = [
554
583
  "pm",
555
584
  "install-write",
@@ -562,7 +591,7 @@ export class PackageManager extends AdbCommandBase {
562
591
 
563
592
  const process = await this.#cmdOrSubprocess(args);
564
593
  const output = process.stdout
565
- .pipeThrough(new DecodeUtf8Stream())
594
+ .pipeThrough(new TextDecoderStream())
566
595
  .pipeThrough(new ConcatStringStream())
567
596
  .then((output) => output.trim());
568
597
 
@@ -576,7 +605,7 @@ export class PackageManager extends AdbCommandBase {
576
605
  ]);
577
606
  }
578
607
 
579
- async sessionCommit(sessionId: number) {
608
+ async sessionCommit(sessionId: number): Promise<void> {
580
609
  const args: string[] = ["pm", "install-commit", sessionId.toString()];
581
610
  const output = await this.adb.subprocess
582
611
  .spawnAndWaitLegacy(args)
@@ -586,7 +615,7 @@ export class PackageManager extends AdbCommandBase {
586
615
  }
587
616
  }
588
617
 
589
- async sessionAbandon(sessionId: number) {
618
+ async sessionAbandon(sessionId: number): Promise<void> {
590
619
  const args: string[] = ["pm", "install-abandon", sessionId.toString()];
591
620
  const output = await this.adb.subprocess
592
621
  .spawnAndWaitLegacy(args)
@@ -601,7 +630,7 @@ export class PackageManagerInstallSession {
601
630
  static async create(
602
631
  packageManager: PackageManager,
603
632
  options?: Partial<PackageManagerInstallOptions>,
604
- ) {
633
+ ): Promise<PackageManagerInstallSession> {
605
634
  const id = await packageManager.sessionCreate(options);
606
635
  return new PackageManagerInstallSession(packageManager, id);
607
636
  }
@@ -609,7 +638,7 @@ export class PackageManagerInstallSession {
609
638
  #packageManager: PackageManager;
610
639
 
611
640
  #id: number;
612
- get id() {
641
+ get id(): number {
613
642
  return this.#id;
614
643
  }
615
644
 
@@ -618,15 +647,15 @@ export class PackageManagerInstallSession {
618
647
  this.#id = id;
619
648
  }
620
649
 
621
- addSplit(splitName: string, path: string) {
650
+ addSplit(splitName: string, path: string): Promise<void> {
622
651
  return this.#packageManager.sessionAddSplit(this.#id, splitName, path);
623
652
  }
624
653
 
625
654
  addSplitStream(
626
655
  splitName: string,
627
656
  size: number,
628
- stream: ReadableStream<Consumable<Uint8Array>>,
629
- ) {
657
+ stream: ReadableStream<MaybeConsumable<Uint8Array>>,
658
+ ): Promise<void> {
630
659
  return this.#packageManager.sessionAddSplitStream(
631
660
  this.#id,
632
661
  splitName,
@@ -635,11 +664,11 @@ export class PackageManagerInstallSession {
635
664
  );
636
665
  }
637
666
 
638
- commit() {
667
+ commit(): Promise<void> {
639
668
  return this.#packageManager.sessionCommit(this.#id);
640
669
  }
641
670
 
642
- abandon() {
671
+ abandon(): Promise<void> {
643
672
  return this.#packageManager.sessionAbandon(this.#id);
644
673
  }
645
674
  }
package/src/settings.ts CHANGED
@@ -66,7 +66,7 @@ export class Settings extends AdbCommandBase {
66
66
  namespace: SettingsNamespace,
67
67
  key: string,
68
68
  options?: SettingsOptions,
69
- ) {
69
+ ): Promise<string> {
70
70
  const output = await this.base("get", namespace, options, key);
71
71
  // Remove last \n
72
72
  return output.substring(0, output.length - 1);
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
1
  export class ParseError extends Error {
3
2
  #expected: string[];
4
3
 
@@ -94,7 +93,7 @@ export const p = {
94
93
  const result = format.stringify(value);
95
94
  // Parse the result to make sure it is valid
96
95
  format.parse({ value: result, position: 0 });
97
- } catch (e) {
96
+ } catch {
98
97
  // ignore
99
98
  }
100
99
  }
@@ -104,8 +103,7 @@ export const p = {
104
103
  separated: <T>(
105
104
  separator: string,
106
105
  format: Format<T>,
107
- min = 0,
108
- max = Infinity,
106
+ { min = 0, max = Infinity }: { min?: number; max?: number } = {},
109
107
  ): Format<T[]> => ({
110
108
  parse(reader: Reader) {
111
109
  const result: T[] = [];
@@ -143,7 +141,7 @@ export const p = {
143
141
  while (true) {
144
142
  try {
145
143
  result.push(format.parse(reader));
146
- } catch (e) {
144
+ } catch {
147
145
  break;
148
146
  }
149
147
  }
@@ -9,6 +9,6 @@
9
9
  },
10
10
  {
11
11
  "path": "../struct/tsconfig.build.json"
12
- },
12
+ }
13
13
  ]
14
14
  }