refactor: extract common types to @yume-chan/async package

This commit is contained in:
Simon Chan 2024-11-20 06:37:09 +08:00
parent 6cb0a589fa
commit db8466f6ee
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
58 changed files with 337 additions and 267 deletions

View file

@ -0,0 +1,5 @@
---
"@yume-chan/scrcpy-decoder-tinyh264": patch
---
Add support for rendering into `OffscreenCanvas`

View file

@ -0,0 +1,8 @@
---
"@yume-chan/adb": patch
"@yume-chan/adb-scrcpy": patch
"@yume-chan/scrcpy": patch
"@yume-chan/struct": patch
---
Rewrite the struct API completely

View file

@ -0,0 +1,5 @@
---
"@yume-chan/adb-daemon-webusb": patch
---
Accept standard `USBDeviceFilter` type and fill in default interface filters automatically

View file

@ -0,0 +1,6 @@
---
"@yume-chan/adb": patch
"@yume-chan/adb-credential-web": patch
---
Add common interface for device observers

View file

@ -0,0 +1,5 @@
---
"@yume-chan/scrcpy-decoder-webcodecs": patch
---
Fix H.265 rendering in Microsoft Edge

View file

@ -0,0 +1,5 @@
---
"@yume-chan/adb-daemon-webusb": patch
---
Throw `DeviceBusyError` when interface can't be claimed

View file

@ -0,0 +1,7 @@
---
"@yume-chan/adb": patch
"@yume-chan/scrcpy": patch
"@yume-chan/struct": patch
---
Improve tree-shaking by removing TypeScript enum and namespace

View file

@ -0,0 +1,5 @@
---
"@yume-chan/scrcpy-decoder-webcodecs": patch
---
Add a `snapshot` method to convert the last rendered frame into PNG

View file

@ -0,0 +1,5 @@
---
"@yume-chan/adb-scrcpy": patch
---
Fix automatically switching to forward tunnel when reverse tunnel is not supported

View file

@ -41,7 +41,7 @@
"source-map-support": "^0.5.21" "source-map-support": "^0.5.21"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",
"prettier": "^3.3.3", "prettier": "^3.3.3",

View file

@ -5,10 +5,5 @@
"ESNext", "ESNext",
"DOM" "DOM"
] ]
},
"references": [
{
"path": "../adb/tsconfig.build.json"
} }
]
} }

View file

@ -2,6 +2,12 @@
"references": [ "references": [
{ {
"path": "./tsconfig.build.json" "path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.test.json"
},
{
"path": "../adb/tsconfig.build.json"
} }
] ]
} }

View file

@ -39,7 +39,7 @@
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -17,17 +17,17 @@ export class AdbDaemonWebUsbDeviceObserver
#filters: UsbInterfaceFilter[]; #filters: UsbInterfaceFilter[];
#usbManager: USB; #usbManager: USB;
#deviceAdded = new EventEmitter<AdbDaemonWebUsbDevice[]>(); #onError = new EventEmitter<Error>();
deviceAdded = this.#deviceAdded.event; onError = this.#onError.event;
#deviceRemoved = new EventEmitter<AdbDaemonWebUsbDevice[]>(); #onDeviceAdd = new EventEmitter<AdbDaemonWebUsbDevice[]>();
deviceRemoved = this.#deviceRemoved.event; onDeviceAdd = this.#onDeviceAdd.event;
#deviceChanged = new EventEmitter<AdbDaemonWebUsbDevice[]>(); #onDeviceRemove = new EventEmitter<AdbDaemonWebUsbDevice[]>();
deviceChanged = this.#deviceChanged.event; onDeviceRemove = this.#onDeviceRemove.event;
#listChanged = new EventEmitter<AdbDaemonWebUsbDevice[]>(); #onListChange = new EventEmitter<AdbDaemonWebUsbDevice[]>();
listChanged = this.#listChanged.event; onListChange = this.#onListChange.event;
current: AdbDaemonWebUsbDevice[] = []; current: AdbDaemonWebUsbDevice[] = [];
@ -49,9 +49,9 @@ export class AdbDaemonWebUsbDeviceObserver
this.#filters, this.#filters,
this.#usbManager, this.#usbManager,
); );
this.#deviceAdded.fire([device]); this.#onDeviceAdd.fire([device]);
this.current.push(device); this.current.push(device);
this.#listChanged.fire(this.current); this.#onListChange.fire(this.current);
}; };
#handleDisconnect = (e: USBConnectionEvent) => { #handleDisconnect = (e: USBConnectionEvent) => {
@ -60,10 +60,10 @@ export class AdbDaemonWebUsbDeviceObserver
); );
if (index !== -1) { if (index !== -1) {
const device = this.current[index]!; const device = this.current[index]!;
this.#deviceRemoved.fire([device]); this.#onDeviceRemove.fire([device]);
this.current[index] = this.current[this.current.length - 1]!; this.current[index] = this.current[this.current.length - 1]!;
this.current.length -= 1; this.current.length -= 1;
this.#listChanged.fire(this.current); this.#onListChange.fire(this.current);
} }
}; };

