mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-04 18:29:23 +02:00
chore: fix typos
This commit is contained in:
parent
f125e82903
commit
42c7da9350
21 changed files with 91 additions and 41 deletions
37
.vscode/settings.json
vendored
37
.vscode/settings.json
vendored
|
@ -1,67 +1,44 @@
|
||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"ADB's",
|
"ADB's",
|
||||||
"addrs",
|
"adbd",
|
||||||
"allowlist",
|
"allowlist",
|
||||||
"arraybuffer",
|
"arraybuffer",
|
||||||
"autorun",
|
"autorun",
|
||||||
"Backends",
|
|
||||||
"brotli",
|
"brotli",
|
||||||
"Callout",
|
"Callout",
|
||||||
"carriernetworkchange",
|
"Cascadia",
|
||||||
"CLASSPATH",
|
|
||||||
"CLSE",
|
"CLSE",
|
||||||
"CNXN",
|
"CNXN",
|
||||||
"cybojenix",
|
|
||||||
"Deserialization",
|
"Deserialization",
|
||||||
"endregion",
|
"Embedder",
|
||||||
"fluentui",
|
"fluentui",
|
||||||
"genymobile",
|
"genymobile",
|
||||||
"Genymobile's",
|
"Genymobile's",
|
||||||
"getprop",
|
"getprop",
|
||||||
"GPRS",
|
|
||||||
"hardcode",
|
|
||||||
"hardcodes",
|
|
||||||
"hhmm",
|
|
||||||
"hisi",
|
|
||||||
"HSPA",
|
|
||||||
"jmuxer",
|
|
||||||
"keyof",
|
"keyof",
|
||||||
"killforward",
|
|
||||||
"laggy",
|
"laggy",
|
||||||
"lapo",
|
|
||||||
"libusb",
|
|
||||||
"localabstract",
|
"localabstract",
|
||||||
"lstat",
|
"lstat",
|
||||||
|
"luma",
|
||||||
"mitm",
|
"mitm",
|
||||||
"Muxer",
|
"Nalu",
|
||||||
"nosim",
|
|
||||||
"opendir",
|
"opendir",
|
||||||
"PKCS",
|
"PKCS",
|
||||||
"pluggable",
|
|
||||||
"powersave",
|
|
||||||
"reimplement",
|
|
||||||
"reimplemented",
|
|
||||||
"Remux",
|
|
||||||
"Remuxer",
|
|
||||||
"RSASSA",
|
|
||||||
"runtimes",
|
"runtimes",
|
||||||
"Scrcpy",
|
"Scrcpy",
|
||||||
"scrollback",
|
|
||||||
"sendrecv",
|
"sendrecv",
|
||||||
|
"sideload",
|
||||||
"streamsaver",
|
"streamsaver",
|
||||||
"struct",
|
"struct",
|
||||||
"struct's",
|
"struct's",
|
||||||
"systemui",
|
|
||||||
"sysui",
|
|
||||||
"tcpip",
|
"tcpip",
|
||||||
"tinyh",
|
"tinyh",
|
||||||
|
"transferables",
|
||||||
"tsbuildinfo",
|
"tsbuildinfo",
|
||||||
"typeof",
|
"typeof",
|
||||||
"uifabric",
|
|
||||||
"webadb",
|
"webadb",
|
||||||
"webcodecs",
|
"webcodecs",
|
||||||
"webpackbar",
|
|
||||||
"websockify",
|
"websockify",
|
||||||
"webusb",
|
"webusb",
|
||||||
"wifi",
|
"wifi",
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
sidebar_position: 1
|
sidebar_position: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# Achitecture
|
<!--
|
||||||
|
cspell: ignore libusb
|
||||||
|
cspell: ignore nodaemon
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Architecture
|
||||||
|
|
||||||
This part describes the architecture of native ADB and Web ADB, and why there are designed in this way.
|
This part describes the architecture of native ADB and Web ADB, and why there are designed in this way.
|
||||||
|
|
||||||
|
@ -110,7 +115,7 @@ Web ADB reuses native ADB daemons, but there is no **client**/**server**: One ap
|
||||||
|
|
||||||
### Core
|
### Core
|
||||||
|
|
||||||
**Core** is the `@yume-chan/adb` package. It generates data in ADB protocol, without "host prefix" (not needed because packets are directly sent to **daemons** via **backends**).
|
**Core** is the `@yume-chan/adb` package. It generates data in ADB protocol, without "host prefix" (not needed because packets are directly sent to **daemons** via a **backend**).
|
||||||
|
|
||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
sidebar_position: 3
|
sidebar_position: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
cspell: ignore bootloader
|
||||||
|
cspell: ignore enduml
|
||||||
|
cspell: ignore mkdir
|
||||||
|
cspell: ignore startuml
|
||||||
|
-->
|
||||||
|
|
||||||
# Connection
|
# Connection
|
||||||
|
|
||||||
In native ADB architecture, once ADB **server** detects a new device, it initiates a connection by sending a `CNXN` [packet](./packet.md).
|
In native ADB architecture, once ADB **server** detects a new device, it initiates a connection by sending a `CNXN` [packet](./packet.md).
|
||||||
|
@ -48,7 +55,7 @@ Device banners describe device information and capabilities. It has the followin
|
||||||
*DeviceBanner* **:**<br/>
|
*DeviceBanner* **:**<br/>
|
||||||
*DeviceIdentifier* **::** *ParameterList* **\0**
|
*DeviceIdentifier* **::** *ParameterList* **\0**
|
||||||
|
|
||||||
*DeviceIdentifer* **:**<br/>
|
*DeviceIdentifier* **:**<br/>
|
||||||
**host**<br/>
|
**host**<br/>
|
||||||
**device**<br/>
|
**device**<br/>
|
||||||
**bootloader**
|
**bootloader**
|
||||||
|
|
|
@ -32,8 +32,11 @@ const MobileDataTypeOptions =
|
||||||
'5ge': '5GE',
|
'5ge': '5GE',
|
||||||
'5g+': '5G+',
|
'5g+': '5G+',
|
||||||
'e': 'EDGE',
|
'e': 'EDGE',
|
||||||
|
// cspell: disable-next-line
|
||||||
'g': 'GPRS',
|
'g': 'GPRS',
|
||||||
|
// cspell: disable-next-line
|
||||||
'h': 'HSPA',
|
'h': 'HSPA',
|
||||||
|
// cspell: disable-next-line
|
||||||
'h+': 'HSPA+',
|
'h+': 'HSPA+',
|
||||||
'lte': 'LTE',
|
'lte': 'LTE',
|
||||||
'lte+': 'LTE+',
|
'lte+': 'LTE+',
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// cspell: ignore scrollback
|
||||||
|
|
||||||
import { AdbShell, encodeUtf8 } from "@yume-chan/adb";
|
import { AdbShell, encodeUtf8 } from "@yume-chan/adb";
|
||||||
import { AutoDisposable } from "@yume-chan/event";
|
import { AutoDisposable } from "@yume-chan/event";
|
||||||
|
|
|
@ -154,8 +154,8 @@ class FileManagerState {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// StreamSaver doens't work with strict site isolation enabled (`Cross-Origin-Embedder-Policy: require-corp`),
|
// StreamSaver doesn't work with strict site isolation enabled (`Cross-Origin-Embedder-Policy: require-corp`),
|
||||||
// `SharedArrayBuffer` doesn't work WHITHOUT strict site isolation.
|
// `SharedArrayBuffer` doesn't work WITHOUT strict site isolation.
|
||||||
if (this.selectedItems[0].type === LinuxFileType.File && typeof SharedArrayBuffer === 'undefined') {
|
if (this.selectedItems[0].type === LinuxFileType.File && typeof SharedArrayBuffer === 'undefined') {
|
||||||
result.push({
|
result.push({
|
||||||
key: 'download',
|
key: 'download',
|
||||||
|
|
|
@ -10,6 +10,7 @@ It started because I want to try the <ExternalLink href="https://developer.mozil
|
||||||
It was called "ya-webadb" (Yet Another WebADB), because there have already been several similar projects, for example:
|
It was called "ya-webadb" (Yet Another WebADB), because there have already been several similar projects, for example:
|
||||||
|
|
||||||
* <ExternalLink href="https://github.com/webadb/webadb.js">webadb/webadb.js</ExternalLink>
|
* <ExternalLink href="https://github.com/webadb/webadb.js">webadb/webadb.js</ExternalLink>
|
||||||
|
<!-- cspell: disable-next-line -->
|
||||||
* <ExternalLink href="https://github.com/cybojenix/WebADB">cybojenix/WebADB</ExternalLink>
|
* <ExternalLink href="https://github.com/cybojenix/WebADB">cybojenix/WebADB</ExternalLink>
|
||||||
|
|
||||||
However, they are all pretty simple and not maintained, so I decided to make my own.
|
However, they are all pretty simple and not maintained, so I decided to make my own.
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// cspell: ignore bootloader
|
||||||
|
// cspell: ignore fastboot
|
||||||
|
|
||||||
import { DefaultButton, Icon, MessageBar, MessageBarType, TooltipHost } from "@fluentui/react";
|
import { DefaultButton, Icon, MessageBar, MessageBarType, TooltipHost } from "@fluentui/react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// cspell: ignore addrs
|
||||||
|
|
||||||
import { CommandBar, ICommandBarItemProps, MessageBar, Stack, StackItem, Text, TextField, Toggle } from "@fluentui/react";
|
import { CommandBar, ICommandBarItemProps, MessageBar, Stack, StackItem, Text, TextField, Toggle } from "@fluentui/react";
|
||||||
import { autorun, makeAutoObservable, runInAction } from "mobx";
|
import { autorun, makeAutoObservable, runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// cspell: ignore RSASSA
|
||||||
|
|
||||||
import { AdbCredentialStore, calculateBase64EncodedLength, calculatePublicKey, calculatePublicKeyLength, decodeBase64, encodeBase64 } from "@yume-chan/adb";
|
import { AdbCredentialStore, calculateBase64EncodedLength, calculatePublicKey, calculatePublicKeyLength, decodeBase64, encodeBase64 } from "@yume-chan/adb";
|
||||||
|
|
||||||
const Utf8Encoder = new TextEncoder();
|
const Utf8Encoder = new TextEncoder();
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
// cspell: ignore carriernetworkchange
|
||||||
|
// cspell: ignore powersave
|
||||||
|
// cspell: ignore nosim
|
||||||
|
// cspell: ignore systemui
|
||||||
|
// cspell: ignore sysui
|
||||||
|
|
||||||
import { AdbCommandBase } from './base';
|
import { AdbCommandBase } from './base';
|
||||||
|
|
||||||
export enum AdbDemoModeSignalStrength {
|
export enum AdbDemoModeSignalStrength {
|
||||||
|
@ -155,6 +161,11 @@ export class AdbDemoMode extends AdbCommandBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setTime(hour: number, minute: number): Promise<void> {
|
public async setTime(hour: number, minute: number): Promise<void> {
|
||||||
await this.broadcast('clock', { hhmm: `${hour.toString().padStart(2, '0')}${minute.toString().padStart(2, '0')}` });
|
await this.broadcast('clock', {
|
||||||
|
// cspell: disable-next-line
|
||||||
|
hhmm:
|
||||||
|
hour.toString().padStart(2, '0') +
|
||||||
|
minute.toString().padStart(2, '0'),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
// cspell: ignore bootloader
|
||||||
|
// cspell: ignore fastboot
|
||||||
|
// cspell: ignore keyevent
|
||||||
|
// cspell: ignore longpress
|
||||||
|
|
||||||
import { AdbCommandBase } from "./base";
|
import { AdbCommandBase } from "./base";
|
||||||
|
|
||||||
export class AdbPower extends AdbCommandBase {
|
export class AdbPower extends AdbCommandBase {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// cspell: ignore killforward
|
||||||
|
|
||||||
import { AutoDisposable } from '@yume-chan/event';
|
import { AutoDisposable } from '@yume-chan/event';
|
||||||
import Struct from '@yume-chan/struct';
|
import Struct from '@yume-chan/struct';
|
||||||
import type { AdbPacket } from '../packet';
|
import type { AdbPacket } from '../packet';
|
||||||
|
|
|
@ -45,18 +45,22 @@ describe('base64', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("input length 3", () => {
|
it("input length 3", () => {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
expect(new Uint8Array(decodeBase64('AAEC'))).toEqual(new Uint8Array([0, 1, 2]));
|
expect(new Uint8Array(decodeBase64('AAEC'))).toEqual(new Uint8Array([0, 1, 2]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("input length 4", () => {
|
it("input length 4", () => {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
expect(new Uint8Array(decodeBase64('AAECAw=='))).toEqual(new Uint8Array([0, 1, 2, 3]));
|
expect(new Uint8Array(decodeBase64('AAECAw=='))).toEqual(new Uint8Array([0, 1, 2, 3]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("input length 5", () => {
|
it("input length 5", () => {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
expect(new Uint8Array(decodeBase64('AAECAwQ='))).toEqual(new Uint8Array([0, 1, 2, 3, 4]));
|
expect(new Uint8Array(decodeBase64('AAECAwQ='))).toEqual(new Uint8Array([0, 1, 2, 3, 4]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("input length 6", () => {
|
it("input length 6", () => {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
expect(new Uint8Array(decodeBase64('AAECAwQF'))).toEqual(new Uint8Array([0, 1, 2, 3, 4, 5]));
|
expect(new Uint8Array(decodeBase64('AAECAwQF'))).toEqual(new Uint8Array([0, 1, 2, 3, 4, 5]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -115,6 +119,7 @@ describe('base64', () => {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
/* cspell: disable-next-line */
|
||||||
).toEqual(new Uint8Array([65, 65, 69, 67])); // AAEC
|
).toEqual(new Uint8Array([65, 65, 69, 67])); // AAEC
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -127,6 +132,7 @@ describe('base64', () => {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
/* cspell: disable-next-line */
|
||||||
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 61, 61])); // AAECAw==
|
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 61, 61])); // AAECAw==
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,6 +145,7 @@ describe('base64', () => {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
/* cspell: disable-next-line */
|
||||||
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 81, 61])); // AAECAwQ=
|
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 81, 61])); // AAECAwQ=
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -151,6 +158,7 @@ describe('base64', () => {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
/* cspell: disable-next-line */
|
||||||
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 81, 70])); // AAECAwQF
|
).toEqual(new Uint8Array([65, 65, 69, 67, 65, 119, 81, 70])); // AAECAwQF
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ export function encodeBase64(
|
||||||
let outputIndex = outputOffset + outputLength - 1;
|
let outputIndex = outputOffset + outputLength - 1;
|
||||||
|
|
||||||
if (paddingLength === 2) {
|
if (paddingLength === 2) {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// aaaaaabb
|
// aaaaaabb
|
||||||
const x = input[inputIndex]!;
|
const x = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
@ -156,10 +157,12 @@ export function encodeBase64(
|
||||||
output[outputIndex] = indexToChar[x >> 2]!;
|
output[outputIndex] = indexToChar[x >> 2]!;
|
||||||
outputIndex -= 1;
|
outputIndex -= 1;
|
||||||
} else if (paddingLength === 1) {
|
} else if (paddingLength === 1) {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// bbbbcccc
|
// bbbbcccc
|
||||||
const y = input[inputIndex]!;
|
const y = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// aaaaaabb
|
// aaaaaabb
|
||||||
const x = input[inputIndex]!;
|
const x = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
@ -178,14 +181,17 @@ export function encodeBase64(
|
||||||
}
|
}
|
||||||
|
|
||||||
while (inputIndex >= inputOffset) {
|
while (inputIndex >= inputOffset) {
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// ccdddddd
|
// ccdddddd
|
||||||
const z = input[inputIndex]!;
|
const z = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// bbbbcccc
|
// bbbbcccc
|
||||||
const y = input[inputIndex]!;
|
const y = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
|
||||||
|
/* cspell: disable-next-line */
|
||||||
// aaaaaabb
|
// aaaaaabb
|
||||||
const x = input[inputIndex]!;
|
const x = input[inputIndex]!;
|
||||||
inputIndex -= 1;
|
inputIndex -= 1;
|
||||||
|
|
|
@ -160,6 +160,7 @@ export class ScrcpyClient {
|
||||||
|
|
||||||
process = await this.device.childProcess.spawn(
|
process = await this.device.childProcess.spawn(
|
||||||
[
|
[
|
||||||
|
// cspell: disable-next-line
|
||||||
`CLASSPATH=${path}`,
|
`CLASSPATH=${path}`,
|
||||||
'app_process',
|
'app_process',
|
||||||
/* unused */ '/',
|
/* unused */ '/',
|
||||||
|
|
|
@ -118,7 +118,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptions1_16Type = ScrcpyOptions1_
|
||||||
this.value = value as Partial<T>;
|
this.value = value as Partial<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getArgumnetOrder(): (keyof T)[] {
|
protected getArgumentOrder(): (keyof T)[] {
|
||||||
return [
|
return [
|
||||||
'logLevel',
|
'logLevel',
|
||||||
'maxSize',
|
'maxSize',
|
||||||
|
@ -158,7 +158,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptions1_16Type = ScrcpyOptions1_
|
||||||
|
|
||||||
public formatServerArguments(): string[] {
|
public formatServerArguments(): string[] {
|
||||||
const defaults = this.getDefaultValue();
|
const defaults = this.getDefaultValue();
|
||||||
return this.getArgumnetOrder()
|
return this.getArgumentOrder()
|
||||||
.map(key => toScrcpyOptionValue(this.value[key] || defaults[key], '-'));
|
.map(key => toScrcpyOptionValue(this.value[key] || defaults[key], '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ export class ScrcpyOptions1_18<T extends ScrcpyOptions1_18Type = ScrcpyOptions1_
|
||||||
super(value);
|
super(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getArgumnetOrder(): (keyof T)[] {
|
protected override getArgumentOrder(): (keyof T)[] {
|
||||||
return super.getArgumnetOrder().concat(['powerOffOnClose']);
|
return super.getArgumentOrder().concat(['powerOffOnClose']);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getDefaultValue(): T {
|
protected override getDefaultValue(): T {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// cspell: ignore autosync
|
||||||
|
|
||||||
import { ScrcpyOptions1_18, ScrcpyOptions1_18Type } from './1_18';
|
import { ScrcpyOptions1_18, ScrcpyOptions1_18Type } from './1_18';
|
||||||
import { toScrcpyOptionValue } from "./common";
|
import { toScrcpyOptionValue } from "./common";
|
||||||
|
|
||||||
|
@ -22,6 +24,8 @@ export class ScrcpyOptions1_21<T extends ScrcpyOptions1_21Type = ScrcpyOptions1_
|
||||||
}
|
}
|
||||||
|
|
||||||
public override formatServerArguments(): string[] {
|
public override formatServerArguments(): string[] {
|
||||||
|
// 1.21 changed the format of arguments
|
||||||
|
// So `getArgumentOrder()` is no longer needed
|
||||||
return Object.entries(this.value)
|
return Object.entries(this.value)
|
||||||
.map(([key, value]) => [key, toScrcpyOptionValue(value, undefined)] as const)
|
.map(([key, value]) => [key, toScrcpyOptionValue(value, undefined)] as const)
|
||||||
.filter((pair): pair is [string, string] => pair[1] !== undefined)
|
.filter((pair): pair is [string, string] => pair[1] !== undefined)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// cspell: ignore golomb
|
||||||
|
// cspell: ignore qpprime
|
||||||
|
|
||||||
class BitReader {
|
class BitReader {
|
||||||
private buffer: Uint8Array;
|
private buffer: Uint8Array;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# @yume-chan/struct
|
# @yume-chan/struct
|
||||||
|
|
||||||
|
<!--
|
||||||
|
cspell: ignore Codecov
|
||||||
|
cspell: ignore arraybufferuint8clampedarraystring
|
||||||
|
-->
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
[](https://www.npmjs.com/package/@yume-chan/struct)
|
[](https://www.npmjs.com/package/@yume-chan/struct)
|
||||||
|
@ -42,6 +47,8 @@ const buffer = MyStruct.serialize({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<!-- cspell: disable -->
|
||||||
|
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Quick Start](#quick-start)
|
- [Quick Start](#quick-start)
|
||||||
- [Compatibility](#compatibility)
|
- [Compatibility](#compatibility)
|
||||||
|
@ -68,6 +75,8 @@ const buffer = MyStruct.serialize({
|
||||||
- [`get`/`set`](#getset)
|
- [`get`/`set`](#getset)
|
||||||
- [`serialize`](#serialize-1)
|
- [`serialize`](#serialize-1)
|
||||||
|
|
||||||
|
<!-- cspell: enable -->
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
| | Chrome | Edge | Firefox | Internet Explorer | Safari | Node.js |
|
| | Chrome | Edge | Firefox | Internet Explorer | Safari | Node.js |
|
||||||
|
@ -447,7 +456,7 @@ Multiple calls merge all extra fields together.
|
||||||
postDeserialize(): Struct<TFields, TOmitInitKey, TExtra, undefined>;
|
postDeserialize(): Struct<TFields, TOmitInitKey, TExtra, undefined>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Remove any registered post deserialization callback.
|
Remove any registered post-deserialization callback.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
postDeserialize(
|
postDeserialize(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue