@yume-chan/adb 2.0.1 → 2.3.1

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 (69) hide show
  1. package/CHANGELOG.md +95 -77
  2. package/README.md +5 -2
  3. package/esm/adb.d.ts +2 -2
  4. package/esm/adb.d.ts.map +1 -1
  5. package/esm/adb.js +2 -0
  6. package/esm/adb.js.map +1 -1
  7. package/esm/banner.d.ts +2 -2
  8. package/esm/banner.d.ts.map +1 -1
  9. package/esm/banner.js.map +1 -1
  10. package/esm/commands/subprocess/none/service.d.ts +1 -1
  11. package/esm/commands/subprocess/none/service.d.ts.map +1 -1
  12. package/esm/commands/subprocess/none/service.js +3 -1
  13. package/esm/commands/subprocess/none/service.js.map +1 -1
  14. package/esm/commands/subprocess/none/spawner.d.ts +4 -4
  15. package/esm/commands/subprocess/none/spawner.d.ts.map +1 -1
  16. package/esm/commands/subprocess/none/spawner.js.map +1 -1
  17. package/esm/commands/subprocess/shell/service.d.ts +1 -1
  18. package/esm/commands/subprocess/shell/service.d.ts.map +1 -1
  19. package/esm/commands/subprocess/shell/spawner.d.ts +4 -4
  20. package/esm/commands/subprocess/shell/spawner.d.ts.map +1 -1
  21. package/esm/commands/subprocess/shell/spawner.js.map +1 -1
  22. package/esm/daemon/auth.d.ts +1 -1
  23. package/esm/daemon/auth.d.ts.map +1 -1
  24. package/esm/daemon/auth.js.map +1 -1
  25. package/esm/daemon/crypto.d.ts +2 -2
  26. package/esm/daemon/crypto.d.ts.map +1 -1
  27. package/esm/daemon/crypto.js.map +1 -1
  28. package/esm/daemon/transport.d.ts +2 -2
  29. package/esm/daemon/transport.d.ts.map +1 -1
  30. package/esm/daemon/transport.js.map +1 -1
  31. package/esm/server/client.d.ts +10 -4
  32. package/esm/server/client.d.ts.map +1 -1
  33. package/esm/server/client.js +18 -6
  34. package/esm/server/client.js.map +1 -1
  35. package/esm/server/observer.d.ts +6 -1
  36. package/esm/server/observer.d.ts.map +1 -1
  37. package/esm/server/observer.js +31 -8
  38. package/esm/server/observer.js.map +1 -1
  39. package/esm/server/transport.d.ts +2 -2
  40. package/esm/server/transport.d.ts.map +1 -1
  41. package/esm/server/transport.js.map +1 -1
  42. package/esm/utils/array-buffer.d.ts +2 -0
  43. package/esm/utils/array-buffer.d.ts.map +1 -0
  44. package/esm/utils/array-buffer.js +9 -0
  45. package/esm/utils/array-buffer.js.map +1 -0
  46. package/esm/utils/base64.d.ts +2 -2
  47. package/esm/utils/base64.d.ts.map +1 -1
  48. package/esm/utils/index.d.ts +1 -0
  49. package/esm/utils/index.d.ts.map +1 -1
  50. package/esm/utils/index.js +1 -0
  51. package/esm/utils/index.js.map +1 -1
  52. package/package.json +6 -6
  53. package/src/adb.ts +5 -3
  54. package/src/banner.ts +2 -2
  55. package/src/commands/subprocess/none/service.ts +5 -2
  56. package/src/commands/subprocess/none/spawner.ts +5 -5
  57. package/src/commands/subprocess/shell/service.ts +1 -1
  58. package/src/commands/subprocess/shell/spawner.ts +5 -5
  59. package/src/commands/sync/response.ts +1 -1
  60. package/src/daemon/auth.ts +1 -1
  61. package/src/daemon/crypto.ts +7 -2
  62. package/src/daemon/transport.ts +2 -2
  63. package/src/server/client.ts +30 -8
  64. package/src/server/observer.ts +62 -15
  65. package/src/server/transport.ts +1 -1
  66. package/src/utils/array-buffer.ts +9 -0
  67. package/src/utils/base64.ts +2 -2
  68. package/src/utils/index.ts +1 -0
  69. package/tsconfig.build.tsbuildinfo +1 -1