View file

@ -33,7 +33,7 @@
}, },
"dependencies": { "dependencies": {
"@yume-chan/adb": "workspace:^", "@yume-chan/adb": "workspace:^",
"@yume-chan/async": "^4.0.0", "@yume-chan/async": "^4.0.2",
"@yume-chan/event": "workspace:^", "@yume-chan/event": "workspace:^",
"@yume-chan/scrcpy": "workspace:^", "@yume-chan/scrcpy": "workspace:^",
"@yume-chan/stream-extra": "workspace:^", "@yume-chan/stream-extra": "workspace:^",

View file

@ -1,5 +1,6 @@
import type { Adb, AdbSocket } from "@yume-chan/adb"; import type { Adb, AdbSocket } from "@yume-chan/adb";
import { AdbReverseNotSupportedError, NOOP } from "@yume-chan/adb"; import { AdbReverseNotSupportedError, NOOP } from "@yume-chan/adb";
import type { MaybePromiseLike } from "@yume-chan/async";
import { delay } from "@yume-chan/async"; import { delay } from "@yume-chan/async";
import type { Disposable } from "@yume-chan/event"; import type { Disposable } from "@yume-chan/event";
import type { import type {
@ -13,7 +14,6 @@ import {
BufferedReadableStream, BufferedReadableStream,
PushReadableStream, PushReadableStream,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
export interface AdbScrcpyConnectionOptions { export interface AdbScrcpyConnectionOptions {
scid: number; scid: number;

View file

@ -33,11 +33,12 @@
}, },
"dependencies": { "dependencies": {
"@yume-chan/adb": "workspace:^", "@yume-chan/adb": "workspace:^",
"@yume-chan/async": "^4.0.2",
"@yume-chan/stream-extra": "workspace:^", "@yume-chan/stream-extra": "workspace:^",
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",
"prettier": "^3.3.3", "prettier": "^3.3.3",

View file

@ -2,12 +2,12 @@ import type { AddressInfo, SocketConnectOpts } from "net";
import { Server, Socket } from "net"; import { Server, Socket } from "net";
import type { AdbIncomingSocketHandler, AdbServerClient } from "@yume-chan/adb"; import type { AdbIncomingSocketHandler, AdbServerClient } from "@yume-chan/adb";
import type { MaybePromiseLike } from "@yume-chan/async";
import { import {
MaybeConsumable, MaybeConsumable,
PushReadableStream, PushReadableStream,
tryClose, tryClose,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
function nodeSocketToConnection( function nodeSocketToConnection(
socket: Socket, socket: Socket,

View file

@ -32,14 +32,14 @@
"test": "run-test" "test": "run-test"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.0", "@yume-chan/async": "^4.0.2",
"@yume-chan/event": "workspace:^", "@yume-chan/event": "workspace:^",
"@yume-chan/no-data-view": "workspace:^", "@yume-chan/no-data-view": "workspace:^",
"@yume-chan/stream-extra": "workspace:^", "@yume-chan/stream-extra": "workspace:^",
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -1,9 +1,9 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { import type {
MaybeConsumable, MaybeConsumable,
ReadableWritablePair, ReadableWritablePair,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import type { AdbBanner } from "./banner.js"; import type { AdbBanner } from "./banner.js";
import type { AdbFrameBuffer } from "./commands/index.js"; import type { AdbFrameBuffer } from "./commands/index.js";

View file

@ -1,9 +1,9 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { import type {
MaybeConsumable, MaybeConsumable,
ReadableStream, ReadableStream,
WritableStream, WritableStream,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import type { Adb, AdbSocket } from "../../../adb.js"; import type { Adb, AdbSocket } from "../../../adb.js";

View file

@ -1,6 +1,6 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver } from "@yume-chan/async";
import type { Disposable } from "@yume-chan/event"; import type { Disposable } from "@yume-chan/event";
import type { MaybePromiseLike } from "@yume-chan/struct";
import { EmptyUint8Array } from "@yume-chan/struct"; import { EmptyUint8Array } from "@yume-chan/struct";
import { import {

View file

@ -1,5 +1,5 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra"; import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import type { AdbPacketData, AdbPacketInit } from "./packet.js"; import type { AdbPacketData, AdbPacketInit } from "./packet.js";

View file

@ -1,3 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver } from "@yume-chan/async";
import type { ReadableWritablePair } from "@yume-chan/stream-extra"; import type { ReadableWritablePair } from "@yume-chan/stream-extra";
import { import {
@ -5,7 +6,6 @@ import {
Consumable, Consumable,
WritableStream, WritableStream,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import { decodeUtf8, encodeUtf8 } from "@yume-chan/struct"; import { decodeUtf8, encodeUtf8 } from "@yume-chan/struct";
import type { import type {

View file

@ -1,10 +1,11 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { Event } from "@yume-chan/event"; import type { Event } from "@yume-chan/event";
import type { MaybePromiseLike } from "@yume-chan/struct";
export interface DeviceObserver<T> { export interface DeviceObserver<T> {
deviceAdded: Event<T[]>; onError: Event<Error>;
deviceRemoved: Event<T[]>; onDeviceAdd: Event<T[]>;
listChanged: Event<T[]>; onDeviceRemove: Event<T[]>;
onListChange: Event<T[]>;
current: T[]; current: T[];
stop(): MaybePromiseLike<void>; stop(): MaybePromiseLike<void>;
} }

View file

@ -1,5 +1,6 @@
// cspell:ignore tport // cspell:ignore tport
import type { MaybePromiseLike } from "@yume-chan/async";
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver } from "@yume-chan/async";
import { EventEmitter } from "@yume-chan/event"; import { EventEmitter } from "@yume-chan/event";
import { getUint64LittleEndian } from "@yume-chan/no-data-view"; import { getUint64LittleEndian } from "@yume-chan/no-data-view";
@ -14,7 +15,6 @@ import {
tryCancel, tryCancel,
tryClose, tryClose,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import { import {
bipedal, bipedal,
decodeUtf8, decodeUtf8,
@ -297,11 +297,13 @@ export class AdbServerClient {
const connection = await this.createConnection("host:track-devices-l"); const connection = await this.createConnection("host:track-devices-l");
let current: AdbServerClient.Device[] = []; let current: AdbServerClient.Device[] = [];
const deviceAddedEvent = new EventEmitter<AdbServerClient.Device[]>(); const onError = new EventEmitter<Error>();
const deviceRemovedEvent = new EventEmitter<AdbServerClient.Device[]>(); const onDeviceAdd = new EventEmitter<AdbServerClient.Device[]>();
const listChangedEvent = new EventEmitter<AdbServerClient.Device[]>(); const onDeviceRemove = new EventEmitter<AdbServerClient.Device[]>();
const onListChange = new EventEmitter<AdbServerClient.Device[]>();
void (async () => { void (async () => {
try {
while (true) { while (true) {
const response = await connection.readString(); const response = await connection.readString();
const next = AdbServerClient.parseDeviceList(response); const next = AdbServerClient.parseDeviceList(response);
@ -322,21 +324,25 @@ export class AdbServerClient {
} }
if (added.length) { if (added.length) {
deviceAddedEvent.fire(added); onDeviceAdd.fire(added);
} }
if (current.length) { if (current.length) {
deviceRemovedEvent.fire(current); onDeviceRemove.fire(current);
} }
current = next; current = next;
listChangedEvent.fire(current); onListChange.fire(current);
}
} catch (e) {
onError.fire(e as Error);
} }
})(); })();
return { return {
deviceAdded: deviceAddedEvent.event, onError: onError.event,
deviceRemoved: deviceRemovedEvent.event, onDeviceAdd: onDeviceAdd.event,
listChanged: listChangedEvent.event, onDeviceRemove: onDeviceRemove.event,
onListChange: onListChange.event,
get current() { get current() {
return current; return current;
}, },

View file

@ -1,3 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver } from "@yume-chan/async";
import { AbortController } from "@yume-chan/stream-extra"; import { AbortController } from "@yume-chan/stream-extra";
@ -95,7 +96,7 @@ export class AdbServerTransport implements AdbTransport {
await this.#client.connector.clearReverseTunnels(); await this.#client.connector.clearReverseTunnels();
} }
close(): void | Promise<void> { close(): MaybePromiseLike<void> {
this.#closed.resolve(); this.#closed.resolve();
this.#waitAbortController.abort(); this.#waitAbortController.abort();
} }

View file

@ -37,7 +37,7 @@
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -33,10 +33,10 @@
"test": "run-test" "test": "run-test"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.0" "@yume-chan/async": "^4.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -31,6 +31,6 @@
"gh-release-fetch": "^4.0.3" "gh-release-fetch": "^4.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0" "@types/node": "^22.9.1"
} }
} }

View file

@ -30,7 +30,7 @@
"test": "run-test" "test": "run-test"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -33,7 +33,7 @@
"prepublishOnly": "npm run build" "prepublishOnly": "npm run build"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.0", "@yume-chan/async": "^4.0.2",
"@yume-chan/event": "workspace:^", "@yume-chan/event": "workspace:^",
"@yume-chan/scrcpy": "workspace:^", "@yume-chan/scrcpy": "workspace:^",
"@yume-chan/stream-extra": "workspace:^", "@yume-chan/stream-extra": "workspace:^",

View file

@ -33,6 +33,7 @@
"prepublishOnly": "npm run build" "prepublishOnly": "npm run build"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.2",
"@yume-chan/event": "workspace:^", "@yume-chan/event": "workspace:^",
"@yume-chan/no-data-view": "workspace:^", "@yume-chan/no-data-view": "workspace:^",
"@yume-chan/scrcpy": "workspace:^", "@yume-chan/scrcpy": "workspace:^",

View file

@ -1,5 +1,7 @@
import type { MaybePromiseLike } from "@yume-chan/async";
export interface WebCodecsVideoDecoderRenderer { export interface WebCodecsVideoDecoderRenderer {
setSize(width: number, height: number): void; setSize(width: number, height: number): void;
draw(frame: VideoFrame): Promise<void>; draw(frame: VideoFrame): MaybePromiseLike<void>;
} }

View file

@ -33,13 +33,13 @@
"test": "run-test" "test": "run-test"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.0", "@yume-chan/async": "^4.0.2",
"@yume-chan/no-data-view": "workspace:^", "@yume-chan/no-data-view": "workspace:^",
"@yume-chan/stream-extra": "workspace:^", "@yume-chan/stream-extra": "workspace:^",
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -1,3 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { import {
getUint16BigEndian, getUint16BigEndian,
getUint32BigEndian, getUint32BigEndian,
@ -12,7 +13,7 @@ import {
StructDeserializeStream, StructDeserializeStream,
TransformStream, TransformStream,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { AsyncExactReadable, MaybePromiseLike } from "@yume-chan/struct"; import type { AsyncExactReadable } from "@yume-chan/struct";
import { decodeUtf8 } from "@yume-chan/struct"; import { decodeUtf8 } from "@yume-chan/struct";
import type { import type {

View file

@ -1,5 +1,5 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { ReadableStream } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import type { ScrcpyScrollController } from "../1_16/index.js"; import type { ScrcpyScrollController } from "../1_16/index.js";
import { ScrcpyOptions1_21 } from "../1_21.js"; import { ScrcpyOptions1_21 } from "../1_21.js";

View file

@ -1,10 +1,11 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { getUint32BigEndian } from "@yume-chan/no-data-view"; import { getUint32BigEndian } from "@yume-chan/no-data-view";
import type { ReadableStream } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra";
import { import {
BufferedReadableStream, BufferedReadableStream,
PushReadableStream, PushReadableStream,
} from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra";
import type { MaybePromiseLike, StructInit } from "@yume-chan/struct"; import type { StructInit } from "@yume-chan/struct";
import { struct, u16, u32, u64, u8 } from "@yume-chan/struct"; import { struct, u16, u32, u64, u8 } from "@yume-chan/struct";
import type { import type {

View file

@ -1,5 +1,5 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { ReadableStream } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra";
import type { MaybePromiseLike } from "@yume-chan/struct";
import { ScrcpyOptions1_21 } from "./1_21.js"; import { ScrcpyOptions1_21 } from "./1_21.js";
import { ScrcpyOptions2_0 } from "./2_0.js"; import { ScrcpyOptions2_0 } from "./2_0.js";

View file

@ -1,5 +1,6 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra"; import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
import type { AsyncExactReadable, MaybePromiseLike } from "@yume-chan/struct"; import type { AsyncExactReadable } from "@yume-chan/struct";
import type { import type {
ScrcpyBackOrScreenOnControlMessage, ScrcpyBackOrScreenOnControlMessage,

View file

@ -32,11 +32,11 @@
"test": "run-test" "test": "run-test"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.0", "@yume-chan/async": "^4.0.2",
"@yume-chan/struct": "workspace:^" "@yume-chan/struct": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -1,4 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/struct"; import type { MaybePromiseLike } from "@yume-chan/async";
import { StructEmptyError } from "@yume-chan/struct"; import { StructEmptyError } from "@yume-chan/struct";
import { BufferedReadableStream } from "./buffered.js"; import { BufferedReadableStream } from "./buffered.js";

View file

@ -1,4 +1,5 @@
import type { AsyncExactReadable, MaybePromiseLike } from "@yume-chan/struct"; import type { MaybePromiseLike } from "@yume-chan/async";
import type { AsyncExactReadable } from "@yume-chan/struct";
import { bipedal, ExactReadableEndedError } from "@yume-chan/struct"; import { bipedal, ExactReadableEndedError } from "@yume-chan/struct";
import { PushReadableStream } from "./push-readable.js"; import { PushReadableStream } from "./push-readable.js";

View file

@ -1,4 +1,4 @@
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver, isPromiseLike } from "@yume-chan/async";
import type { import type {
QueuingStrategy, QueuingStrategy,
@ -12,14 +12,8 @@ import {
import type { Task } from "./task.js"; import type { Task } from "./task.js";
import { createTask } from "./task.js"; import { createTask } from "./task.js";
function isPromiseLike(value: unknown): value is PromiseLike<unknown> { // Workaround https://github.com/evanw/esbuild/issues/3923
return typeof value === "object" && value !== null && "then" in value; class WritableStream<in T> extends NativeWritableStream<Consumable<T>> {
}
export class Consumable<T> {
static readonly WritableStream = class WritableStream<
in T,
> extends NativeWritableStream<Consumable<T>> {
static async write<T>( static async write<T>(
writer: WritableStreamDefaultWriter<Consumable<T>>, writer: WritableStreamDefaultWriter<Consumable<T>>,
value: T, value: T,
@ -68,11 +62,9 @@ export class Consumable<T> {
wrappedStrategy, wrappedStrategy,
); );
} }
}; }
static readonly ReadableStream = class ReadableStream< class ReadableStream<T> extends NativeReadableStream<Consumable<T>> {
T,
> extends NativeReadableStream<Consumable<T>> {
static async enqueue<T>( static async enqueue<T>(
controller: { enqueue: (chunk: Consumable<T>) => void }, controller: { enqueue: (chunk: Consumable<T>) => void },
chunk: T, chunk: T,
@ -130,7 +122,12 @@ export class Consumable<T> {
wrappedStrategy, wrappedStrategy,
); );
} }
}; }
export class Consumable<T> {
static readonly WritableStream = WritableStream;
static readonly ReadableStream = ReadableStream;
readonly #task: Task; readonly #task: Task;
readonly #resolver: PromiseResolver<void>; readonly #resolver: PromiseResolver<void>;

View file

@ -1,5 +1,5 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { PromiseResolver } from "@yume-chan/async"; import { PromiseResolver } from "@yume-chan/async";
import type { MaybePromiseLike } from "@yume-chan/struct";
import type { import type {
QueuingStrategy, QueuingStrategy,

View file

@ -75,7 +75,7 @@ export class PushReadableStream<T> extends ReadableStream<T> {
// But in `PushReadableStream`, `enqueue` is an async function, // But in `PushReadableStream`, `enqueue` is an async function,
// the producer can't just check `abortSignal.aborted` // the producer can't just check `abortSignal.aborted`
// before calling `enqueue`, as it might change when waiting // before calling `enqueue`, as it might change when waiting
// for the backpressure to be resolved. // for the backpressure to be reduced.
// //
// So IMO it's better to handle this for the producer // So IMO it's better to handle this for the producer
// by simply ignoring the `enqueue` call. // by simply ignoring the `enqueue` call.
@ -85,7 +85,7 @@ export class PushReadableStream<T> extends ReadableStream<T> {
// they called `close` or `error`. // they called `close` or `error`.
// //
// Obviously, the producer should listen to the `abortSignal` and // Obviously, the producer should listen to the `abortSignal` and
// stop producing, but most pushing data sources can't be stopped. // stop producing, but most pushing data sources don't support that.
logger?.({ logger?.({
source: "producer", source: "producer",
operation: "enqueue", operation: "enqueue",

View file

@ -1,4 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/struct"; import type { MaybePromiseLike } from "@yume-chan/async";
import type { import type {
QueuingStrategy, QueuingStrategy,

View file

@ -1,4 +1,4 @@
import type { MaybePromiseLike } from "@yume-chan/struct"; import type { MaybePromiseLike } from "@yume-chan/async";
import type { TransformStream, WritableStreamDefaultWriter } from "./stream.js"; import type { TransformStream, WritableStreamDefaultWriter } from "./stream.js";
import { WritableStream } from "./stream.js"; import { WritableStream } from "./stream.js";

View file

@ -34,10 +34,11 @@
"test": "run-test" "test": "run-test"
}, },
"dependencies": { "dependencies": {
"@yume-chan/async": "^4.0.2",
"@yume-chan/no-data-view": "workspace:^" "@yume-chan/no-data-view": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"@yume-chan/eslint-config": "workspace:^", "@yume-chan/eslint-config": "workspace:^",
"@yume-chan/test-runner": "workspace:^", "@yume-chan/test-runner": "workspace:^",
"@yume-chan/tsconfig": "workspace:^", "@yume-chan/tsconfig": "workspace:^",

View file

@ -1,8 +1,5 @@
import type { MaybePromiseLike } from "./utils.js"; import type { MaybePromiseLike } from "@yume-chan/async";
import { isPromiseLike } from "@yume-chan/async";
function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {
return typeof value === "object" && value !== null && "then" in value;
}
function advance<T>( function advance<T>(
iterator: Iterator<unknown, T, unknown>, iterator: Iterator<unknown, T, unknown>,

View file

@ -1,5 +1,6 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import type { AsyncExactReadable } from "./readable.js"; import type { AsyncExactReadable } from "./readable.js";
import type { MaybePromiseLike } from "./utils.js";
export interface SerializeContext { export interface SerializeContext {
buffer: Uint8Array; buffer: Uint8Array;

View file

@ -1,6 +1,6 @@
// TODO: allow over reading (returning a `Uint8Array`, an `offset` and a `length`) to avoid copying // TODO: allow over reading (returning a `Uint8Array`, an `offset` and a `length`) to avoid copying
import type { MaybePromiseLike } from "./utils.js"; import type { MaybePromiseLike } from "@yume-chan/async";
export class ExactReadableEndedError extends Error { export class ExactReadableEndedError extends Error {
constructor() { constructor() {

View file

@ -1,8 +1,9 @@
import type { MaybePromiseLike } from "@yume-chan/async";
import { bipedal } from "./bipedal.js"; import { bipedal } from "./bipedal.js";
import type { DeserializeContext, Field, SerializeContext } from "./field.js"; import type { DeserializeContext, Field, SerializeContext } from "./field.js";
import type { AsyncExactReadable, ExactReadable } from "./readable.js"; import type { AsyncExactReadable, ExactReadable } from "./readable.js";
import { ExactReadableEndedError } from "./readable.js"; import { ExactReadableEndedError } from "./readable.js";
import type { MaybePromiseLike } from "./utils.js";
export type FieldsType< export type FieldsType<
T extends Record<string, Field<unknown, string, unknown>>, T extends Record<string, Field<unknown, string, unknown>>,

View file

@ -38,7 +38,3 @@ export function decodeUtf8(buffer: ArrayBufferView | ArrayBuffer): string {
// but this method is not for stream mode, so the instance can be reused // but this method is not for stream mode, so the instance can be reused
return SharedDecoder.decode(buffer); return SharedDecoder.decode(buffer);
} }
export type MaybePromise<T> = T | Promise<T>;
export type MaybePromiseLike<T> = T | PromiseLike<T>;

101
pnpm-lock.yaml generated
View file

@ -34,8 +34,8 @@ importers:
version: 0.5.21 version: 0.5.21
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -52,8 +52,8 @@ importers:
libraries/adb: libraries/adb:
dependencies: dependencies:
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
'@yume-chan/event': '@yume-chan/event':
specifier: workspace:^ specifier: workspace:^
version: link:../event version: link:../event
@ -68,8 +68,8 @@ importers:
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -124,8 +124,8 @@ importers:
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -148,8 +148,8 @@ importers:
specifier: workspace:^ specifier: workspace:^
version: link:../adb version: link:../adb
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
'@yume-chan/event': '@yume-chan/event':
specifier: workspace:^ specifier: workspace:^
version: link:../event version: link:../event
@ -181,6 +181,9 @@ importers:
'@yume-chan/adb': '@yume-chan/adb':
specifier: workspace:^ specifier: workspace:^
version: link:../adb version: link:../adb
'@yume-chan/async':
specifier: ^4.0.2
version: 4.0.2
'@yume-chan/stream-extra': '@yume-chan/stream-extra':
specifier: workspace:^ specifier: workspace:^
version: link:../stream-extra version: link:../stream-extra
@ -189,8 +192,8 @@ importers:
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -217,8 +220,8 @@ importers:
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -257,12 +260,12 @@ importers:
libraries/event: libraries/event:
dependencies: dependencies:
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -286,14 +289,14 @@ importers:
version: 4.0.3 version: 4.0.3
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
libraries/no-data-view: libraries/no-data-view:
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -334,8 +337,8 @@ importers:
libraries/scrcpy: libraries/scrcpy:
dependencies: dependencies:
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
'@yume-chan/no-data-view': '@yume-chan/no-data-view':
specifier: workspace:^ specifier: workspace:^
version: link:../no-data-view version: link:../no-data-view
@ -347,8 +350,8 @@ importers:
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -368,8 +371,8 @@ importers:
libraries/scrcpy-decoder-tinyh264: libraries/scrcpy-decoder-tinyh264:
dependencies: dependencies:
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
'@yume-chan/event': '@yume-chan/event':
specifier: workspace:^ specifier: workspace:^
version: link:../event version: link:../event
@ -404,6 +407,9 @@ importers:
libraries/scrcpy-decoder-webcodecs: libraries/scrcpy-decoder-webcodecs:
dependencies: dependencies:
'@yume-chan/async':
specifier: ^4.0.2
version: 4.0.2
'@yume-chan/event': '@yume-chan/event':
specifier: workspace:^ specifier: workspace:^
version: link:../event version: link:../event
@ -436,15 +442,15 @@ importers:
libraries/stream-extra: libraries/stream-extra:
dependencies: dependencies:
'@yume-chan/async': '@yume-chan/async':
specifier: ^4.0.0 specifier: ^4.0.2
version: 4.0.0 version: 4.0.2
'@yume-chan/struct': '@yume-chan/struct':
specifier: workspace:^ specifier: workspace:^
version: link:../struct version: link:../struct
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -463,13 +469,16 @@ importers:
libraries/struct: libraries/struct:
dependencies: dependencies:
'@yume-chan/async':
specifier: ^4.0.2
version: 4.0.2
'@yume-chan/no-data-view': '@yume-chan/no-data-view':
specifier: workspace:^ specifier: workspace:^
version: link:../no-data-view version: link:../no-data-view
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
'@yume-chan/eslint-config': '@yume-chan/eslint-config':
specifier: workspace:^ specifier: workspace:^
version: link:../../toolchain/eslint-config version: link:../../toolchain/eslint-config
@ -492,8 +501,8 @@ importers:
specifier: ^9.15.0 specifier: ^9.15.0
version: 9.15.0 version: 9.15.0
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
eslint: eslint:
specifier: ^9.15.0 specifier: ^9.15.0
version: 9.15.0 version: 9.15.0
@ -514,8 +523,8 @@ importers:
toolchain/package-lint: toolchain/package-lint:
dependencies: dependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
json5: json5:
specifier: ^2.2.3 specifier: ^2.2.3
version: 2.2.3 version: 2.2.3
@ -523,8 +532,8 @@ importers:
toolchain/test-runner: toolchain/test-runner:
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.9.0 specifier: ^22.9.1
version: 22.9.0 version: 22.9.1
typescript: typescript:
specifier: ^5.6.3 specifier: ^5.6.3
version: 5.6.3 version: 5.6.3
@ -694,8 +703,8 @@ packages:
'@types/node@12.20.55': '@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
'@types/node@22.9.0': '@types/node@22.9.1':
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} resolution: {integrity: sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==}
'@types/w3c-web-usb@1.0.10': '@types/w3c-web-usb@1.0.10':
resolution: {integrity: sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==} resolution: {integrity: sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==}
@ -790,8 +799,8 @@ packages:
resolution: {integrity: sha512-mBvWew1kZJHfNQVVfVllMjUDwCGN9apPa0t4/z1zaUJ9MzpXjRL3w8fsfJKB8gHN/h4rik9HneKfDbh2fErN+w==} resolution: {integrity: sha512-mBvWew1kZJHfNQVVfVllMjUDwCGN9apPa0t4/z1zaUJ9MzpXjRL3w8fsfJKB8gHN/h4rik9HneKfDbh2fErN+w==}
engines: {node: ^14.14.0 || >=16.0.0} engines: {node: ^14.14.0 || >=16.0.0}
'@yume-chan/async@4.0.0': '@yume-chan/async@4.0.2':
resolution: {integrity: sha512-T4DOnvaVqrx+PQh8bESdS6y2ozii7M0isJ5MpGU0girfz9kmwOaJ+rF1oeTJGZ0k+v92+eo/q6SpJjcjnO9tuQ==} resolution: {integrity: sha512-YP5Hg4DZoq6CXzeTsiOu6rDNUaWw8SMiM4cB2rHam4zRTatgUHCWpSKMawQt0+nUro/+IeNTZLh2QpIFyxuGzg==}
acorn-jsx@5.3.2: acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
@ -1978,7 +1987,7 @@ snapshots:
'@types/node@12.20.55': {} '@types/node@12.20.55': {}
'@types/node@22.9.0': '@types/node@22.9.1':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
@ -2119,7 +2128,7 @@ snapshots:
merge-options: 3.0.4 merge-options: 3.0.4
p-event: 5.0.1 p-event: 5.0.1
'@yume-chan/async@4.0.0': {} '@yume-chan/async@4.0.2': {}
acorn-jsx@5.3.2(acorn@8.14.0): acorn-jsx@5.3.2(acorn@8.14.0):
dependencies: dependencies:

View file

@ -9,7 +9,7 @@
}, },
"dependencies": { "dependencies": {
"@eslint/js": "^9.15.0", "@eslint/js": "^9.15.0",
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"eslint": "^9.15.0", "eslint": "^9.15.0",
"eslint-plugin-import-x": "^4.4.2", "eslint-plugin-import-x": "^4.4.2",
"typescript": "^5.6.3", "typescript": "^5.6.3",

View file

@ -7,7 +7,7 @@
"scripts": {}, "scripts": {},
"keywords": [], "keywords": [],
"dependencies": { "dependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"json5": "^2.2.3" "json5": "^2.2.3"
}, },
"author": "", "author": "",

View file

@ -6,7 +6,7 @@
"run-test": "wrapper.js" "run-test": "wrapper.js"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.0", "@types/node": "^22.9.1",
"typescript": "^5.6.3" "typescript": "^5.6.3"
} }
} }