package/src/banner.ts CHANGED
@@ -66,7 +66,7 @@ export class AdbBanner {
66
66
  return this.#device;
67
67
  }
68
68
 
69
- readonly #features: AdbFeature[] = [];
69
+ readonly #features: readonly AdbFeature[] = [];
70
70
  get features() {
71
71
  return this.#features;
72
72
  }
@@ -75,7 +75,7 @@ export class AdbBanner {
75
75
  product: string | undefined,
76
76
  model: string | undefined,
77
77
  device: string | undefined,
78
- features: AdbFeature[],
78
+ features: readonly AdbFeature[],
79
79
  ) {
80
80
  this.#product = product;
81
81
  this.#model = model;
@@ -28,7 +28,9 @@ export class AdbNoneProtocolSubprocessService extends AdbNoneProtocolSpawner {
28
28
  this.#adb = adb;
29
29
  }
30
30
 
31
- async pty(command?: string | string[]): Promise<AdbNoneProtocolPtyProcess> {
31
+ async pty(
32
+ command?: string | readonly string[],
33
+ ): Promise<AdbNoneProtocolPtyProcess> {
32
34
  if (command === undefined) {
33
35
  command = "";
34
36
  } else if (Array.isArray(command)) {
@@ -36,7 +38,8 @@ export class AdbNoneProtocolSubprocessService extends AdbNoneProtocolSpawner {
36
38
  }
37
39
 
38
40
  return new AdbNoneProtocolPtyProcess(
39
- await this.#adb.createSocket(`shell:${command}`),
41
+ // https://github.com/microsoft/typescript/issues/17002
42
+ await this.#adb.createSocket(`shell:${command as string}`),
40
43
  );
41
44
  }
42
45
  }
@@ -28,13 +28,13 @@ export interface AdbNoneProtocolProcess {
28
28
 
29
29
  export class AdbNoneProtocolSpawner {
30
30
  readonly #spawn: (
31
- command: string[],
31
+ command: readonly string[],
32
32
  signal: AbortSignal | undefined,
33
33
  ) => Promise<AdbNoneProtocolProcess>;
34
34
 
35
35
  constructor(
36
36
  spawn: (
37
- command: string[],
37
+ command: readonly string[],
38
38
  signal: AbortSignal | undefined,
39
39
  ) => Promise<AdbNoneProtocolProcess>,
40
40
  ) {
@@ -42,7 +42,7 @@ export class AdbNoneProtocolSpawner {
42
42
  }
43
43
 
44
44
  spawn(
45
- command: string | string[],
45
+ command: string | readonly string[],
46
46
  signal?: AbortSignal,
47
47
  ): Promise<AdbNoneProtocolProcess> {
48
48
  signal?.throwIfAborted();
@@ -54,12 +54,12 @@ export class AdbNoneProtocolSpawner {
54
54
  return this.#spawn(command, signal);
55
55
  }
56
56
 
57
- async spawnWait(command: string | string[]): Promise<Uint8Array> {
57
+ async spawnWait(command: string | readonly string[]): Promise<Uint8Array> {
58
58
  const process = await this.spawn(command);
59
59
  return await process.output.pipeThrough(new ConcatBufferStream());
60
60
  }
61
61
 
62
- async spawnWaitText(command: string | string[]): Promise<string> {
62
+ async spawnWaitText(command: string | readonly string[]): Promise<string> {
63
63
  const process = await this.spawn(command);
64
64
  return await process.output
65
65
  .pipeThrough(new TextDecoderStream())
@@ -32,7 +32,7 @@ export class AdbShellProtocolSubprocessService extends AdbShellProtocolSpawner {
32
32
  }
33
33
 
34
34
  async pty(options?: {
35
- command?: string | string[] | undefined;
35
+ command?: string | readonly string[] | undefined;
36
36
  terminalType?: string;
37
37
  }): Promise<AdbShellProtocolPtyProcess> {
38
38
  let service = "shell,v2,pty";
@@ -26,13 +26,13 @@ export interface AdbShellProtocolProcess {
26
26
 
27
27
  export class AdbShellProtocolSpawner {
28
28
  readonly #spawn: (
29
- command: string[],
29
+ command: readonly string[],
30
30
  signal: AbortSignal | undefined,
31
31
  ) => Promise<AdbShellProtocolProcess>;
32
32
 
33
33
  constructor(
34
34
  spawn: (
35
- command: string[],
35
+ command: readonly string[],
36
36
  signal: AbortSignal | undefined,
37
37
  ) => Promise<AdbShellProtocolProcess>,
38
38
  ) {
@@ -40,7 +40,7 @@ export class AdbShellProtocolSpawner {
40
40
  }
41
41
 
42
42
  spawn(
43
- command: string | string[],
43
+ command: string | readonly string[],
44
44
  signal?: AbortSignal,
45
45
  ): Promise<AdbShellProtocolProcess> {
46
46
  signal?.throwIfAborted();
@@ -53,7 +53,7 @@ export class AdbShellProtocolSpawner {
53
53
  }
54
54
 
55
55
  async spawnWait(
56
- command: string | string[],
56
+ command: string | readonly string[],
57
57
  ): Promise<AdbShellProtocolSpawner.WaitResult<Uint8Array>> {
58
58
  const process = await this.spawn(command);
59
59
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -65,7 +65,7 @@ export class AdbShellProtocolSpawner {
65
65
  }
66
66
 
67
67
  async spawnWaitText(
68
- command: string | string[],
68
+ command: string | readonly string[],
69
69
  ): Promise<AdbShellProtocolSpawner.WaitResult<string>> {
70
70
  const process = await this.spawn(command);
71
71
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -4,7 +4,7 @@ import { decodeUtf8, string, struct, u32 } from "@yume-chan/struct";
4
4
 
5
5
  import { unreachable } from "../../utils/no-op.js";
6
6
 
7
- function encodeAsciiUnchecked(value: string): Uint8Array {
7
+ function encodeAsciiUnchecked(value: string): Uint8Array<ArrayBuffer> {
8
8
  const result = new Uint8Array(value.length);
9
9
  for (let i = 0; i < value.length; i += 1) {
10
10
  result[i] = value.charCodeAt(i);
@@ -139,7 +139,7 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
139
139
  };
140
140
  };
141
141
 
142
- export const ADB_DEFAULT_AUTHENTICATORS: AdbAuthenticator[] = [
142
+ export const ADB_DEFAULT_AUTHENTICATORS: readonly AdbAuthenticator[] = [
143
143
  AdbSignatureAuthenticator,
144
144
  AdbPublicKeyAuthenticator,
145
145
  ];
@@ -140,7 +140,9 @@ export function adbGetPublicKeySize() {
140
140
  return 4 + 4 + ModulusLengthInBytes + ModulusLengthInBytes + 4;
141
141
  }
142
142
 
143
- export function adbGeneratePublicKey(privateKey: Uint8Array): Uint8Array;
143
+ export function adbGeneratePublicKey(
144
+ privateKey: Uint8Array,
145
+ ): Uint8Array<ArrayBuffer>;
144
146
  export function adbGeneratePublicKey(
145
147
  privateKey: Uint8Array,
146
148
  output: Uint8Array,
@@ -287,7 +289,10 @@ export const SHA1_DIGEST_INFO = new Uint8Array([
287
289
  // encrypt the given data with its private key)
288
290
  // However SubtileCrypto.encrypt() doesn't accept 'RSASSA-PKCS1-v1_5' algorithm
289
291
  // So we need to implement the encryption by ourself
290
- export function rsaSign(privateKey: Uint8Array, data: Uint8Array): Uint8Array {
292
+ export function rsaSign(
293
+ privateKey: Uint8Array,
294
+ data: Uint8Array,
295
+ ): Uint8Array<ArrayBuffer> {
291
296
  const [n, d] = rsaParsePrivateKey(privateKey);
292
297
 
293
298
  // PKCS#1 padding
@@ -49,7 +49,7 @@ export const ADB_DAEMON_DEFAULT_FEATURES = /* #__PURE__ */ (() =>
49
49
  "sendrecv_v2_zstd",
50
50
  "sendrecv_v2_dry_run_send",
51
51
  AdbFeature.DelayedAck,
52
- ] as AdbFeature[])();
52
+ ] as readonly AdbFeature[])();
53
53
  export const ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE = 32 * 1024 * 1024;
54
54
 
55
55
  export type AdbDaemonConnection = ReadableWritablePair<
@@ -61,7 +61,7 @@ export interface AdbDaemonAuthenticationOptions {
61
61
  serial: string;
62
62
  connection: AdbDaemonConnection;
63
63
  credentialStore: AdbCredentialStore;
64
- authenticators?: AdbAuthenticator[];
64
+ authenticators?: readonly AdbAuthenticator[];
65
65
  features?: readonly AdbFeature[];
66
66
 
67
67
  /**
@@ -12,6 +12,7 @@ import type {
12
12
  import { AbortController } from "@yume-chan/stream-extra";
13
13
 
14
14
  import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
15
+ import { Adb } from "../adb.js";
15
16
  import { AdbBanner } from "../banner.js";
16
17
  import type { DeviceObserver as DeviceObserverBase } from "../device-observer.js";
17
18
  import type { AdbFeature } from "../features.js";
@@ -36,7 +37,13 @@ export class AdbServerClient {
36
37
  static UnauthorizedError = _UnauthorizedError;
37
38
  static AlreadyConnectedError = _AlreadyConnectedError;
38
39
 
39
- static parseDeviceList(value: string): AdbServerClient.Device[] {
40
+ static parseDeviceList(
41
+ value: string,
42
+ includeStates: readonly AdbServerClient.ConnectionState[] = [
43
+ "device",
44
+ "unauthorized",
45
+ ],
46
+ ): AdbServerClient.Device[] {
40
47
  const devices: AdbServerClient.Device[] = [];
41
48
  for (const line of value.split("\n")) {
42
49
  if (!line) {
@@ -45,8 +52,8 @@ export class AdbServerClient {
45
52
 
46
53
  const parts = line.split(" ").filter(Boolean);
47
54
  const serial = parts[0]!;
48
- const status = parts[1]!;
49
- if (status !== "device" && status !== "unauthorized") {
55
+ const state = parts[1]! as AdbServerClient.ConnectionState;
56
+ if (!includeStates.includes(state)) {
50
57
  continue;
51
58
  }
52
59
 
@@ -76,7 +83,8 @@ export class AdbServerClient {
76
83
  }
77
84
  devices.push({
78
85
  serial,
79
- authenticating: status === "unauthorized",
86
+ state,
87
+ authenticating: state === "unauthorized",
80
88
  product,
81
89
  model,
82
90
  device,
@@ -192,11 +200,16 @@ export class AdbServerClient {
192
200
  *
193
201
  * Equivalent ADB Command: `adb devices -l`
194
202
  */
195
- async getDevices(): Promise<AdbServerClient.Device[]> {
203
+ async getDevices(
204
+ includeStates: readonly AdbServerClient.ConnectionState[] = [
205
+ "device",
206
+ "unauthorized",
207
+ ],
208
+ ): Promise<AdbServerClient.Device[]> {
196
209
  const connection = await this.createConnection("host:devices-l");
197
210
  try {
198
211
  const response = await connection.readString();
199
- return AdbServerClient.parseDeviceList(response);
212
+ return AdbServerClient.parseDeviceList(response, includeStates);
200
213
  } finally {
201
214
  await connection.dispose();
202
215
  }
@@ -206,7 +219,7 @@ export class AdbServerClient {
206
219
  * Monitors device list changes.
207
220
  */
208
221
  async trackDevices(
209
- options?: AdbServerClient.ServerConnectionOptions,
222
+ options?: AdbServerDeviceObserverOwner.Options,
210
223
  ): Promise<AdbServerClient.DeviceObserver> {
211
224
  return this.#observerOwner.createObserver(options);
212
225
  }
@@ -236,7 +249,7 @@ export class AdbServerClient {
236
249
  */
237
250
  async getDeviceFeatures(
238
251
  device: AdbServerClient.DeviceSelector,
239
- ): Promise<{ transportId: bigint; features: AdbFeature[] }> {
252
+ ): Promise<{ transportId: bigint; features: readonly AdbFeature[] }> {
240
253
  // On paper, `host:features` is a host service (device features are cached in host),
241
254
  // so it shouldn't use `createDeviceConnection`,
242
255
  // which is used to forward the service to the device.
@@ -462,6 +475,11 @@ export class AdbServerClient {
462
475
 
463
476
  return transport;
464
477
  }
478
+
479
+ async createAdb(device: AdbServerClient.DeviceSelector) {
480
+ const transport = await this.createTransport(device);
481
+ return new Adb(transport);
482
+ }
465
483
  }
466
484
 
467
485
  export async function raceSignal<T>(
@@ -536,8 +554,12 @@ export namespace AdbServerClient {
536
554
  | { tcp: true }
537
555
  | undefined;
538
556
 
557
+ export type ConnectionState = "unauthorized" | "offline" | "device";
558
+
539
559
  export interface Device {
540
560
  serial: string;
561
+ state: ConnectionState;
562
+ /** @deprecated Use {@link state} instead */
541
563
  authenticating: boolean;
542
564
  product?: string | undefined;
543
565
  model?: string | undefined;
@@ -13,17 +13,28 @@ export function unorderedRemove<T>(array: T[], index: number) {
13
13
  array.length -= 1;
14
14
  }
15
15
 
16
+ interface Observer {
17
+ includeStates: readonly AdbServerClient.ConnectionState[];
18
+ onDeviceAdd: EventEmitter<readonly AdbServerClient.Device[]>;
19
+ onDeviceRemove: EventEmitter<readonly AdbServerClient.Device[]>;
20
+ onListChange: EventEmitter<readonly AdbServerClient.Device[]>;
21
+ onError: EventEmitter<Error>;
22
+ }
23
+
24
+ function filterDeviceStates(
25
+ devices: readonly AdbServerClient.Device[],
26
+ states: readonly AdbServerClient.ConnectionState[],
27
+ ) {
28
+ return devices.filter((device) => states.includes(device.state));
29
+ }
30
+
16
31
  export class AdbServerDeviceObserverOwner {
17
32
  current: readonly AdbServerClient.Device[] = [];
18
33
 
19
34
  readonly #client: AdbServerClient;
35
+
20
36
  #stream: Promise<AdbServerStream> | undefined;
21
- #observers: {
22
- onDeviceAdd: EventEmitter<readonly AdbServerClient.Device[]>;
23
- onDeviceRemove: EventEmitter<readonly AdbServerClient.Device[]>;
24
- onListChange: EventEmitter<readonly AdbServerClient.Device[]>;
25
- onError: EventEmitter<Error>;
26
- }[] = [];
37
+ #observers: Observer[] = [];
27
38
 
28
39
  constructor(client: AdbServerClient) {
29
40
  this.#client = client;
@@ -52,17 +63,33 @@ export class AdbServerDeviceObserverOwner {
52
63
 
53
64
  if (added.length) {
54
65
  for (const observer of this.#observers) {
55
- observer.onDeviceAdd.fire(added);
66
+ const filtered = filterDeviceStates(
67
+ added,
68
+ observer.includeStates,
69
+ );
70
+ if (filtered.length) {
71
+ observer.onDeviceAdd.fire(filtered);
72
+ }
56
73
  }
57
74
  }
58
75
  if (removed.length) {
59
76
  for (const observer of this.#observers) {
60
- observer.onDeviceRemove.fire(removed);
77
+ const filtered = filterDeviceStates(
78
+ removed,
79
+ observer.includeStates,
80
+ );
81
+ if (filtered.length) {
82
+ observer.onDeviceRemove.fire(removed);
83
+ }
61
84
  }
62
85
  }
63
86
 
64
87
  for (const observer of this.#observers) {
65
- observer.onListChange.fire(this.current);
88
+ const filtered = filterDeviceStates(
89
+ this.current,
90
+ observer.includeStates,
91
+ );
92
+ observer.onListChange.fire(filtered);
66
93
  }
67
94
  }
68
95
 
@@ -104,10 +131,11 @@ export class AdbServerDeviceObserverOwner {
104
131
  }
105
132
 
106
133
  async createObserver(
107
- options?: AdbServerClient.ServerConnectionOptions,
134
+ options?: AdbServerDeviceObserverOwner.Options,
108
135
  ): Promise<AdbServerClient.DeviceObserver> {
109
136
  options?.signal?.throwIfAborted();
110
137
 
138
+ let current: readonly AdbServerClient.Device[] = [];
111
139
  const onDeviceAdd = new EventEmitter<
112
140
  readonly AdbServerClient.Device[]
113
141
  >();
@@ -119,13 +147,27 @@ export class AdbServerDeviceObserverOwner {
119
147
  >();
120
148
  const onError = new StickyEventEmitter<Error>();
121
149
 
122
- const observer = { onDeviceAdd, onDeviceRemove, onListChange, onError };
150
+ const includeStates = options?.includeStates ?? [
151
+ "device",
152
+ "unauthorized",
153
+ ];
154
+ const observer = {
155
+ includeStates,
156
+ onDeviceAdd,
157
+ onDeviceRemove,
158
+ onListChange,
159
+ onError,
160
+ } satisfies Observer;
123
161
  // Register `observer` before `#connect`.
124
162
  // So `#handleObserverStop` knows if there is any observer.
125
163
  this.#observers.push(observer);
126
164
 
165
+ // Read the filtered `current` value from `onListChange` event
166
+ onListChange.event((value) => (current = value));
167
+
127
168
  let stream: AdbServerStream;
128
169
  if (!this.#stream) {
170
+ // `#connect` will initialize `onListChange` and `current`
129
171
  this.#stream = this.#connect();
130
172
 
131
173
  try {
@@ -136,7 +178,8 @@ export class AdbServerDeviceObserverOwner {
136
178
  }
137
179
  } else {
138
180
  stream = await this.#stream;
139
- onListChange.fire(this.current);
181
+ // Initialize `onListChange` and `current` ourselves
182
+ onListChange.fire(filterDeviceStates(this.current, includeStates));
140
183
  }
141
184
 
142
185
  const ref = new Ref(options);
@@ -156,17 +199,21 @@ export class AdbServerDeviceObserverOwner {
156
199
  options.signal.addEventListener("abort", () => void stop());
157
200
  }
158
201
 
159
- // eslint-disable-next-line @typescript-eslint/no-this-alias
160
- const _this = this;
161
202
  return {
162
203
  onDeviceAdd: onDeviceAdd.event,
163
204
  onDeviceRemove: onDeviceRemove.event,
164
205
  onListChange: onListChange.event,
165
206
  onError: onError.event,
166
207
  get current() {
167
- return _this.current;
208
+ return current;
168
209
  },
169
210
  stop,
170
211
  };
171
212
  }
172
213
  }
214
+
215
+ export namespace AdbServerDeviceObserverOwner {
216
+ export interface Options extends AdbServerClient.ServerConnectionOptions {
217
+ includeStates?: readonly AdbServerClient.ConnectionState[];
218
+ }
219
+ }
@@ -30,7 +30,7 @@ export const ADB_SERVER_DEFAULT_FEATURES = /* #__PURE__ */ (() =>
30
30
  "sendrecv_v2_lz4",
31
31
  "sendrecv_v2_zstd",
32
32
  "sendrecv_v2_dry_run_send",
33
- ] as AdbFeature[])();
33
+ ] as readonly AdbFeature[])();
34
34
 
35
35
  export class AdbServerTransport implements AdbTransport {
36
36
  #client: AdbServerClient;
@@ -0,0 +1,9 @@
1
+ export function toLocalUint8Array(value: Uint8Array): Uint8Array<ArrayBuffer> {
2
+ if (value.buffer instanceof ArrayBuffer) {
3
+ return value as Uint8Array<ArrayBuffer>;
4
+ }
5
+
6
+ const copy = new Uint8Array(value.length);
7
+ copy.set(value);
8
+ return copy;
9
+ }
@@ -47,7 +47,7 @@ export function calculateBase64EncodedLength(
47
47
  * @param input The input buffer
48
48
  * @returns The encoded output buffer
49
49
  */
50
- export function encodeBase64(input: Uint8Array): Uint8Array;
50
+ export function encodeBase64(input: Uint8Array): Uint8Array<ArrayBuffer>;
51
51
  /**
52
52
  * Encode the given input into base64 and write it to the output buffer.
53
53
  *
@@ -295,7 +295,7 @@ function encodeBackward(
295
295
  }
296
296
  }
297
297
 
298
- export function decodeBase64(input: string): Uint8Array {
298
+ export function decodeBase64(input: string): Uint8Array<ArrayBuffer> {
299
299
  let padding: number;
300
300
  if (input[input.length - 2] === "=") {
301
301
  padding = 2;
@@ -1,4 +1,5 @@
1
1
  export { decodeUtf8, encodeUtf8 } from "@yume-chan/struct";
2
+ export * from "./array-buffer.js";
2
3
  export * from "./auto-reset-event.js";
3
4
  export * from "./base64.js";
4
5
  export * from "./hex.js";