Showing preview only (271K chars total). Download the full file or copy to clipboard to get everything.
Repository: GoogleChromeLabs/wadb
Branch: main
Commit: 3488a4ab05b0
Files: 73
Total size: 251.8 KB
Directory structure:
gitextract_qi4f3tty/
├── .eslintrc.json
├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── demo/
│ ├── .firebaserc
│ ├── .gitignore
│ ├── firebase.json
│ ├── package.json
│ ├── public/
│ │ ├── 404.html
│ │ ├── index.html
│ │ ├── interactiveshell.html
│ │ ├── js/
│ │ │ ├── interactiveshell.bundle.js
│ │ │ ├── interactiveshell.d.ts
│ │ │ ├── interactiveshell.js
│ │ │ ├── livestream.bundle.js
│ │ │ ├── livestream.d.ts
│ │ │ ├── livestream.js
│ │ │ ├── screenrecord.bundle.js
│ │ │ ├── screenrecord.d.ts
│ │ │ └── screenrecord.js
│ │ ├── livestream.html
│ │ ├── screenrecord.html
│ │ ├── sw.js
│ │ ├── video.html
│ │ ├── workbox-69b5a3b7.js
│ │ └── workbox-aa2f3006.js
│ ├── src/
│ │ ├── interactiveshell.ts
│ │ ├── livestream.ts
│ │ └── screenrecord.ts
│ ├── tsconfig.json
│ ├── webpack.config.js
│ └── workbox-config.js
├── eslint.config.mjs
├── jasmine.json
├── package.json
├── src/
│ ├── index.ts
│ ├── lib/
│ │ ├── AdbClient.ts
│ │ ├── AdbConnectionInformation.ts
│ │ ├── Framebuffer.ts
│ │ ├── Helpers.ts
│ │ ├── IndexedDbKeyStore.ts
│ │ ├── KeyStore.ts
│ │ ├── Log.ts
│ │ ├── Options.ts
│ │ ├── Queues.ts
│ │ ├── Shell.ts
│ │ ├── Stream.ts
│ │ ├── SyncFrame.ts
│ │ ├── message/
│ │ │ ├── Message.ts
│ │ │ ├── MessageChannel.ts
│ │ │ ├── MessageHeader.ts
│ │ │ ├── MessageListener.ts
│ │ │ └── index.ts
│ │ └── transport/
│ │ ├── Transport.ts
│ │ ├── WebUsbTransport.ts
│ │ └── index.ts
│ └── spec/
│ ├── AdbClientSpec.ts
│ ├── IndexedDbKeyStoreSpec.ts
│ ├── QueuesSpec.ts
│ ├── StreamSpec.ts
│ ├── SyncFrameSpec.ts
│ ├── data/
│ │ └── messages/
│ │ ├── connect/
│ │ │ ├── connect_auth_public_key.json
│ │ │ └── connect_simple.json
│ │ └── stream/
│ │ └── open.json
│ ├── message/
│ │ ├── MessageChannelSpec.ts
│ │ ├── MessageHeaderSpec.ts
│ │ └── MessageSpec.ts
│ └── mock/
│ ├── MockKeyStore.ts
│ ├── MockMessageListener.ts
│ └── MockTransport.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"rules": {
"@typescript-eslint/no-non-null-assertion": "off",
"no-trailing-spaces": "error",
"eol-last": "error"
},
"env": {
"node": true,
"jasmine": true
}
}
================================================
FILE: .gitignore
================================================
node_modules/
dist/
.DS_Store
wq
================================================
FILE: .npmignore
================================================
tsconfig.json
src
================================================
FILE: CONTRIBUTING.md
================================================
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# An ADB Implementation using WebUSB
This project is a TypeScript implementation of the Android Debug Bridge(ADB) protocol over WebUSB.
The implementation inspired on the [webadb.js][1], with the main difference being that
implementation supports multiple concurrent streams.
This is not an exhaustive implementation of the protocol and hasn't been tested on a wide range of
devices.
A non-exhaustive list of things that are not implemented:
- `STAT`: reads stats from the Android filesystem (file size, mode and time).
## Usage
### Connecting to a device
```typescript
const options: Options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
const transport = await WebUsbTransport.open(options);
const adbClient = new AdbClient(transport, options, keyStore);
await adbClient.connect();
```
### Downloading a file from the device (adb pull)
```typescript
const result: Blob = await adbClient.pull('/sdcard/my-video.mp4');
```
### Sending shell commands
```typescript
const result: string = await adbClient.shell('uname -a');
```
### Interactive shell
```typescript
const callback = (output: string) => {
console.log('server: ' + output);
};
const shell: Shell = await adbClient.interactiveShell(callback);
await shell.write('ls /sdcard\n');
await shell.close();
```
## Related Documents
- https://github.com/webadb/webadb.js
- https://github.com/cstyan/adbDocumentation
- https://android.googlesource.com/platform/system/core/+/master/adb/
## Contributing
See [CONTRIBUTING](./CONTRIBUTING.md) for more.
## License
See [LICENSE](./LICENSE) for more.
## Disclaimer
This is not a Google product.
[1]: https://github.com/webadb/webadb.js
================================================
FILE: demo/.firebaserc
================================================
{
"projects": {
"default": "screenrecord-bandarra-me"
}
}
================================================
FILE: demo/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
firebase-debug.log*
# Firebase cache
.firebase/
# Firebase config
# Uncomment this if you'd like others to create their own Firebase project.
# For a team working on the same Firebase project(s), it is recommended to leave
# it commented so all members can deploy to the same project(s) in .firebaserc.
# .firebaserc
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
================================================
FILE: demo/firebase.json
================================================
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
================================================
FILE: demo/package.json
================================================
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"private": true,
"scripts": {
"build": "tsc",
"dev": "webpack serve --mode=development",
"package": "webpack --mode=production && workbox generateSW",
"serve": "serve"
},
"author": "André Cipriani Bandarra",
"license": "Apache-2.0",
"devDependencies": {
"serve": "^14.2.5",
"ts-loader": "^9.5.4",
"typescript": "^5.9.3",
"webpack": "^5.105.2",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.3",
"workbox-cli": "^7.4.0"
},
"dependencies": {
"wadb": "file:../"
}
}
================================================
FILE: demo/public/404.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Not Found</title>
<style media="screen">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px 16px; border-radius: 3px; }
#message h3 { color: #888; font-weight: normal; font-size: 16px; margin: 16px 0 12px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>404</h2>
<h1>Page Not Found</h1>
<p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
<h3>Why am I seeing this?</h3>
<p>This page was generated by the Firebase Command-Line Interface. To modify it, edit the <code>404.html</code> file in your project's configured <code>public</code> directory.</p>
</div>
</body>
</html>
================================================
FILE: demo/public/index.html
================================================
<!--
Copyright 2020 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
<title>WebADB Screenrecord</title>
<script src="js/screenrecord.bundle.js" defer></script>
<style>
html {
font-family: 'Roboto', sans-serif;
background-color: lightsteelblue;
box-sizing: border-box;
min-width: 320px;
}
body {
margin: 0;
}
header, .status {
box-sizing: border-box;
box-shadow: 0px 2px 4px #999999;
}
header > h1, .status > div, content > div {
margin: 0px auto;
max-width: 900px;
padding: 0px 16px;
box-sizing: border-box;
}
header {
background-color: #789ac7;
}
header > h1 {
height: 56px;
padding: 8px 16px;
}
.status {
height: 28px;
background-color: steelblue;
font-size: 12px;
padding-top: 6px;
text-transform: uppercase;
margin-bottom: 16px;
}
h2 {
margin: 16px 0 8px 0;
}
.video-container > div {
background-color: #222222;
width: 100%;
margin: 0px auto;
}
video, #screenshot {
width: 100%;
max-width: 100%;
max-height: 100%;
}
.video-container {
margin-top: 16px;
margin-bottom: 16px;
width: 100%;
}
.button {
width: 145px;
height: 30px;
text-transform: uppercase;
padding-left: 20px;
}
#connect {
background-image: url(./assets/phonelink.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#disconnect {
background-image: url(./assets/phonelink_off.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#start {
background-image: url(./assets/video-start.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#stop {
background-image: url(./assets/video-stop.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#screencapture {
background-image: url(./assets/screenshot.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
/* #download {
background-image: url(./assets/save.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
text-decoration: none;
color: black;
background-color: lightgrey;
width: 14px;
} */
.hidden {
display: none;
}
</style>
</head>
<body>
<header>
<h1>WebADB Screenrecord</h1>
</header>
<div class="status">
<div id="status">
Connect to a device to start
</div>
</div>
<content>
<div class="buttons">
<button id="connect" class="button">Connect</button>
<button id="disconnect" class="button hidden">Disconnect</button>
<button id="start" class="button" disabled>Record</button>
<button id="stop" class="button hidden" disabled>Stop</button>
<button id="screencapture" class="button" disabled>Screenshot</button>
</div>
<div class="video-container">
<div>
<video id="video" controls></video>
<img id="screenshot" class="hidden"></img>
</div>
<a id="download" class='hidden' href="#" download="recording.mp4">Download</a>
</div>
<div>
<h2>How to use:</h2>
<ol>
<li>Enable developer mode on the Android device (<a href="https://developer.android.com/studio/debug/dev-options">more info</a>).</li>
<li>Connect the Android device to the computer with an USB cable.</li>
<li>Click the <em>Connect</em> button.</li>
<li>Accept the prompt on the Android device.</li>
<li>Click the <em>Record</em> or <em>Screenshot</em> button.</li>
</ol>
</div>
</content>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
</script>
</body>
</html>
================================================
FILE: demo/public/interactiveshell.html
================================================
<!--
Copyright 2020 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
<title>Web ADB Interactive Shell</title>
<script src="js/interactiveshell.bundle.js" defer></script>
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono&display=swap" rel="stylesheet">
<style>
html {
font-family: 'Roboto', sans-serif;
background-color: lightsteelblue;
box-sizing: border-box;
}
body {
margin: 0;
}
h1 {
height: 56px;
margin: 0 0 16px 0;
padding: 8px 16px;
background-color: #789ac7;
box-sizing: border-box;
box-shadow: 0px 2px 4px #999999;
}
h2 {
margin: 16px 0 8px 0;
}
code {
font-family: 'Roboto Mono', monospace;
width: 100%;
height: 70vh;
border: 0.5px solid;
border-bottom: 0px;
display: block;
background-color: black;
color: lightgreen;
overflow: auto;
}
input {
font-family: 'Roboto Mono', monospace;
width: 100%;
border: 0.5px solid;
border-top: 0px;
background-color: black;
color: lightgreen;
}
.content-wrapper {
padding: 8px;
}
code > span {
display: block;
}
.buttons {
height: 30px;
}
.button {
width: 130px;
height: 30px;
text-transform: uppercase;
padding-left: 20px;
}
#connect {
background-image: url(./assets/phonelink.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#disconnect {
background-image: url(./assets/phonelink_off.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<h1>WebADB Shell</h1>
<div class="content-wrapper">
<div class="buttons">
<button id="connect" class="button">Connect</button>
<button id="disconnect" class="button hidden">Disconnect</button>
</div>
<div>
<h2>Console</h2>
<code id="output">
</code>
<input id="input" type="text"></input>
</div>
</div>
</body>
</html>
================================================
FILE: demo/public/js/interactiveshell.bundle.js
================================================
(()=>{"use strict";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var s=Object.getOwnPropertyDescriptor(t,n);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,s)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),s=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),s(n(620),t),s(n(449),t),s(n(540),t),s(n(432),t),s(n(16),t),s(n(908),t),s(n(870),t),s(n(858),t),s(n(980),t)},620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AdbClient=void 0;const s=n(858),o=n(351),r=n(449),a=n(908),c=n(16),d=n(364),u=n(681);class h{constructor(e,t,n){this.transport=e,this.options=t,this.keyStore=n,this.messageQueue=new d.AsyncBlockingQueue,this.openStreams=new Set,this.messageChannel=new s.MessageChannel(e,t,this)}registerStream(e){this.openStreams.add(e)}unregisterStream(e){this.openStreams.delete(e)}newMessage(e){const t=Array.from(this.openStreams);for(const n of t)if(n.consumeMessage(e))return;this.messageQueue.enqueue(e)}awaitMessage(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}connect(){return i(this,void 0,void 0,function*(){const e=this.options.useChecksum?16777216:16777217,t=s.Message.cnxn(e,262144,"host::\0",this.options.useChecksum);let n;yield this.sendMessage(t);do{n=yield this.awaitMessage()}while("CNXN"!==n.header.cmd&&"AUTH"!==n.header.cmd);if("CNXN"===n.header.cmd){if(!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)}if(n=yield this.doAuth(n),!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)})}disconnect(){return i(this,void 0,void 0,function*(){this.messageChannel.close()})}shell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,`shell:${e}`,this.options),n=yield t.read();return yield t.close(),n.dataAsString()||""})}framebuffer(){return i(this,void 0,void 0,function*(){return u.Framebuffer.create(this,this.options)})}interactiveShell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,"shell:",this.options);return new c.Shell(t,e)})}sync(){return i(this,void 0,void 0,function*(){return yield a.Stream.open(this,"sync:",this.options)})}pull(e){return i(this,void 0,void 0,function*(){const t=yield this.sync(),n=yield t.pull(e);return yield t.close(),n})}push(e,t,n,s){return i(this,void 0,void 0,function*(){const i=yield this.sync();yield i.push(e,t,n,s),yield i.close()})}doAuth(e){return i(this,void 0,void 0,function*(){if("AUTH"!==e.header.cmd)throw new Error("Not an AUTH response");if(1!==e.header.arg0)throw new Error(`\n Invalid AUTH parameter. Expected 1 and received ${e.header.arg0}`);if(!e.data)throw new Error("AUTH message doens't contain data");const t=e.data.buffer,n=yield this.keyStore.loadKeys();for(const e of n){const n=yield crypto.subtle.sign("RSASSA-PKCS1-v1_5",e.privateKey,t),i=s.Message.authSignature(new DataView(n),this.options.useChecksum);yield this.sendMessage(i);const o=yield this.awaitMessage();if("CNXN"===o.header.cmd)return o;console.log("Received message ",o,"from phone")}const i=yield h.generateKey(this.options.dump,this.options.keySize);yield this.keyStore.saveKey(i);const o=new DataView(yield crypto.subtle.exportKey("spki",i.publicKey)),r=s.Message.authPublicKey(o,this.options.useChecksum);yield this.sendMessage(r),this.options.debug&&console.log("Waiting for key to be accepted on the device.");const a=yield this.awaitMessage();if("CNXN"!==a.header.cmd)throw console.error("AUTH failed. Phone didn't accept key",a),new Error("AUTH failed. Phone didn't accept key");return a})}sendMessage(e){return i(this,void 0,void 0,function*(){yield this.messageChannel.write(e)})}static generateKey(e,t){return i(this,void 0,void 0,function*(){const n=e,i=yield crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:t,publicExponent:new Uint8Array([1,0,1]),hash:{name:"SHA-1"}},n,["sign","verify"]);return e&&(yield(0,o.privateKeyDump)(i)),i})}}t.AdbClient=h},449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectionInformation=void 0;const n="<unkwnown>";class i{constructor(e,t,n,i){this.productName=e,this.productDevice=t,this.productModel=n,this.features=i}static fromDataView(e){const t=(new TextDecoder).decode(e);return i.fromString(t)}static fromString(e){const t=e.indexOf("::"),s=e.substring(t+2).split(";");let o=n,r=n,a=n,c=[];for(const e of s)e.startsWith("ro.product.name")?o=e.substring(16):e.startsWith("ro.product.model")?a=e.substring(17):e.startsWith("ro.product.device")?r=e.substring(18):e.startsWith("features")&&(c=e.substring(9).split(","));return new i(o,r,a,c)}}t.AdbConnectionInformation=i},681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Framebuffer=void 0;const s=n(908);class o{constructor(e,t,n,i,s,o,r,a,c,d,u,h,l,f,y){this.version=e,this.bpp=t,this.colorSpace=n,this.size=i,this.width=s,this.height=o,this.redOffset=r,this.redLength=a,this.blueOffset=c,this.blueLength=d,this.greenOffset=u,this.greenLength=h,this.alphaOffset=l,this.alphaLength=f,this.imageData=y}static create(e,t){return i(this,void 0,void 0,function*(){var n;const i=yield s.Stream.open(e,"framebuffer:",t);let r=yield i.read();if("WRTE"!==r.header.cmd)throw yield i.write("CLSE"),new Error(`Expected WRTE message but received ${r.header.cmd}`);if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");yield i.write("OKAY");const a=r.data.getUint32(0,!0),c=r.data.getUint32(4,!0),d=r.data.getUint32(8,!0),u=r.data.getUint32(12,!0),h=r.data.getUint32(16,!0),l=r.data.getUint32(20,!0),f=r.data.getUint32(24,!0),y=r.data.getUint32(28,!0),g=r.data.getUint32(32,!0),w=r.data.getUint32(36,!0),v=r.data.getUint32(40,!0),p=r.data.getUint32(44,!0),m=r.data.getUint32(48,!0),b=r.data.getUint32(52,!0),E=new Uint8Array(u);let M=0,_=new Uint8Array(r.data.buffer.slice(o.BYTE_LENGTH));for(E.set(_,0),M=_.length;M<u&&(r=yield i.read(),"CLSE"!==r.header.cmd);){if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");_=new Uint8Array(null===(n=r.data)||void 0===n?void 0:n.buffer),E.set(_,M),M+=_.length,yield i.write("OKAY")}return yield i.close(),new o(a,c,d,u,h,l,f,y,g,w,v,p,m,b,Uint8ClampedArray.from(E))})}}t.Framebuffer=o,o.BYTE_LENGTH=56},351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};function i(e,t,n){const i=t-e.length;let s="";for(let e=0;e<i;e++)s+=n;return s+e}function s(e){return i(e.toString(16),2,"0")}function o(e){return i(e.toString(16),4,"0")}function r(e){return btoa(new Uint8Array(e).reduce((e,t)=>e+String.fromCharCode(t),""))}Object.defineProperty(t,"__esModule",{value:!0}),t.toHex8=s,t.toHex16=o,t.toHex32=function(e){return i(e.toString(16),8,"0")},t.hexdump=function(e,t=""){const n=new TextDecoder;for(let i=0;i<e.byteLength;i+=16){const r=e.byteLength-i>16?16:e.byteLength-i;let a,c=t+o(i)+" ";for(a=0;a<r;a++)c+=" "+s(e.getUint8(i+a));for(;a<16;a++)c+=" ";c+=" | "+n.decode(new DataView(e.buffer,i,r)),console.log(c)}},t.toB64=r,t.privateKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.privateKey.extractable)return void console.log("cannot dump the private key, it's not extractable");const t=yield crypto.subtle.exportKey("pkcs8",e.privateKey);console.log(`-----BEGIN PRIVATE KEY-----\n${r(t)}\n-----END PRIVATE KEY-----`)})},t.publicKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.publicKey.extractable)return void console.log("cannot dump the public key, it's not extractable");const t=yield crypto.subtle.exportKey("spki",e.publicKey);console.log(`-----BEGIN PUBLIC KEY-----\n${r(t)}'\n-----END PUBLIC KEY-----`)})},t.encodeCmd=function(e){const t=(new TextEncoder).encode(e).buffer;return new DataView(t).getUint32(0,!0)},t.decodeCmd=function(e){const t=new TextDecoder,n=new ArrayBuffer(4);return new DataView(n).setUint32(0,e,!0),t.decode(n)}},540(e,t){Object.defineProperty(t,"__esModule",{value:!0})},432(e,t){Object.defineProperty(t,"__esModule",{value:!0})},364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AsyncBlockingQueue=t.Queue=void 0;class i{constructor(e){this.data=e}}class s{enqueue(e){const t=new i(e);this.tail&&(this.tail.next=t),this.tail=t,this.head||(this.head=this.tail)}dequeue(){if(this.isEmpty())throw new Error("Cannot dequeue. Queue is empty");const e=this.head.data;return this.head=this.head.next,e}isEmpty(){return null==this.head}}t.Queue=s,t.AsyncBlockingQueue=class{constructor(){this.promiseQueue=new s,this.resolverQueue=new s}add(){const e=new Promise(e=>{this.resolverQueue.enqueue(e)});this.promiseQueue.enqueue(e)}enqueue(e){this.resolverQueue.isEmpty()&&this.add(),this.resolverQueue.dequeue()(e)}dequeue(){return n(this,void 0,void 0,function*(){return this.promiseQueue.isEmpty()&&this.add(),this.promiseQueue.dequeue()})}hasPendingPromises(){return!this.promiseQueue.isEmpty()}hasPendingResolvers(){return!this.resolverQueue.isEmpty()}}},16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Shell=void 0,t.Shell=class{constructor(e,t){this.stream=e,this.callbackFunction=t,this.textDecoder=new TextDecoder,this.textEncoder=new TextEncoder,this.messageListener=[],this.closed=!1,this.loopRead()}loopRead(){return n(this,void 0,void 0,function*(){try{let e;do{if(e=yield this.stream.read(),"WRTE"===e.header.cmd){this.stream.write("OKAY");const t=this.textDecoder.decode(e.data);this.callbackFunction&&this.callbackFunction(t)}for(const t of this.messageListener)t(e)}while(!this.closed)}catch(e){console.error("loopRead crashed",e)}this.stream.client.unregisterStream(this.stream)})}waitForMessage(e){return new Promise(t=>{const n=i=>{if(i.header.cmd===e){const e=this.messageListener.indexOf(n);this.messageListener.splice(e,1),t(i)}};this.messageListener.push(n)})}write(e){return n(this,void 0,void 0,function*(){const t=this.textEncoder.encode(e);yield this.stream.write("WRTE",new DataView(t.buffer)),yield this.waitForMessage("OKAY")})}close(){return n(this,void 0,void 0,function*(){this.closed=!0,yield this.write("CLSE")})}}},908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Stream=void 0;const s=n(858),o=n(351),r=n(870),a=n(364);class c{constructor(e,t,n,i,s){this.client=e,this.service=t,this.localId=n,this.remoteId=i,this.options=s,this.messageQueue=new a.AsyncBlockingQueue}close(){return i(this,void 0,void 0,function*(){yield this.write("CLSE"),this.options.debug&&(console.log(`Closed stream ${this.service}`),console.log(` local_id: 0x${(0,o.toHex32)(this.localId)}`),console.log(` remote_id: 0x${(0,o.toHex32)(this.remoteId)}`)),this.client.unregisterStream(this)})}consumeMessage(e){return 0!==e.header.arg0&&e.header.arg0===this.remoteId&&0!==e.header.arg1&&e.header.arg1===this.localId&&(this.messageQueue.enqueue(e),!0)}write(e,t){return i(this,void 0,void 0,function*(){const n=this.newMessage(e,t);yield this.client.sendMessage(n)})}read(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}sendReceive(e,t){return i(this,void 0,void 0,function*(){yield this.client.sendMessage(e);const n=yield this.read();if(n.header.cmd!==t)throw new Error("WRTE/SEND failed: "+n)})}pull(e){return i(this,void 0,void 0,function*(){const t=(new TextEncoder).encode(e),n=new r.SyncFrame("RECV",t.byteLength),i=this.newMessage("WRTE",n.toDataView());yield this.client.sendMessage(i);const s=yield this.read();if("OKAY"!==s.header.cmd)throw new Error("WRTE/RECV failed: "+s);const o=this.newMessage("WRTE",new DataView(t.buffer));yield this.client.sendMessage(o);const a=yield this.read();if("OKAY"!==a.header.cmd)throw new Error("WRTE/filename failed: "+a);const c=this.newMessage("OKAY");let d=yield this.read();yield this.client.sendMessage(c);let u=r.SyncFrame.fromDataView(new DataView(d.data.buffer.slice(0,8))),h=new Uint8Array(d.data.buffer.slice(8));const l=[];for(;"DONE"!==u.cmd;){for(;u.byteLength>=h.byteLength;){d=yield this.read(),yield this.client.sendMessage(c);const e=h.byteLength+d.data.byteLength,t=new Uint8Array(e);t.set(h,0),t.set(new Uint8Array(d.data.buffer),h.byteLength),h=t}l.push(h.slice(0,u.byteLength).buffer),h=h.slice(u.byteLength),u=r.SyncFrame.fromDataView(new DataView(h.slice(0,8).buffer)),h=h.slice(8)}return new Blob(l)})}push(e,t,n,s){return i(this,void 0,void 0,function*(){const i=new FileReader,o=new TextEncoder,a=o.encode(t),c=new r.SyncFrame("SEND",t.length+1+n.length),d=this.newMessage("WRTE",c.toDataView());yield this.sendReceive(d,"OKAY");const u=this.newMessage("WRTE",new DataView(a.buffer));yield this.sendReceive(u,"OKAY");const h=this.newMessage("WRTE",new DataView(o.encode(","+n).buffer));yield this.sendReceive(h,"OKAY");const l=new Promise((t,n)=>{i.onload=e=>t(e.target.result),i.onerror=n,i.readAsArrayBuffer(e)}),f=yield l,y=[];for(let e=0;e<f.byteLength;e+=s)y.push(f.slice(e,Math.min(e+s,f.byteLength)));for(const e of y){const t=new r.SyncFrame("DATA",e.byteLength),n=this.newMessage("WRTE",t.toDataView());yield this.sendReceive(n,"OKAY");const i=new DataView(e),s=this.newMessage("WRTE",i);yield this.sendReceive(s,"OKAY")}const g=new r.SyncFrame("DONE",Math.round(Date.now()/1e3)),w=this.newMessage("WRTE",g.toDataView());yield this.client.sendMessage(w);const v=this.newMessage("OKAY");yield this.sendReceive(v,"OKAY")})}newMessage(e,t){return s.Message.newMessage(e,this.localId,this.remoteId,this.options.useChecksum,t)}static open(e,t,n){return i(this,void 0,void 0,function*(){const i=c.nextId++;let r=0;const a=s.Message.open(i,r,t,n.useChecksum);let d;yield e.sendMessage(a);do{d=yield e.awaitMessage()}while(d.header.arg1!==i);if("OKAY"!==d.header.cmd)throw new Error("OPEN Failed");r=d.header.arg0,n.debug&&(console.log(`Opened stream ${t}`),console.log(` local_id: 0x${(0,o.toHex32)(i)}`),console.log(` remote_id: 0x${(0,o.toHex32)(r)}`));const u=new c(e,t,i,r,n);return e.registerStream(u),u})}}t.Stream=c,c.nextId=1},870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=void 0;const i=n(351);class s{constructor(e,t){this.cmd=e,this.byteLength=t}toDataView(){const e=new ArrayBuffer(8),t=(0,i.encodeCmd)(this.cmd),n=new DataView(e);return n.setUint32(0,t,!0),n.setUint32(4,this.byteLength,!0),n}static fromDataView(e){const t=(0,i.decodeCmd)(e.getUint32(0,!0)),n=e.getUint32(4,!0);return new s(t,n)}}t.SyncFrame=s},397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=void 0;const i=n(864),s=n(351);class o{constructor(e,t){this.header=e,this.data=t}dataAsString(){return this.data?(new TextDecoder).decode(this.data):null}static newMessage(e,t,n,s,r){let a=0,c=0;r&&(c=r.byteLength,s&&(a=o.checksum(r)));const d=new i.MessageHeader(e,t,n,c,a);return new o(d,r)}static open(e,t,n,i){const s=new TextEncoder,r=new DataView(s.encode(n+"\0").buffer);return o.newMessage("OPEN",e,t,i,r)}static cnxn(e,t,n,i){const s=new TextEncoder,r=new DataView(s.encode(n).buffer);return o.newMessage("CNXN",e,t,i,r)}static authSignature(e,t){return o.newMessage("AUTH",2,0,t,e)}static authPublicKey(e,t){const n=(new TextEncoder).encode((0,s.toB64)(e.buffer)+"\0");return o.newMessage("AUTH",3,0,t,new DataView(n.buffer))}static checksum(e){let t=0;for(let n=0;n<e.byteLength;n++)t+=e.getUint8(n);return 4294967295&t}}t.Message=o},734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.MessageChannel=void 0;const s=n(397),o=n(864);t.MessageChannel=class{constructor(e,t,n){this.transport=e,this.options=t,this.listener=n,this.active=!0,this.readLoop()}readLoop(){return i(this,void 0,void 0,function*(){let e;do{e=yield this.read(),this.options.debug&&console.log("<<<",e),this.listener.newMessage(e)}while(this.active)})}readHeader(){return i(this,void 0,void 0,function*(){const e=yield this.transport.read(24);return o.MessageHeader.parse(e,this.options.useChecksum)})}read(){return i(this,void 0,void 0,function*(){const e=yield this.readHeader();let t;return e.cmd,e.length>0&&(t=yield this.transport.read(e.length)),new s.Message(e,t)})}close(){this.active=!1}write(e){return i(this,void 0,void 0,function*(){this.options.debug&&console.log(">>>",e);const t=e.header.toDataView();yield this.transport.write(t.buffer),e.data&&(yield this.transport.write(e.data.buffer))})}}},864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHeader=void 0;const i=n(351);class s{constructor(e,t,n,i,s){this.cmd=e,this.arg0=t,this.arg1=n,this.length=i,this.checksum=s}toDataView(){const e=new DataView(new ArrayBuffer(24)),t=(0,i.encodeCmd)(this.cmd),n=4294967295^t;return e.setUint32(0,t,!0),e.setUint32(4,this.arg0,!0),e.setUint32(8,this.arg1,!0),e.setUint32(12,this.length,!0),e.setUint32(16,this.checksum,!0),e.setUint32(20,n,!0),e}static parse(e,t=!1){const n=e.getUint32(0,!0),o=e.getUint32(4,!0),r=e.getUint32(8,!0),a=e.getUint32(12,!0),c=e.getUint32(16,!0);if(t&&e.byteLength>20&&-1!==(n^e.getUint32(20,!0)))throw new Error("magic mismatch");return new s((0,i.decodeCmd)(n),o,r,a,c)}}t.MessageHeader=s},257(e,t){Object.defineProperty(t,"__esModule",{value:!0})},858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var s=Object.getOwnPropertyDescriptor(t,n);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,s)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),s=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),s(n(397),t),s(n(734),t),s(n(864),t),s(n(257),t)},225(e,t){Object.defineProperty(t,"__esModule",{value:!0})},289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.WebUsbTransport=void 0;const s=n(351),o={classCode:255,subclassCode:66,protocolCode:1},r={classCode:255,subclassCode:66,protocolCode:3},a=[o,r];class c{constructor(e,t,n,i,s,o=console.log){this.device=e,this.match=t,this.endpointIn=n,this.endpointOut=i,this.options=s,this.log=o}close(){return i(this,void 0,void 0,function*(){yield this.device.releaseInterface(this.match.intf.interfaceNumber),yield this.device.close()})}write(e){return i(this,void 0,void 0,function*(){this.options.dump&&(0,s.hexdump)(new DataView(e),this.endpointOut+"==> "),yield this.device.transferOut(this.endpointOut,e)})}read(e){return i(this,void 0,void 0,function*(){const t=yield this.device.transferIn(this.endpointIn,e);if(!t.data)throw new Error("Response didn't contain any data");return t.data})}isAdb(){return null!=c.findMatch(this.device,o)}isFastboot(){return null!=c.findMatch(this.device,r)}static open(e){return i(this,void 0,void 0,function*(){const t=yield navigator.usb.requestDevice({filters:a});yield t.open();const n=this.findMatch(t,o);if(!n)throw new Error("Could not find an ADB device");yield t.selectConfiguration(n.conf.configurationValue),yield t.claimInterface(n.intf.interfaceNumber);const i=c.getEndpointNum(n.alternate.endpoints,"in"),s=c.getEndpointNum(n.alternate.endpoints,"out"),r=new c(t,n,i,s,e);return e.debug&&console.log("Created new Transport: ",r),r})}static findMatch(e,t){for(const n of e.configurations)for(const e of n.interfaces)for(const i of e.alternates)if(t.classCode===i.interfaceClass&&t.subclassCode===i.interfaceSubclass&&t.protocolCode===i.interfaceProtocol)return{conf:n,intf:e,alternate:i};return null}static getEndpointNum(e,t,n="bulk"){for(const i of e)if(i.direction===t&&i.type===n)return i.endpointNumber;throw new Error(`Cannot find ${t} endpoint`)}}t.WebUsbTransport=c},980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var s=Object.getOwnPropertyDescriptor(t,n);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,s)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),s=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),s(n(225),t),s(n(289),t)}},t={};function n(i){var s=t[i];if(void 0!==s)return s.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,n),o.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i=n(834),s=function(e,t,n,i){return new(n||(n=Promise))(function(s,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};const o=document.querySelector("#connect"),r=document.querySelector("#disconnect"),a=document.querySelector("#output"),c=document.querySelector("#input"),d={debug:!0,useChecksum:!1,dump:!1,keySize:2048},u=new class{constructor(){this.keys=[]}loadKeys(){return s(this,void 0,void 0,function*(){return this.keys})}saveKey(e){return s(this,void 0,void 0,function*(){this.keys.push(e),console.log("Saving Key"+e)})}};let h=null,l=null,f=null;function y(e){const t=document.createElement("span");t.innerText=e,a.appendChild(t),a.scrollTop=a.scrollHeight}o.addEventListener("click",e=>s(void 0,void 0,void 0,function*(){try{h=yield i.WebUsbTransport.open(d),l=new i.AdbClient(h,d,u),yield l.connect(),f=yield l.interactiveShell(y),r.classList.toggle("hidden"),o.classList.toggle("hidden")}catch(e){console.error("Connection Failed: ",e)}})),r.addEventListener("click",e=>s(void 0,void 0,void 0,function*(){try{yield null==f?void 0:f.close(),yield null==h?void 0:h.close(),h=null,l=null,f=null}catch(e){console.error("Error closing the connection",e)}r.classList.toggle("hidden"),o.classList.toggle("hidden")})),c.addEventListener("keyup",e=>{return 13!==e.keyCode||(e.preventDefault(),t=c.value,f.write(t+"\n"),c.value="",!1);var t})})();
================================================
FILE: demo/public/js/interactiveshell.d.ts
================================================
export {};
//# sourceMappingURL=interactiveshell.d.ts.map
================================================
FILE: demo/public/js/interactiveshell.js
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AdbClient, WebUsbTransport } from 'wadb';
const connectButton = document.querySelector('#connect');
const disconnectButton = document.querySelector('#disconnect');
const output = document.querySelector('#output');
const input = document.querySelector('#input');
class MyKeyStore {
constructor() {
this.keys = [];
}
loadKeys() {
return __awaiter(this, void 0, void 0, function* () {
return this.keys;
});
}
saveKey(key) {
return __awaiter(this, void 0, void 0, function* () {
this.keys.push(key);
console.log('Saving Key' + key);
});
}
}
const options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
const keyStore = new MyKeyStore();
let transport = null;
let adbClient = null;
let shell = null;
function appendToCode(text) {
const span = document.createElement('span');
span.innerText = text;
output.appendChild(span);
output.scrollTop = output.scrollHeight;
}
function sendCommand(cmd) {
shell.write(cmd + '\n');
}
connectButton.addEventListener('click', (e) => __awaiter(void 0, void 0, void 0, function* () {
try {
transport = yield WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
yield adbClient.connect();
shell = yield adbClient.interactiveShell(appendToCode);
disconnectButton.classList.toggle('hidden');
connectButton.classList.toggle('hidden');
}
catch (e) {
console.error('Connection Failed: ', e);
}
}));
disconnectButton.addEventListener('click', (e) => __awaiter(void 0, void 0, void 0, function* () {
try {
yield (shell === null || shell === void 0 ? void 0 : shell.close());
yield (transport === null || transport === void 0 ? void 0 : transport.close());
transport = null;
adbClient = null;
shell = null;
}
catch (e) {
console.error('Error closing the connection', e);
}
disconnectButton.classList.toggle('hidden');
connectButton.classList.toggle('hidden');
}));
input.addEventListener('keyup', (e) => {
if (e.keyCode === 13) {
e.preventDefault();
sendCommand(input.value);
input.value = '';
return false;
}
return true;
});
//# sourceMappingURL=interactiveshell.js.map
================================================
FILE: demo/public/js/livestream.bundle.js
================================================
(()=>{"use strict";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(620),t),o(n(449),t),o(n(540),t),o(n(432),t),o(n(16),t),o(n(908),t),o(n(870),t),o(n(858),t),o(n(980),t)},620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AdbClient=void 0;const o=n(858),s=n(351),r=n(449),a=n(908),c=n(16),d=n(364),u=n(681);class l{constructor(e,t,n){this.transport=e,this.options=t,this.keyStore=n,this.messageQueue=new d.AsyncBlockingQueue,this.openStreams=new Set,this.messageChannel=new o.MessageChannel(e,t,this)}registerStream(e){this.openStreams.add(e)}unregisterStream(e){this.openStreams.delete(e)}newMessage(e){const t=Array.from(this.openStreams);for(const n of t)if(n.consumeMessage(e))return;this.messageQueue.enqueue(e)}awaitMessage(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}connect(){return i(this,void 0,void 0,function*(){const e=this.options.useChecksum?16777216:16777217,t=o.Message.cnxn(e,262144,"host::\0",this.options.useChecksum);let n;yield this.sendMessage(t);do{n=yield this.awaitMessage()}while("CNXN"!==n.header.cmd&&"AUTH"!==n.header.cmd);if("CNXN"===n.header.cmd){if(!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)}if(n=yield this.doAuth(n),!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)})}disconnect(){return i(this,void 0,void 0,function*(){this.messageChannel.close()})}shell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,`shell:${e}`,this.options),n=yield t.read();return yield t.close(),n.dataAsString()||""})}framebuffer(){return i(this,void 0,void 0,function*(){return u.Framebuffer.create(this,this.options)})}interactiveShell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,"shell:",this.options);return new c.Shell(t,e)})}sync(){return i(this,void 0,void 0,function*(){return yield a.Stream.open(this,"sync:",this.options)})}pull(e){return i(this,void 0,void 0,function*(){const t=yield this.sync(),n=yield t.pull(e);return yield t.close(),n})}push(e,t,n,o){return i(this,void 0,void 0,function*(){const i=yield this.sync();yield i.push(e,t,n,o),yield i.close()})}doAuth(e){return i(this,void 0,void 0,function*(){if("AUTH"!==e.header.cmd)throw new Error("Not an AUTH response");if(1!==e.header.arg0)throw new Error(`\n Invalid AUTH parameter. Expected 1 and received ${e.header.arg0}`);if(!e.data)throw new Error("AUTH message doens't contain data");const t=e.data.buffer,n=yield this.keyStore.loadKeys();for(const e of n){const n=yield crypto.subtle.sign("RSASSA-PKCS1-v1_5",e.privateKey,t),i=o.Message.authSignature(new DataView(n),this.options.useChecksum);yield this.sendMessage(i);const s=yield this.awaitMessage();if("CNXN"===s.header.cmd)return s;console.log("Received message ",s,"from phone")}const i=yield l.generateKey(this.options.dump,this.options.keySize);yield this.keyStore.saveKey(i);const s=new DataView(yield crypto.subtle.exportKey("spki",i.publicKey)),r=o.Message.authPublicKey(s,this.options.useChecksum);yield this.sendMessage(r),this.options.debug&&console.log("Waiting for key to be accepted on the device.");const a=yield this.awaitMessage();if("CNXN"!==a.header.cmd)throw console.error("AUTH failed. Phone didn't accept key",a),new Error("AUTH failed. Phone didn't accept key");return a})}sendMessage(e){return i(this,void 0,void 0,function*(){yield this.messageChannel.write(e)})}static generateKey(e,t){return i(this,void 0,void 0,function*(){const n=e,i=yield crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:t,publicExponent:new Uint8Array([1,0,1]),hash:{name:"SHA-1"}},n,["sign","verify"]);return e&&(yield(0,s.privateKeyDump)(i)),i})}}t.AdbClient=l},449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectionInformation=void 0;const n="<unkwnown>";class i{constructor(e,t,n,i){this.productName=e,this.productDevice=t,this.productModel=n,this.features=i}static fromDataView(e){const t=(new TextDecoder).decode(e);return i.fromString(t)}static fromString(e){const t=e.indexOf("::"),o=e.substring(t+2).split(";");let s=n,r=n,a=n,c=[];for(const e of o)e.startsWith("ro.product.name")?s=e.substring(16):e.startsWith("ro.product.model")?a=e.substring(17):e.startsWith("ro.product.device")?r=e.substring(18):e.startsWith("features")&&(c=e.substring(9).split(","));return new i(s,r,a,c)}}t.AdbConnectionInformation=i},681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Framebuffer=void 0;const o=n(908);class s{constructor(e,t,n,i,o,s,r,a,c,d,u,l,h,f,y){this.version=e,this.bpp=t,this.colorSpace=n,this.size=i,this.width=o,this.height=s,this.redOffset=r,this.redLength=a,this.blueOffset=c,this.blueLength=d,this.greenOffset=u,this.greenLength=l,this.alphaOffset=h,this.alphaLength=f,this.imageData=y}static create(e,t){return i(this,void 0,void 0,function*(){var n;const i=yield o.Stream.open(e,"framebuffer:",t);let r=yield i.read();if("WRTE"!==r.header.cmd)throw yield i.write("CLSE"),new Error(`Expected WRTE message but received ${r.header.cmd}`);if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");yield i.write("OKAY");const a=r.data.getUint32(0,!0),c=r.data.getUint32(4,!0),d=r.data.getUint32(8,!0),u=r.data.getUint32(12,!0),l=r.data.getUint32(16,!0),h=r.data.getUint32(20,!0),f=r.data.getUint32(24,!0),y=r.data.getUint32(28,!0),g=r.data.getUint32(32,!0),w=r.data.getUint32(36,!0),v=r.data.getUint32(40,!0),p=r.data.getUint32(44,!0),m=r.data.getUint32(48,!0),b=r.data.getUint32(52,!0),E=new Uint8Array(u);let M=0,_=new Uint8Array(r.data.buffer.slice(s.BYTE_LENGTH));for(E.set(_,0),M=_.length;M<u&&(r=yield i.read(),"CLSE"!==r.header.cmd);){if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");_=new Uint8Array(null===(n=r.data)||void 0===n?void 0:n.buffer),E.set(_,M),M+=_.length,yield i.write("OKAY")}return yield i.close(),new s(a,c,d,u,l,h,f,y,g,w,v,p,m,b,Uint8ClampedArray.from(E))})}}t.Framebuffer=s,s.BYTE_LENGTH=56},351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};function i(e,t,n){const i=t-e.length;let o="";for(let e=0;e<i;e++)o+=n;return o+e}function o(e){return i(e.toString(16),2,"0")}function s(e){return i(e.toString(16),4,"0")}function r(e){return btoa(new Uint8Array(e).reduce((e,t)=>e+String.fromCharCode(t),""))}Object.defineProperty(t,"__esModule",{value:!0}),t.toHex8=o,t.toHex16=s,t.toHex32=function(e){return i(e.toString(16),8,"0")},t.hexdump=function(e,t=""){const n=new TextDecoder;for(let i=0;i<e.byteLength;i+=16){const r=e.byteLength-i>16?16:e.byteLength-i;let a,c=t+s(i)+" ";for(a=0;a<r;a++)c+=" "+o(e.getUint8(i+a));for(;a<16;a++)c+=" ";c+=" | "+n.decode(new DataView(e.buffer,i,r)),console.log(c)}},t.toB64=r,t.privateKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.privateKey.extractable)return void console.log("cannot dump the private key, it's not extractable");const t=yield crypto.subtle.exportKey("pkcs8",e.privateKey);console.log(`-----BEGIN PRIVATE KEY-----\n${r(t)}\n-----END PRIVATE KEY-----`)})},t.publicKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.publicKey.extractable)return void console.log("cannot dump the public key, it's not extractable");const t=yield crypto.subtle.exportKey("spki",e.publicKey);console.log(`-----BEGIN PUBLIC KEY-----\n${r(t)}'\n-----END PUBLIC KEY-----`)})},t.encodeCmd=function(e){const t=(new TextEncoder).encode(e).buffer;return new DataView(t).getUint32(0,!0)},t.decodeCmd=function(e){const t=new TextDecoder,n=new ArrayBuffer(4);return new DataView(n).setUint32(0,e,!0),t.decode(n)}},540(e,t){Object.defineProperty(t,"__esModule",{value:!0})},432(e,t){Object.defineProperty(t,"__esModule",{value:!0})},364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AsyncBlockingQueue=t.Queue=void 0;class i{constructor(e){this.data=e}}class o{enqueue(e){const t=new i(e);this.tail&&(this.tail.next=t),this.tail=t,this.head||(this.head=this.tail)}dequeue(){if(this.isEmpty())throw new Error("Cannot dequeue. Queue is empty");const e=this.head.data;return this.head=this.head.next,e}isEmpty(){return null==this.head}}t.Queue=o,t.AsyncBlockingQueue=class{constructor(){this.promiseQueue=new o,this.resolverQueue=new o}add(){const e=new Promise(e=>{this.resolverQueue.enqueue(e)});this.promiseQueue.enqueue(e)}enqueue(e){this.resolverQueue.isEmpty()&&this.add(),this.resolverQueue.dequeue()(e)}dequeue(){return n(this,void 0,void 0,function*(){return this.promiseQueue.isEmpty()&&this.add(),this.promiseQueue.dequeue()})}hasPendingPromises(){return!this.promiseQueue.isEmpty()}hasPendingResolvers(){return!this.resolverQueue.isEmpty()}}},16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Shell=void 0,t.Shell=class{constructor(e,t){this.stream=e,this.callbackFunction=t,this.textDecoder=new TextDecoder,this.textEncoder=new TextEncoder,this.messageListener=[],this.closed=!1,this.loopRead()}loopRead(){return n(this,void 0,void 0,function*(){try{let e;do{if(e=yield this.stream.read(),"WRTE"===e.header.cmd){this.stream.write("OKAY");const t=this.textDecoder.decode(e.data);this.callbackFunction&&this.callbackFunction(t)}for(const t of this.messageListener)t(e)}while(!this.closed)}catch(e){console.error("loopRead crashed",e)}this.stream.client.unregisterStream(this.stream)})}waitForMessage(e){return new Promise(t=>{const n=i=>{if(i.header.cmd===e){const e=this.messageListener.indexOf(n);this.messageListener.splice(e,1),t(i)}};this.messageListener.push(n)})}write(e){return n(this,void 0,void 0,function*(){const t=this.textEncoder.encode(e);yield this.stream.write("WRTE",new DataView(t.buffer)),yield this.waitForMessage("OKAY")})}close(){return n(this,void 0,void 0,function*(){this.closed=!0,yield this.write("CLSE")})}}},908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Stream=void 0;const o=n(858),s=n(351),r=n(870),a=n(364);class c{constructor(e,t,n,i,o){this.client=e,this.service=t,this.localId=n,this.remoteId=i,this.options=o,this.messageQueue=new a.AsyncBlockingQueue}close(){return i(this,void 0,void 0,function*(){yield this.write("CLSE"),this.options.debug&&(console.log(`Closed stream ${this.service}`),console.log(` local_id: 0x${(0,s.toHex32)(this.localId)}`),console.log(` remote_id: 0x${(0,s.toHex32)(this.remoteId)}`)),this.client.unregisterStream(this)})}consumeMessage(e){return 0!==e.header.arg0&&e.header.arg0===this.remoteId&&0!==e.header.arg1&&e.header.arg1===this.localId&&(this.messageQueue.enqueue(e),!0)}write(e,t){return i(this,void 0,void 0,function*(){const n=this.newMessage(e,t);yield this.client.sendMessage(n)})}read(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}sendReceive(e,t){return i(this,void 0,void 0,function*(){yield this.client.sendMessage(e);const n=yield this.read();if(n.header.cmd!==t)throw new Error("WRTE/SEND failed: "+n)})}pull(e){return i(this,void 0,void 0,function*(){const t=(new TextEncoder).encode(e),n=new r.SyncFrame("RECV",t.byteLength),i=this.newMessage("WRTE",n.toDataView());yield this.client.sendMessage(i);const o=yield this.read();if("OKAY"!==o.header.cmd)throw new Error("WRTE/RECV failed: "+o);const s=this.newMessage("WRTE",new DataView(t.buffer));yield this.client.sendMessage(s);const a=yield this.read();if("OKAY"!==a.header.cmd)throw new Error("WRTE/filename failed: "+a);const c=this.newMessage("OKAY");let d=yield this.read();yield this.client.sendMessage(c);let u=r.SyncFrame.fromDataView(new DataView(d.data.buffer.slice(0,8))),l=new Uint8Array(d.data.buffer.slice(8));const h=[];for(;"DONE"!==u.cmd;){for(;u.byteLength>=l.byteLength;){d=yield this.read(),yield this.client.sendMessage(c);const e=l.byteLength+d.data.byteLength,t=new Uint8Array(e);t.set(l,0),t.set(new Uint8Array(d.data.buffer),l.byteLength),l=t}h.push(l.slice(0,u.byteLength).buffer),l=l.slice(u.byteLength),u=r.SyncFrame.fromDataView(new DataView(l.slice(0,8).buffer)),l=l.slice(8)}return new Blob(h)})}push(e,t,n,o){return i(this,void 0,void 0,function*(){const i=new FileReader,s=new TextEncoder,a=s.encode(t),c=new r.SyncFrame("SEND",t.length+1+n.length),d=this.newMessage("WRTE",c.toDataView());yield this.sendReceive(d,"OKAY");const u=this.newMessage("WRTE",new DataView(a.buffer));yield this.sendReceive(u,"OKAY");const l=this.newMessage("WRTE",new DataView(s.encode(","+n).buffer));yield this.sendReceive(l,"OKAY");const h=new Promise((t,n)=>{i.onload=e=>t(e.target.result),i.onerror=n,i.readAsArrayBuffer(e)}),f=yield h,y=[];for(let e=0;e<f.byteLength;e+=o)y.push(f.slice(e,Math.min(e+o,f.byteLength)));for(const e of y){const t=new r.SyncFrame("DATA",e.byteLength),n=this.newMessage("WRTE",t.toDataView());yield this.sendReceive(n,"OKAY");const i=new DataView(e),o=this.newMessage("WRTE",i);yield this.sendReceive(o,"OKAY")}const g=new r.SyncFrame("DONE",Math.round(Date.now()/1e3)),w=this.newMessage("WRTE",g.toDataView());yield this.client.sendMessage(w);const v=this.newMessage("OKAY");yield this.sendReceive(v,"OKAY")})}newMessage(e,t){return o.Message.newMessage(e,this.localId,this.remoteId,this.options.useChecksum,t)}static open(e,t,n){return i(this,void 0,void 0,function*(){const i=c.nextId++;let r=0;const a=o.Message.open(i,r,t,n.useChecksum);let d;yield e.sendMessage(a);do{d=yield e.awaitMessage()}while(d.header.arg1!==i);if("OKAY"!==d.header.cmd)throw new Error("OPEN Failed");r=d.header.arg0,n.debug&&(console.log(`Opened stream ${t}`),console.log(` local_id: 0x${(0,s.toHex32)(i)}`),console.log(` remote_id: 0x${(0,s.toHex32)(r)}`));const u=new c(e,t,i,r,n);return e.registerStream(u),u})}}t.Stream=c,c.nextId=1},870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=void 0;const i=n(351);class o{constructor(e,t){this.cmd=e,this.byteLength=t}toDataView(){const e=new ArrayBuffer(8),t=(0,i.encodeCmd)(this.cmd),n=new DataView(e);return n.setUint32(0,t,!0),n.setUint32(4,this.byteLength,!0),n}static fromDataView(e){const t=(0,i.decodeCmd)(e.getUint32(0,!0)),n=e.getUint32(4,!0);return new o(t,n)}}t.SyncFrame=o},397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=void 0;const i=n(864),o=n(351);class s{constructor(e,t){this.header=e,this.data=t}dataAsString(){return this.data?(new TextDecoder).decode(this.data):null}static newMessage(e,t,n,o,r){let a=0,c=0;r&&(c=r.byteLength,o&&(a=s.checksum(r)));const d=new i.MessageHeader(e,t,n,c,a);return new s(d,r)}static open(e,t,n,i){const o=new TextEncoder,r=new DataView(o.encode(n+"\0").buffer);return s.newMessage("OPEN",e,t,i,r)}static cnxn(e,t,n,i){const o=new TextEncoder,r=new DataView(o.encode(n).buffer);return s.newMessage("CNXN",e,t,i,r)}static authSignature(e,t){return s.newMessage("AUTH",2,0,t,e)}static authPublicKey(e,t){const n=(new TextEncoder).encode((0,o.toB64)(e.buffer)+"\0");return s.newMessage("AUTH",3,0,t,new DataView(n.buffer))}static checksum(e){let t=0;for(let n=0;n<e.byteLength;n++)t+=e.getUint8(n);return 4294967295&t}}t.Message=s},734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.MessageChannel=void 0;const o=n(397),s=n(864);t.MessageChannel=class{constructor(e,t,n){this.transport=e,this.options=t,this.listener=n,this.active=!0,this.readLoop()}readLoop(){return i(this,void 0,void 0,function*(){let e;do{e=yield this.read(),this.options.debug&&console.log("<<<",e),this.listener.newMessage(e)}while(this.active)})}readHeader(){return i(this,void 0,void 0,function*(){const e=yield this.transport.read(24);return s.MessageHeader.parse(e,this.options.useChecksum)})}read(){return i(this,void 0,void 0,function*(){const e=yield this.readHeader();let t;return e.cmd,e.length>0&&(t=yield this.transport.read(e.length)),new o.Message(e,t)})}close(){this.active=!1}write(e){return i(this,void 0,void 0,function*(){this.options.debug&&console.log(">>>",e);const t=e.header.toDataView();yield this.transport.write(t.buffer),e.data&&(yield this.transport.write(e.data.buffer))})}}},864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHeader=void 0;const i=n(351);class o{constructor(e,t,n,i,o){this.cmd=e,this.arg0=t,this.arg1=n,this.length=i,this.checksum=o}toDataView(){const e=new DataView(new ArrayBuffer(24)),t=(0,i.encodeCmd)(this.cmd),n=4294967295^t;return e.setUint32(0,t,!0),e.setUint32(4,this.arg0,!0),e.setUint32(8,this.arg1,!0),e.setUint32(12,this.length,!0),e.setUint32(16,this.checksum,!0),e.setUint32(20,n,!0),e}static parse(e,t=!1){const n=e.getUint32(0,!0),s=e.getUint32(4,!0),r=e.getUint32(8,!0),a=e.getUint32(12,!0),c=e.getUint32(16,!0);if(t&&e.byteLength>20&&-1!==(n^e.getUint32(20,!0)))throw new Error("magic mismatch");return new o((0,i.decodeCmd)(n),s,r,a,c)}}t.MessageHeader=o},257(e,t){Object.defineProperty(t,"__esModule",{value:!0})},858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(397),t),o(n(734),t),o(n(864),t),o(n(257),t)},225(e,t){Object.defineProperty(t,"__esModule",{value:!0})},289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.WebUsbTransport=void 0;const o=n(351),s={classCode:255,subclassCode:66,protocolCode:1},r={classCode:255,subclassCode:66,protocolCode:3},a=[s,r];class c{constructor(e,t,n,i,o,s=console.log){this.device=e,this.match=t,this.endpointIn=n,this.endpointOut=i,this.options=o,this.log=s}close(){return i(this,void 0,void 0,function*(){yield this.device.releaseInterface(this.match.intf.interfaceNumber),yield this.device.close()})}write(e){return i(this,void 0,void 0,function*(){this.options.dump&&(0,o.hexdump)(new DataView(e),this.endpointOut+"==> "),yield this.device.transferOut(this.endpointOut,e)})}read(e){return i(this,void 0,void 0,function*(){const t=yield this.device.transferIn(this.endpointIn,e);if(!t.data)throw new Error("Response didn't contain any data");return t.data})}isAdb(){return null!=c.findMatch(this.device,s)}isFastboot(){return null!=c.findMatch(this.device,r)}static open(e){return i(this,void 0,void 0,function*(){const t=yield navigator.usb.requestDevice({filters:a});yield t.open();const n=this.findMatch(t,s);if(!n)throw new Error("Could not find an ADB device");yield t.selectConfiguration(n.conf.configurationValue),yield t.claimInterface(n.intf.interfaceNumber);const i=c.getEndpointNum(n.alternate.endpoints,"in"),o=c.getEndpointNum(n.alternate.endpoints,"out"),r=new c(t,n,i,o,e);return e.debug&&console.log("Created new Transport: ",r),r})}static findMatch(e,t){for(const n of e.configurations)for(const e of n.interfaces)for(const i of e.alternates)if(t.classCode===i.interfaceClass&&t.subclassCode===i.interfaceSubclass&&t.protocolCode===i.interfaceProtocol)return{conf:n,intf:e,alternate:i};return null}static getEndpointNum(e,t,n="bulk"){for(const i of e)if(i.direction===t&&i.type===n)return i.endpointNumber;throw new Error(`Cannot find ${t} endpoint`)}}t.WebUsbTransport=c},980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(225),t),o(n(289),t)}},t={};function n(i){var o=t[i];if(void 0!==o)return o.exports;var s=t[i]={exports:{}};return e[i].call(s.exports,s,s.exports,n),s.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i=n(834),o=function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};let s,r;const a=document.querySelector("#connect"),c=document.querySelector("#disconnect"),d=document.querySelector("#start"),u=document.querySelector("#stop"),l=document.querySelector("#video"),h=document.querySelector("#download"),f=document.querySelector("#status"),y={debug:!0,useChecksum:!1,dump:!1,keySize:2048},g=new class{constructor(){this.keys=[]}loadKeys(){return o(this,void 0,void 0,function*(){return this.keys})}saveKey(e){return o(this,void 0,void 0,function*(){this.keys.push(e),console.log("Saving Key"+e)})}};a.addEventListener("click",e=>o(void 0,void 0,void 0,function*(){try{s=yield i.WebUsbTransport.open(y),r=new i.AdbClient(s,y,g),f.textContent="Accept prompt on device";const e=yield r.connect();f.textContent="Connected and ready",console.log("Connected: ",e),a.classList.toggle("hidden"),c.classList.toggle("hidden")}catch(e){console.error("Connection Failed: ",e),f.textContent="Failed to connect to a device"}})),c.addEventListener("click",e=>o(void 0,void 0,void 0,function*(){try{if(r){try{yield r.disconnect()}catch(e){console.log("Error disconnecting ADB Client: ",e)}r=null}s&&(yield s.close(),s=null),a.classList.toggle("hidden"),c.classList.toggle("hidden"),f.textContent="Connect to a device to start"}catch(e){console.error("Disconnecting Failed: ",e)}}));let w=null;d.addEventListener("click",()=>o(void 0,void 0,void 0,function*(){f.textContent="Recording...",u.classList.toggle("hidden"),d.classList.toggle("hidden");const e=new TextDecoder;w=yield i.Stream.open(r,"exec:screenrecord --output-format=h264 -",y);const t=[];let n,o=0;for(;console.log(++o),n=yield w.read(),yield w.write("OKAY"),"CLSE"!==n.header.cmd;)console.log(e.decode(n.data.buffer)),t.push(new Uint8Array(n.data.buffer));console.log(t.length);const s=URL.createObjectURL(new Blob(t));l.src=s,h.href=s})),u.addEventListener("click",()=>o(void 0,void 0,void 0,function*(){yield null==w?void 0:w.write("CLSE")}))})();
================================================
FILE: demo/public/js/livestream.d.ts
================================================
export {};
//# sourceMappingURL=livestream.d.ts.map
================================================
FILE: demo/public/js/livestream.js
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { WebUsbTransport, AdbClient, Stream } from 'wadb';
let transport;
let adbClient;
const connectButton = document.querySelector('#connect');
const disconnectButton = document.querySelector('#disconnect');
const startButton = document.querySelector('#start');
const stopButton = document.querySelector('#stop');
const video = document.querySelector('#video');
const download = document.querySelector('#download');
const status = document.querySelector('#status');
const options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
class MyKeyStore {
constructor() {
this.keys = [];
}
loadKeys() {
return __awaiter(this, void 0, void 0, function* () {
return this.keys;
});
}
saveKey(key) {
return __awaiter(this, void 0, void 0, function* () {
this.keys.push(key);
console.log('Saving Key' + key);
});
}
}
const keyStore = new MyKeyStore();
connectButton.addEventListener('click', (_) => __awaiter(void 0, void 0, void 0, function* () {
try {
transport = yield WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
status.textContent = 'Accept prompt on device';
const adbConnectionInformation = yield adbClient.connect();
status.textContent = 'Connected and ready';
console.log('Connected: ', adbConnectionInformation);
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
}
catch (e) {
console.error('Connection Failed: ', e);
status.textContent = 'Failed to connect to a device';
}
}));
disconnectButton.addEventListener('click', (_) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (adbClient) {
try {
yield adbClient.disconnect();
}
catch (e) {
console.log('Error disconnecting ADB Client: ', e);
}
adbClient = null;
}
if (transport) {
yield transport.close();
transport = null;
}
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
status.textContent = 'Connect to a device to start';
}
catch (e) {
console.error('Disconnecting Failed: ', e);
}
}));
let shell = null;
startButton.addEventListener('click', () => __awaiter(void 0, void 0, void 0, function* () {
// const mediaSource = new MediaSource();
// const url = URL.createObjectURL(mediaSource);
// video.src = url;
status.textContent = 'Recording...';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
const textDecoder = new TextDecoder();
// mediaSource.addEventListener('sourceopen', async () => {
shell = yield Stream.open(adbClient, 'exec:screenrecord --output-format=h264 -', options);
// const audioSourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="mp4a.40.2"');
const chunks = [];
let i = 0;
let msg;
while (true) {
console.log(++i);
msg = yield shell.read();
yield shell.write('OKAY');
if (msg.header.cmd === 'CLSE') {
break;
}
console.log(textDecoder.decode(msg.data.buffer));
chunks.push(new Uint8Array(msg.data.buffer));
}
console.log(chunks.length);
const objectUrl = URL.createObjectURL(new Blob(chunks));
video.src = objectUrl;
download.href = objectUrl;
// });
}));
stopButton.addEventListener('click', () => __awaiter(void 0, void 0, void 0, function* () {
yield (shell === null || shell === void 0 ? void 0 : shell.write('CLSE'));
}));
//# sourceMappingURL=livestream.js.map
================================================
FILE: demo/public/js/screenrecord.bundle.js
================================================
(()=>{"use strict";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(620),t),o(n(449),t),o(n(540),t),o(n(432),t),o(n(16),t),o(n(908),t),o(n(870),t),o(n(858),t),o(n(980),t)},620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AdbClient=void 0;const o=n(858),s=n(351),r=n(449),a=n(908),c=n(16),d=n(364),u=n(681);class l{constructor(e,t,n){this.transport=e,this.options=t,this.keyStore=n,this.messageQueue=new d.AsyncBlockingQueue,this.openStreams=new Set,this.messageChannel=new o.MessageChannel(e,t,this)}registerStream(e){this.openStreams.add(e)}unregisterStream(e){this.openStreams.delete(e)}newMessage(e){const t=Array.from(this.openStreams);for(const n of t)if(n.consumeMessage(e))return;this.messageQueue.enqueue(e)}awaitMessage(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}connect(){return i(this,void 0,void 0,function*(){const e=this.options.useChecksum?16777216:16777217,t=o.Message.cnxn(e,262144,"host::\0",this.options.useChecksum);let n;yield this.sendMessage(t);do{n=yield this.awaitMessage()}while("CNXN"!==n.header.cmd&&"AUTH"!==n.header.cmd);if("CNXN"===n.header.cmd){if(!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)}if(n=yield this.doAuth(n),!n.data)throw new Error("Connection doesn't have data");return r.AdbConnectionInformation.fromDataView(n.data)})}disconnect(){return i(this,void 0,void 0,function*(){this.messageChannel.close()})}shell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,`shell:${e}`,this.options),n=yield t.read();return yield t.close(),n.dataAsString()||""})}framebuffer(){return i(this,void 0,void 0,function*(){return u.Framebuffer.create(this,this.options)})}interactiveShell(e){return i(this,void 0,void 0,function*(){const t=yield a.Stream.open(this,"shell:",this.options);return new c.Shell(t,e)})}sync(){return i(this,void 0,void 0,function*(){return yield a.Stream.open(this,"sync:",this.options)})}pull(e){return i(this,void 0,void 0,function*(){const t=yield this.sync(),n=yield t.pull(e);return yield t.close(),n})}push(e,t,n,o){return i(this,void 0,void 0,function*(){const i=yield this.sync();yield i.push(e,t,n,o),yield i.close()})}doAuth(e){return i(this,void 0,void 0,function*(){if("AUTH"!==e.header.cmd)throw new Error("Not an AUTH response");if(1!==e.header.arg0)throw new Error(`\n Invalid AUTH parameter. Expected 1 and received ${e.header.arg0}`);if(!e.data)throw new Error("AUTH message doens't contain data");const t=e.data.buffer,n=yield this.keyStore.loadKeys();for(const e of n){const n=yield crypto.subtle.sign("RSASSA-PKCS1-v1_5",e.privateKey,t),i=o.Message.authSignature(new DataView(n),this.options.useChecksum);yield this.sendMessage(i);const s=yield this.awaitMessage();if("CNXN"===s.header.cmd)return s;console.log("Received message ",s,"from phone")}const i=yield l.generateKey(this.options.dump,this.options.keySize);yield this.keyStore.saveKey(i);const s=new DataView(yield crypto.subtle.exportKey("spki",i.publicKey)),r=o.Message.authPublicKey(s,this.options.useChecksum);yield this.sendMessage(r),this.options.debug&&console.log("Waiting for key to be accepted on the device.");const a=yield this.awaitMessage();if("CNXN"!==a.header.cmd)throw console.error("AUTH failed. Phone didn't accept key",a),new Error("AUTH failed. Phone didn't accept key");return a})}sendMessage(e){return i(this,void 0,void 0,function*(){yield this.messageChannel.write(e)})}static generateKey(e,t){return i(this,void 0,void 0,function*(){const n=e,i=yield crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:t,publicExponent:new Uint8Array([1,0,1]),hash:{name:"SHA-1"}},n,["sign","verify"]);return e&&(yield(0,s.privateKeyDump)(i)),i})}}t.AdbClient=l},449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectionInformation=void 0;const n="<unkwnown>";class i{constructor(e,t,n,i){this.productName=e,this.productDevice=t,this.productModel=n,this.features=i}static fromDataView(e){const t=(new TextDecoder).decode(e);return i.fromString(t)}static fromString(e){const t=e.indexOf("::"),o=e.substring(t+2).split(";");let s=n,r=n,a=n,c=[];for(const e of o)e.startsWith("ro.product.name")?s=e.substring(16):e.startsWith("ro.product.model")?a=e.substring(17):e.startsWith("ro.product.device")?r=e.substring(18):e.startsWith("features")&&(c=e.substring(9).split(","));return new i(s,r,a,c)}}t.AdbConnectionInformation=i},681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Framebuffer=void 0;const o=n(908);class s{constructor(e,t,n,i,o,s,r,a,c,d,u,l,h,f,g){this.version=e,this.bpp=t,this.colorSpace=n,this.size=i,this.width=o,this.height=s,this.redOffset=r,this.redLength=a,this.blueOffset=c,this.blueLength=d,this.greenOffset=u,this.greenLength=l,this.alphaOffset=h,this.alphaLength=f,this.imageData=g}static create(e,t){return i(this,void 0,void 0,function*(){var n;const i=yield o.Stream.open(e,"framebuffer:",t);let r=yield i.read();if("WRTE"!==r.header.cmd)throw yield i.write("CLSE"),new Error(`Expected WRTE message but received ${r.header.cmd}`);if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");yield i.write("OKAY");const a=r.data.getUint32(0,!0),c=r.data.getUint32(4,!0),d=r.data.getUint32(8,!0),u=r.data.getUint32(12,!0),l=r.data.getUint32(16,!0),h=r.data.getUint32(20,!0),f=r.data.getUint32(24,!0),g=r.data.getUint32(28,!0),y=r.data.getUint32(32,!0),v=r.data.getUint32(36,!0),w=r.data.getUint32(40,!0),p=r.data.getUint32(44,!0),m=r.data.getUint32(48,!0),b=r.data.getUint32(52,!0),E=new Uint8Array(u);let M=0,x=new Uint8Array(r.data.buffer.slice(s.BYTE_LENGTH));for(E.set(x,0),M=x.length;M<u&&(r=yield i.read(),"CLSE"!==r.header.cmd);){if(!r.data)throw yield i.write("CLSE"),new Error("message doesn't contain data");x=new Uint8Array(null===(n=r.data)||void 0===n?void 0:n.buffer),E.set(x,M),M+=x.length,yield i.write("OKAY")}return yield i.close(),new s(a,c,d,u,l,h,f,g,y,v,w,p,m,b,Uint8ClampedArray.from(E))})}}t.Framebuffer=s,s.BYTE_LENGTH=56},351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};function i(e,t,n){const i=t-e.length;let o="";for(let e=0;e<i;e++)o+=n;return o+e}function o(e){return i(e.toString(16),2,"0")}function s(e){return i(e.toString(16),4,"0")}function r(e){return btoa(new Uint8Array(e).reduce((e,t)=>e+String.fromCharCode(t),""))}Object.defineProperty(t,"__esModule",{value:!0}),t.toHex8=o,t.toHex16=s,t.toHex32=function(e){return i(e.toString(16),8,"0")},t.hexdump=function(e,t=""){const n=new TextDecoder;for(let i=0;i<e.byteLength;i+=16){const r=e.byteLength-i>16?16:e.byteLength-i;let a,c=t+s(i)+" ";for(a=0;a<r;a++)c+=" "+o(e.getUint8(i+a));for(;a<16;a++)c+=" ";c+=" | "+n.decode(new DataView(e.buffer,i,r)),console.log(c)}},t.toB64=r,t.privateKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.privateKey.extractable)return void console.log("cannot dump the private key, it's not extractable");const t=yield crypto.subtle.exportKey("pkcs8",e.privateKey);console.log(`-----BEGIN PRIVATE KEY-----\n${r(t)}\n-----END PRIVATE KEY-----`)})},t.publicKeyDump=function(e){return n(this,void 0,void 0,function*(){if(!e.publicKey.extractable)return void console.log("cannot dump the public key, it's not extractable");const t=yield crypto.subtle.exportKey("spki",e.publicKey);console.log(`-----BEGIN PUBLIC KEY-----\n${r(t)}'\n-----END PUBLIC KEY-----`)})},t.encodeCmd=function(e){const t=(new TextEncoder).encode(e).buffer;return new DataView(t).getUint32(0,!0)},t.decodeCmd=function(e){const t=new TextDecoder,n=new ArrayBuffer(4);return new DataView(n).setUint32(0,e,!0),t.decode(n)}},540(e,t){Object.defineProperty(t,"__esModule",{value:!0})},432(e,t){Object.defineProperty(t,"__esModule",{value:!0})},364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.AsyncBlockingQueue=t.Queue=void 0;class i{constructor(e){this.data=e}}class o{enqueue(e){const t=new i(e);this.tail&&(this.tail.next=t),this.tail=t,this.head||(this.head=this.tail)}dequeue(){if(this.isEmpty())throw new Error("Cannot dequeue. Queue is empty");const e=this.head.data;return this.head=this.head.next,e}isEmpty(){return null==this.head}}t.Queue=o,t.AsyncBlockingQueue=class{constructor(){this.promiseQueue=new o,this.resolverQueue=new o}add(){const e=new Promise(e=>{this.resolverQueue.enqueue(e)});this.promiseQueue.enqueue(e)}enqueue(e){this.resolverQueue.isEmpty()&&this.add(),this.resolverQueue.dequeue()(e)}dequeue(){return n(this,void 0,void 0,function*(){return this.promiseQueue.isEmpty()&&this.add(),this.promiseQueue.dequeue()})}hasPendingPromises(){return!this.promiseQueue.isEmpty()}hasPendingResolvers(){return!this.resolverQueue.isEmpty()}}},16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Shell=void 0,t.Shell=class{constructor(e,t){this.stream=e,this.callbackFunction=t,this.textDecoder=new TextDecoder,this.textEncoder=new TextEncoder,this.messageListener=[],this.closed=!1,this.loopRead()}loopRead(){return n(this,void 0,void 0,function*(){try{let e;do{if(e=yield this.stream.read(),"WRTE"===e.header.cmd){this.stream.write("OKAY");const t=this.textDecoder.decode(e.data);this.callbackFunction&&this.callbackFunction(t)}for(const t of this.messageListener)t(e)}while(!this.closed)}catch(e){console.error("loopRead crashed",e)}this.stream.client.unregisterStream(this.stream)})}waitForMessage(e){return new Promise(t=>{const n=i=>{if(i.header.cmd===e){const e=this.messageListener.indexOf(n);this.messageListener.splice(e,1),t(i)}};this.messageListener.push(n)})}write(e){return n(this,void 0,void 0,function*(){const t=this.textEncoder.encode(e);yield this.stream.write("WRTE",new DataView(t.buffer)),yield this.waitForMessage("OKAY")})}close(){return n(this,void 0,void 0,function*(){this.closed=!0,yield this.write("CLSE")})}}},908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.Stream=void 0;const o=n(858),s=n(351),r=n(870),a=n(364);class c{constructor(e,t,n,i,o){this.client=e,this.service=t,this.localId=n,this.remoteId=i,this.options=o,this.messageQueue=new a.AsyncBlockingQueue}close(){return i(this,void 0,void 0,function*(){yield this.write("CLSE"),this.options.debug&&(console.log(`Closed stream ${this.service}`),console.log(` local_id: 0x${(0,s.toHex32)(this.localId)}`),console.log(` remote_id: 0x${(0,s.toHex32)(this.remoteId)}`)),this.client.unregisterStream(this)})}consumeMessage(e){return 0!==e.header.arg0&&e.header.arg0===this.remoteId&&0!==e.header.arg1&&e.header.arg1===this.localId&&(this.messageQueue.enqueue(e),!0)}write(e,t){return i(this,void 0,void 0,function*(){const n=this.newMessage(e,t);yield this.client.sendMessage(n)})}read(){return i(this,void 0,void 0,function*(){return this.messageQueue.dequeue()})}sendReceive(e,t){return i(this,void 0,void 0,function*(){yield this.client.sendMessage(e);const n=yield this.read();if(n.header.cmd!==t)throw new Error("WRTE/SEND failed: "+n)})}pull(e){return i(this,void 0,void 0,function*(){const t=(new TextEncoder).encode(e),n=new r.SyncFrame("RECV",t.byteLength),i=this.newMessage("WRTE",n.toDataView());yield this.client.sendMessage(i);const o=yield this.read();if("OKAY"!==o.header.cmd)throw new Error("WRTE/RECV failed: "+o);const s=this.newMessage("WRTE",new DataView(t.buffer));yield this.client.sendMessage(s);const a=yield this.read();if("OKAY"!==a.header.cmd)throw new Error("WRTE/filename failed: "+a);const c=this.newMessage("OKAY");let d=yield this.read();yield this.client.sendMessage(c);let u=r.SyncFrame.fromDataView(new DataView(d.data.buffer.slice(0,8))),l=new Uint8Array(d.data.buffer.slice(8));const h=[];for(;"DONE"!==u.cmd;){for(;u.byteLength>=l.byteLength;){d=yield this.read(),yield this.client.sendMessage(c);const e=l.byteLength+d.data.byteLength,t=new Uint8Array(e);t.set(l,0),t.set(new Uint8Array(d.data.buffer),l.byteLength),l=t}h.push(l.slice(0,u.byteLength).buffer),l=l.slice(u.byteLength),u=r.SyncFrame.fromDataView(new DataView(l.slice(0,8).buffer)),l=l.slice(8)}return new Blob(h)})}push(e,t,n,o){return i(this,void 0,void 0,function*(){const i=new FileReader,s=new TextEncoder,a=s.encode(t),c=new r.SyncFrame("SEND",t.length+1+n.length),d=this.newMessage("WRTE",c.toDataView());yield this.sendReceive(d,"OKAY");const u=this.newMessage("WRTE",new DataView(a.buffer));yield this.sendReceive(u,"OKAY");const l=this.newMessage("WRTE",new DataView(s.encode(","+n).buffer));yield this.sendReceive(l,"OKAY");const h=new Promise((t,n)=>{i.onload=e=>t(e.target.result),i.onerror=n,i.readAsArrayBuffer(e)}),f=yield h,g=[];for(let e=0;e<f.byteLength;e+=o)g.push(f.slice(e,Math.min(e+o,f.byteLength)));for(const e of g){const t=new r.SyncFrame("DATA",e.byteLength),n=this.newMessage("WRTE",t.toDataView());yield this.sendReceive(n,"OKAY");const i=new DataView(e),o=this.newMessage("WRTE",i);yield this.sendReceive(o,"OKAY")}const y=new r.SyncFrame("DONE",Math.round(Date.now()/1e3)),v=this.newMessage("WRTE",y.toDataView());yield this.client.sendMessage(v);const w=this.newMessage("OKAY");yield this.sendReceive(w,"OKAY")})}newMessage(e,t){return o.Message.newMessage(e,this.localId,this.remoteId,this.options.useChecksum,t)}static open(e,t,n){return i(this,void 0,void 0,function*(){const i=c.nextId++;let r=0;const a=o.Message.open(i,r,t,n.useChecksum);let d;yield e.sendMessage(a);do{d=yield e.awaitMessage()}while(d.header.arg1!==i);if("OKAY"!==d.header.cmd)throw new Error("OPEN Failed");r=d.header.arg0,n.debug&&(console.log(`Opened stream ${t}`),console.log(` local_id: 0x${(0,s.toHex32)(i)}`),console.log(` remote_id: 0x${(0,s.toHex32)(r)}`));const u=new c(e,t,i,r,n);return e.registerStream(u),u})}}t.Stream=c,c.nextId=1},870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=void 0;const i=n(351);class o{constructor(e,t){this.cmd=e,this.byteLength=t}toDataView(){const e=new ArrayBuffer(8),t=(0,i.encodeCmd)(this.cmd),n=new DataView(e);return n.setUint32(0,t,!0),n.setUint32(4,this.byteLength,!0),n}static fromDataView(e){const t=(0,i.decodeCmd)(e.getUint32(0,!0)),n=e.getUint32(4,!0);return new o(t,n)}}t.SyncFrame=o},397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=void 0;const i=n(864),o=n(351);class s{constructor(e,t){this.header=e,this.data=t}dataAsString(){return this.data?(new TextDecoder).decode(this.data):null}static newMessage(e,t,n,o,r){let a=0,c=0;r&&(c=r.byteLength,o&&(a=s.checksum(r)));const d=new i.MessageHeader(e,t,n,c,a);return new s(d,r)}static open(e,t,n,i){const o=new TextEncoder,r=new DataView(o.encode(n+"\0").buffer);return s.newMessage("OPEN",e,t,i,r)}static cnxn(e,t,n,i){const o=new TextEncoder,r=new DataView(o.encode(n).buffer);return s.newMessage("CNXN",e,t,i,r)}static authSignature(e,t){return s.newMessage("AUTH",2,0,t,e)}static authPublicKey(e,t){const n=(new TextEncoder).encode((0,o.toB64)(e.buffer)+"\0");return s.newMessage("AUTH",3,0,t,new DataView(n.buffer))}static checksum(e){let t=0;for(let n=0;n<e.byteLength;n++)t+=e.getUint8(n);return 4294967295&t}}t.Message=s},734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.MessageChannel=void 0;const o=n(397),s=n(864);t.MessageChannel=class{constructor(e,t,n){this.transport=e,this.options=t,this.listener=n,this.active=!0,this.readLoop()}readLoop(){return i(this,void 0,void 0,function*(){let e;do{e=yield this.read(),this.options.debug&&console.log("<<<",e),this.listener.newMessage(e)}while(this.active)})}readHeader(){return i(this,void 0,void 0,function*(){const e=yield this.transport.read(24);return s.MessageHeader.parse(e,this.options.useChecksum)})}read(){return i(this,void 0,void 0,function*(){const e=yield this.readHeader();let t;return e.cmd,e.length>0&&(t=yield this.transport.read(e.length)),new o.Message(e,t)})}close(){this.active=!1}write(e){return i(this,void 0,void 0,function*(){this.options.debug&&console.log(">>>",e);const t=e.header.toDataView();yield this.transport.write(t.buffer),e.data&&(yield this.transport.write(e.data.buffer))})}}},864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHeader=void 0;const i=n(351);class o{constructor(e,t,n,i,o){this.cmd=e,this.arg0=t,this.arg1=n,this.length=i,this.checksum=o}toDataView(){const e=new DataView(new ArrayBuffer(24)),t=(0,i.encodeCmd)(this.cmd),n=4294967295^t;return e.setUint32(0,t,!0),e.setUint32(4,this.arg0,!0),e.setUint32(8,this.arg1,!0),e.setUint32(12,this.length,!0),e.setUint32(16,this.checksum,!0),e.setUint32(20,n,!0),e}static parse(e,t=!1){const n=e.getUint32(0,!0),s=e.getUint32(4,!0),r=e.getUint32(8,!0),a=e.getUint32(12,!0),c=e.getUint32(16,!0);if(t&&e.byteLength>20&&-1!==(n^e.getUint32(20,!0)))throw new Error("magic mismatch");return new o((0,i.decodeCmd)(n),s,r,a,c)}}t.MessageHeader=o},257(e,t){Object.defineProperty(t,"__esModule",{value:!0})},858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(397),t),o(n(734),t),o(n(864),t),o(n(257),t)},225(e,t){Object.defineProperty(t,"__esModule",{value:!0})},289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};Object.defineProperty(t,"__esModule",{value:!0}),t.WebUsbTransport=void 0;const o=n(351),s={classCode:255,subclassCode:66,protocolCode:1},r={classCode:255,subclassCode:66,protocolCode:3},a=[s,r];class c{constructor(e,t,n,i,o,s=console.log){this.device=e,this.match=t,this.endpointIn=n,this.endpointOut=i,this.options=o,this.log=s}close(){return i(this,void 0,void 0,function*(){yield this.device.releaseInterface(this.match.intf.interfaceNumber),yield this.device.close()})}write(e){return i(this,void 0,void 0,function*(){this.options.dump&&(0,o.hexdump)(new DataView(e),this.endpointOut+"==> "),yield this.device.transferOut(this.endpointOut,e)})}read(e){return i(this,void 0,void 0,function*(){const t=yield this.device.transferIn(this.endpointIn,e);if(!t.data)throw new Error("Response didn't contain any data");return t.data})}isAdb(){return null!=c.findMatch(this.device,s)}isFastboot(){return null!=c.findMatch(this.device,r)}static open(e){return i(this,void 0,void 0,function*(){const t=yield navigator.usb.requestDevice({filters:a});yield t.open();const n=this.findMatch(t,s);if(!n)throw new Error("Could not find an ADB device");yield t.selectConfiguration(n.conf.configurationValue),yield t.claimInterface(n.intf.interfaceNumber);const i=c.getEndpointNum(n.alternate.endpoints,"in"),o=c.getEndpointNum(n.alternate.endpoints,"out"),r=new c(t,n,i,o,e);return e.debug&&console.log("Created new Transport: ",r),r})}static findMatch(e,t){for(const n of e.configurations)for(const e of n.interfaces)for(const i of e.alternates)if(t.classCode===i.interfaceClass&&t.subclassCode===i.interfaceSubclass&&t.protocolCode===i.interfaceProtocol)return{conf:n,intf:e,alternate:i};return null}static getEndpointNum(e,t,n="bulk"){for(const i of e)if(i.direction===t&&i.type===n)return i.endpointNumber;throw new Error(`Cannot find ${t} endpoint`)}}t.WebUsbTransport=c},980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,o)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||i(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(225),t),o(n(289),t)}},t={};function n(i){var o=t[i];if(void 0!==o)return o.exports;var s=t[i]={exports:{}};return e[i].call(s.exports,s,s.exports,n),s.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i=n(834),o=function(e,t,n,i){return new(n||(n=Promise))(function(o,s){function r(e){try{c(i.next(e))}catch(e){s(e)}}function a(e){try{c(i.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(r,a)}c((i=i.apply(e,t||[])).next())})};let s,r;const a=document.querySelector("#connect"),c=document.querySelector("#disconnect"),d=document.querySelector("#start"),u=document.querySelector("#stop"),l=document.querySelector("#screencapture"),h=document.querySelector("#video"),f=document.querySelector("#screenshot"),g=document.querySelector("#download"),y=document.querySelector("#status"),v={debug:!0,useChecksum:!1,dump:!1,keySize:2048},w=new class{constructor(){this.keys=[]}loadKeys(){return o(this,void 0,void 0,function*(){return this.keys})}saveKey(e){return o(this,void 0,void 0,function*(){this.keys.push(e),console.log("Saving Key"+e)})}};a.addEventListener("click",e=>o(void 0,void 0,void 0,function*(){try{s=yield i.WebUsbTransport.open(v),r=new i.AdbClient(s,v,w),y.textContent="Accept prompt on device";const e=yield r.connect();y.textContent="Connected and ready",console.log("Connected: ",e),a.classList.toggle("hidden"),c.classList.toggle("hidden"),d.removeAttribute("disabled"),l.removeAttribute("disabled"),u.removeAttribute("disabled")}catch(e){console.error("Connection Failed: ",e),y.textContent="Failed to connect to a device"}})),c.addEventListener("click",e=>o(void 0,void 0,void 0,function*(){try{if(r){try{yield r.disconnect()}catch(e){console.log("Error disconnecting ADB Client: ",e)}r=null}s&&(yield s.close(),s=null),a.classList.toggle("hidden"),c.classList.toggle("hidden"),d.disabled=!0,u.disabled=!0,l.disabled=!0,y.textContent="Connect to a device to start"}catch(e){console.error("Disconnecting Failed: ",e)}}));const p="/sdcard/webadb-record-2.mp4";let m=null;d.addEventListener("click",()=>o(void 0,void 0,void 0,function*(){m=yield i.Stream.open(r,`shell:screenrecord ${p}`,v),y.textContent="Recording...",u.classList.toggle("hidden"),d.classList.toggle("hidden")})),u.addEventListener("click",()=>o(void 0,void 0,void 0,function*(){y.textContent="Finishing Recording...",yield m.close(),y.textContent="Pulling video...",setTimeout(()=>o(void 0,void 0,void 0,function*(){console.log("Starting ADB Pull");const e=yield r.pull(p),t=window.URL.createObjectURL(e);h.src=t,g.href=t,g.download="recording.mp4",u.classList.toggle("hidden"),d.classList.toggle("hidden"),f.classList.add("hidden"),h.classList.remove("hidden"),g.classList.remove("hidden"),y.textContent="Done! Connected and ready"}),2e3)})),l.addEventListener("click",()=>o(void 0,void 0,void 0,function*(){y.textContent="Generating Screenshot...",yield r.shell("screencap -p /sdcard/screenshot.png"),y.textContent="Pulling image...",setTimeout(()=>o(void 0,void 0,void 0,function*(){console.log("Starting ADB Pull");const e=yield r.pull("/sdcard/screenshot.png"),t=window.URL.createObjectURL(e);f.src=t,g.href=t,g.download="screenshot.png",g.classList.remove("hidden"),f.classList.remove("hidden"),h.classList.add("hidden"),y.textContent="Done! Connected and ready"}),2e3)}))})();
================================================
FILE: demo/public/js/screenrecord.d.ts
================================================
export {};
//# sourceMappingURL=screenrecord.d.ts.map
================================================
FILE: demo/public/js/screenrecord.js
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AdbClient, WebUsbTransport, Stream } from 'wadb';
let transport;
let adbClient;
const connectButton = document.querySelector('#connect');
const disconnectButton = document.querySelector('#disconnect');
const startButton = document.querySelector('#start');
const stopButton = document.querySelector('#stop');
const screenshotButton = document.querySelector('#screencapture');
const video = document.querySelector('#video');
const screenshot = document.querySelector('#screenshot');
const download = document.querySelector('#download');
const status = document.querySelector('#status');
const options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
class MyKeyStore {
constructor() {
this.keys = [];
}
loadKeys() {
return __awaiter(this, void 0, void 0, function* () {
return this.keys;
});
}
saveKey(key) {
return __awaiter(this, void 0, void 0, function* () {
this.keys.push(key);
console.log('Saving Key' + key);
});
}
}
const keyStore = new MyKeyStore();
connectButton.addEventListener('click', (_) => __awaiter(void 0, void 0, void 0, function* () {
try {
transport = yield WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
status.textContent = 'Accept prompt on device';
const adbConnectionInformation = yield adbClient.connect();
status.textContent = 'Connected and ready';
console.log('Connected: ', adbConnectionInformation);
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
startButton.removeAttribute('disabled');
screenshotButton.removeAttribute('disabled');
stopButton.removeAttribute('disabled');
}
catch (e) {
console.error('Connection Failed: ', e);
status.textContent = 'Failed to connect to a device';
}
}));
disconnectButton.addEventListener('click', (_) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (adbClient) {
try {
yield adbClient.disconnect();
}
catch (e) {
console.log('Error disconnecting ADB Client: ', e);
}
adbClient = null;
}
if (transport) {
yield transport.close();
transport = null;
}
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
startButton.disabled = true;
stopButton.disabled = true;
screenshotButton.disabled = true;
status.textContent = 'Connect to a device to start';
}
catch (e) {
console.error('Disconnecting Failed: ', e);
}
}));
const RECORD_FILE_NAME = '/sdcard/webadb-record-2.mp4';
let shell = null;
startButton.addEventListener('click', () => __awaiter(void 0, void 0, void 0, function* () {
shell = yield Stream.open(adbClient, `shell:screenrecord ${RECORD_FILE_NAME}`, options);
status.textContent = 'Recording...';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
}));
stopButton.addEventListener('click', () => __awaiter(void 0, void 0, void 0, function* () {
// await shell!.write(String.fromCharCode(3) + '\n'); // CTRL+C
status.textContent = 'Finishing Recording...';
yield shell.close();
status.textContent = 'Pulling video...';
// Trying to load the file straight away results in a broken file.
// Waiting for a couple of seconds fixes it. Maybe send STAT before
// attempting download.
setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
console.log('Starting ADB Pull');
const result = yield adbClient.pull(RECORD_FILE_NAME);
const videoSrc = window.URL.createObjectURL(result);
video.src = videoSrc;
download.href = videoSrc;
download.download = 'recording.mp4';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
screenshot.classList.add('hidden');
video.classList.remove('hidden');
download.classList.remove('hidden');
status.textContent = 'Done! Connected and ready';
}), 2000);
}));
screenshotButton.addEventListener('click', () => __awaiter(void 0, void 0, void 0, function* () {
status.textContent = 'Generating Screenshot...';
yield adbClient.shell('screencap -p /sdcard/screenshot.png');
status.textContent = 'Pulling image...';
setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
console.log('Starting ADB Pull');
const result = yield adbClient.pull('/sdcard/screenshot.png');
const imageSrc = window.URL.createObjectURL(result);
screenshot.src = imageSrc;
download.href = imageSrc;
download.download = 'screenshot.png';
download.classList.remove('hidden');
screenshot.classList.remove('hidden');
video.classList.add('hidden');
status.textContent = 'Done! Connected and ready';
}), 2000);
}));
//# sourceMappingURL=screenrecord.js.map
================================================
FILE: demo/public/livestream.html
================================================
<!--
Copyright 2020 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
<title>Web ADB Livestream</title>
<script src="js/livestream.bundle.js" defer></script>
<style>
html {
font-family: 'Roboto', sans-serif;
background-color: lightsteelblue;
box-sizing: border-box;
}
body {
margin: 0;
}
h1 {
height: 56px;
margin: 0;
padding: 8px 16px;
background-color: #789ac7;
box-sizing: border-box;
box-shadow: 0px 2px 4px #999999;
}
h2 {
margin: 16px 0 8px 0;
}
video {
background-color: darkgrey;
max-width: 100%;
max-height: 60vh;
display: block;
}
.video-container {
margin-top: 16px;
width: 100%;
}
.content-wrapper {
padding: 0 16px;
}
.buttons {
height: 30px;
}
.button {
width: 145px;
height: 30px;
text-transform: uppercase;
padding-left: 20px;
}
#connect {
background-image: url(./assets/phonelink.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#disconnect {
background-image: url(./assets/phonelink_off.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#start {
background-image: url(./assets/video-start.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#stop {
background-image: url(./assets/video-stop.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#screencapture {
background-image: url(./assets/screenshot.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
.hidden {
display: none;
}
.status {
height: 28px;
background-color: steelblue;
font-size: 12px;
box-sizing: border-box;
padding-top: 6px;
text-transform: uppercase;
margin-bottom: 16px;
}
</style>
</head>
<body>
<h1>WebADB Screenrecord</h1>
<div id="status" class="content-wrapper status">
Connect to a device to start
</div>
<div class="content-wrapper">
<div class="buttons">
<button id="connect" class="button">Connect</button>
<button id="disconnect" class="button hidden">Disconnect</button>
</div>
<div>
<h2>Controls</h2>
<div class="buttons">
<button id="start" class="button">Record</button>
<button id="stop" class="button hidden">Stop</button>
</div>
</div>
<div class="video-container">
<h2>Output:</h2>
<video id="video" controls></video>
<a id="download" href="#" download="recording.mp4">Download</a>
</div>
</div>
</body>
</html>
================================================
FILE: demo/public/screenrecord.html
================================================
<!--
Copyright 2020 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
<title>WebADB Screenrecord</title>
<script src="js/screenrecord.bundle.js" defer></script>
<style>
html {
font-family: 'Roboto', sans-serif;
background-color: lightsteelblue;
box-sizing: border-box;
min-width: 320px;
}
body {
margin: 0;
}
header, .status {
box-sizing: border-box;
box-shadow: 0px 2px 4px #999999;
}
header > h1, .status > div, content > div {
margin: 0px auto;
max-width: 900px;
padding: 0px 16px;
box-sizing: border-box;
}
header {
background-color: #789ac7;
}
header > h1 {
height: 56px;
padding: 8px 16px;
}
.status {
height: 28px;
background-color: steelblue;
font-size: 12px;
padding-top: 6px;
text-transform: uppercase;
margin-bottom: 16px;
}
h2 {
margin: 16px 0 8px 0;
}
.video-container > div {
background-color: #222222;
width: 100%;
margin: 0px auto;
}
video, #screenshot {
width: 100%;
max-width: 100%;
max-height: 100%;
}
.video-container {
margin-top: 16px;
margin-bottom: 16px;
width: 100%;
}
.button {
width: 145px;
height: 30px;
text-transform: uppercase;
padding-left: 20px;
}
#connect {
background-image: url(./assets/phonelink.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#disconnect {
background-image: url(./assets/phonelink_off.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 2px;
}
#start {
background-image: url(./assets/video-start.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#stop {
background-image: url(./assets/video-stop.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
#screencapture {
background-image: url(./assets/screenshot.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
}
/* #download {
background-image: url(./assets/save.svg);
background-repeat: no-repeat;
background-position-x: 4px;
background-position-y: 0px;
text-decoration: none;
color: black;
background-color: lightgrey;
width: 14px;
} */
.hidden {
display: none;
}
</style>
</head>
<body>
<header>
<h1>WebADB Screenrecord</h1>
</header>
<div class="status">
<div id="status">
Connect to a device to start
</div>
</div>
<content>
<div class="buttons">
<button id="connect" class="button">Connect</button>
<button id="disconnect" class="button hidden">Disconnect</button>
<button id="start" class="button" disabled>Record</button>
<button id="stop" class="button hidden" disabled>Stop</button>
<button id="screencapture" class="button" disabled>Screenshot</button>
</div>
<div class="video-container">
<div>
<video id="video" controls></video>
<img id="screenshot" class="hidden"></img>
</div>
<a id="download" class='hidden' href="#" download="recording.mp4">Download</a>
</div>
</content>
</body>
</html>
================================================
FILE: demo/public/sw.js
================================================
if(!self.define){let e,s={};const r=(r,i)=>(r=new URL(r+".js",i).href,s[r]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=r,e.onload=s,document.head.appendChild(e)}else e=r,importScripts(r),s()}).then(()=>{let e=s[r];if(!e)throw new Error(`Module ${r} didn’t register its module`);return e}));self.define=(i,c)=>{const a=e||("document"in self?document.currentScript.src:"")||location.href;if(s[a])return;let f={};const d=e=>r(e,a),n={module:{uri:a},exports:f,require:d};s[a]=Promise.all(i.map(e=>n[e]||d(e))).then(e=>(c(...e),f))}}define(["./workbox-aa2f3006"],function(e){"use strict";self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.precacheAndRoute([{url:"video.html",revision:"b6d0ffeea0e993d0e974b66370f26452"},{url:"screenrecord.html",revision:"377711bee26708ee49bbc958ff816a69"},{url:"livestream.html",revision:"a324589fdd328bb93f6223a75a1b5272"},{url:"interactiveshell.html",revision:"522987ae9971ed8dacec16fec3b34e96"},{url:"index.html",revision:"50d0895f12bf0f8f169e31c243dcc4d8"},{url:"404.html",revision:"0a27a4163254fc8fce870c8cc3a3f94f"},{url:"js/screenrecord.js",revision:"e4311f5051f5fda43649113c8f23beaa"},{url:"js/screenrecord.d.ts",revision:"3a0443f883901bd8fc6324e5b777dafc"},{url:"js/screenrecord.bundle.js",revision:"2e8477d5880a4f415bf0e46b36f72b41"},{url:"js/livestream.js",revision:"b03ac911e603183acd922c0828c896da"},{url:"js/livestream.d.ts",revision:"39ab92c97178c18e749a42347f51a2a5"},{url:"js/livestream.bundle.js",revision:"dd97e4b03accf0fc87306d7c9fda0b38"},{url:"js/interactiveshell.js",revision:"13a41015a7ad92da6c1be7f759fcfaf0"},{url:"js/interactiveshell.d.ts",revision:"5681954b090c4fca99f7f787498253b6"},{url:"js/interactiveshell.bundle.js",revision:"d5c056ec7005ec28a6397fe1aa86239c"},{url:"assets/video-stop.svg",revision:"89455ac48d09d5d61abde3e3353da59b"},{url:"assets/video-start.svg",revision:"3cbeae541c34c92d309251e4fcfcf243"},{url:"assets/screenshot.svg",revision:"db7f624d5f5cd6a032c8d65890615069"},{url:"assets/save.svg",revision:"ce3185959ba8c7cdb1f81ce5003d76bc"},{url:"assets/phonelink_off.svg",revision:"55d6032b4173a7fdbef16989c6844211"},{url:"assets/phonelink.svg",revision:"b16eaf9232fa7862f7ba5870c335e042"}],{})});
//# sourceMappingURL=sw.js.map
================================================
FILE: demo/public/video.html
================================================
<!doctype html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
</head>
<body>
<h1>Video</h1>
<video src="./recording.mp4" controls type="video/mp4"></video>
</body>
</html>
================================================
FILE: demo/public/workbox-69b5a3b7.js
================================================
define("./workbox-69b5a3b7.js",["exports"],(function(e){"use strict";try{self["workbox:core:5.1.4"]&&_()}catch(e){}const t={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},n=e=>[t.prefix,e,t.suffix].filter(e=>e&&e.length>0).join("-"),s=e=>e||n(t.precache),i=e=>new URL(String(e),location.href).href.replace(new RegExp("^"+location.origin),""),c=(e,...t)=>{let n=e;return t.length>0&&(n+=" :: "+JSON.stringify(t)),n};class o extends Error{constructor(e,t){super(c(e,t)),this.name=e,this.details=t}}const r=new Set;const a=(e,t)=>e.filter(e=>t in e),u=async({request:e,mode:t,plugins:n=[]})=>{const s=a(n,"cacheKeyWillBeUsed");let i=e;for(const e of s)i=await e.cacheKeyWillBeUsed.call(e,{mode:t,request:i}),"string"==typeof i&&(i=new Request(i));return i},l=async({cacheName:e,request:t,event:n,matchOptions:s,plugins:i=[]})=>{const c=await self.caches.open(e),o=await u({plugins:i,request:t,mode:"read"});let r=await c.match(o,s);for(const t of i)if("cachedResponseWillBeUsed"in t){const i=t.cachedResponseWillBeUsed;r=await i.call(t,{cacheName:e,event:n,matchOptions:s,cachedResponse:r,request:o})}return r},h=async({cacheName:e,request:t,response:n,event:s,plugins:c=[],matchOptions:h})=>{const f=await u({plugins:c,request:t,mode:"write"});if(!n)throw new o("cache-put-with-no-response",{url:i(f.url)});const w=await(async({request:e,response:t,event:n,plugins:s=[]})=>{let i=t,c=!1;for(const t of s)if("cacheWillUpdate"in t){c=!0;const s=t.cacheWillUpdate;if(i=await s.call(t,{request:e,response:i,event:n}),!i)break}return c||(i=i&&200===i.status?i:void 0),i||null})({event:s,plugins:c,response:n,request:f});if(!w)return;const d=await self.caches.open(e),p=a(c,"cacheDidUpdate"),y=p.length>0?await l({cacheName:e,matchOptions:h,request:f}):null;try{await d.put(f,w)}catch(e){throw"QuotaExceededError"===e.name&&await async function(){for(const e of r)await e()}(),e}for(const t of p)await t.cacheDidUpdate.call(t,{cacheName:e,event:s,oldResponse:y,newResponse:w,request:f})},f=async({request:e,fetchOptions:t,event:n,plugins:s=[]})=>{if("string"==typeof e&&(e=new Request(e)),n instanceof FetchEvent&&n.preloadResponse){const e=await n.preloadResponse;if(e)return e}const i=a(s,"fetchDidFail"),c=i.length>0?e.clone():null;try{for(const t of s)if("requestWillFetch"in t){const s=t.requestWillFetch,i=e.clone();e=await s.call(t,{request:i,event:n})}}catch(e){throw new o("plugin-error-request-will-fetch",{thrownError:e})}const r=e.clone();try{let i;i="navigate"===e.mode?await fetch(e):await fetch(e,t);for(const e of s)"fetchDidSucceed"in e&&(i=await e.fetchDidSucceed.call(e,{event:n,request:r,response:i}));return i}catch(e){for(const t of i)await t.fetchDidFail.call(t,{error:e,event:n,originalRequest:c.clone(),request:r.clone()});throw e}};let w;async function d(e,t){const n=e.clone(),s={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=t?t(s):s,c=function(){if(void 0===w){const e=new Response("");if("body"in e)try{new Response(e.body),w=!0}catch(e){w=!1}w=!1}return w}()?n.body:await n.blob();return new Response(c,i)}try{self["workbox:precaching:5.1.4"]&&_()}catch(e){}function p(e){if(!e)throw new o("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){const t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}const{revision:t,url:n}=e;if(!n)throw new o("add-to-cache-list-unexpected-type",{entry:e});if(!t){const e=new URL(n,location.href);return{cacheKey:e.href,url:e.href}}const s=new URL(n,location.href),i=new URL(n,location.href);return s.searchParams.set("__WB_REVISION__",t),{cacheKey:s.href,url:i.href}}class y{constructor(e){this.t=s(e),this.s=new Map,this.i=new Map,this.o=new Map}addToCacheList(e){const t=[];for(const n of e){"string"==typeof n?t.push(n):n&&void 0===n.revision&&t.push(n.url);const{cacheKey:e,url:s}=p(n),i="string"!=typeof n&&n.revision?"reload":"default";if(this.s.has(s)&&this.s.get(s)!==e)throw new o("add-to-cache-list-conflicting-entries",{firstEntry:this.s.get(s),secondEntry:e});if("string"!=typeof n&&n.integrity){if(this.o.has(e)&&this.o.get(e)!==n.integrity)throw new o("add-to-cache-list-conflicting-integrities",{url:s});this.o.set(e,n.integrity)}if(this.s.set(s,e),this.i.set(s,i),t.length>0){const e=`Workbox is precaching URLs without revision info: ${t.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}async install({event:e,plugins:t}={}){const n=[],s=[],i=await self.caches.open(this.t),c=await i.keys(),o=new Set(c.map(e=>e.url));for(const[e,t]of this.s)o.has(t)?s.push(e):n.push({cacheKey:t,url:e});const r=n.map(({cacheKey:n,url:s})=>{const i=this.o.get(n),c=this.i.get(s);return this.u({cacheKey:n,cacheMode:c,event:e,integrity:i,plugins:t,url:s})});return await Promise.all(r),{updatedURLs:n.map(e=>e.url),notUpdatedURLs:s}}async activate(){const e=await self.caches.open(this.t),t=await e.keys(),n=new Set(this.s.values()),s=[];for(const i of t)n.has(i.url)||(await e.delete(i),s.push(i.url));return{deletedURLs:s}}async u({cacheKey:e,url:t,cacheMode:n,event:s,plugins:i,integrity:c}){const r=new Request(t,{integrity:c,cache:n,credentials:"same-origin"});let a,u=await f({event:s,plugins:i,request:r});for(const e of i||[])"cacheWillUpdate"in e&&(a=e);if(!(a?await a.cacheWillUpdate({event:s,request:r,response:u}):u.status<400))throw new o("bad-precaching-response",{url:t,status:u.status});u.redirected&&(u=await d(u)),await h({event:s,plugins:i,response:u,request:e===t?r:new Request(e),cacheName:this.t,matchOptions:{ignoreSearch:!0}})}getURLsToCacheKeys(){return this.s}getCachedURLs(){return[...this.s.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this.s.get(t.href)}async matchPrecache(e){const t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n){return(await self.caches.open(this.t)).match(n)}}createHandler(e=!0){return async({request:t})=>{try{const e=await this.matchPrecache(t);if(e)return e;throw new o("missing-precache-entry",{cacheName:this.t,url:t instanceof Request?t.url:t})}catch(n){if(e)return fetch(t);throw n}}}createHandlerBoundToURL(e,t=!0){if(!this.getCacheKeyForURL(e))throw new o("non-precached-url",{url:e});const n=this.createHandler(t),s=new Request(e);return()=>n({request:s})}}let g;const R=()=>(g||(g=new y),g);const q=(e,t)=>{const n=R().getURLsToCacheKeys();for(const s of function*(e,{ignoreURLParametersMatching:t,directoryIndex:n,cleanURLs:s,urlManipulation:i}={}){const c=new URL(e,location.href);c.hash="",yield c.href;const o=function(e,t=[]){for(const n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}(c,t);if(yield o.href,n&&o.pathname.endsWith("/")){const e=new URL(o.href);e.pathname+=n,yield e.href}if(s){const e=new URL(o.href);e.pathname+=".html",yield e.href}if(i){const e=i({url:c});for(const t of e)yield t.href}}(e,t)){const e=n.get(s);if(e)return e}};let U=!1;function m(e){U||((({ignoreURLParametersMatching:e=[/^utm_/],directoryIndex:t="index.html",cleanURLs:n=!0,urlManipulation:i}={})=>{const c=s();self.addEventListener("fetch",s=>{const o=q(s.request.url,{cleanURLs:n,directoryIndex:t,ignoreURLParametersMatching:e,urlManipulation:i});if(!o)return;let r=self.caches.open(c).then(e=>e.match(o)).then(e=>e||fetch(o));s.respondWith(r)})})(e),U=!0)}const v=[],L={get:()=>v,add(e){v.push(...e)}},x=e=>{const t=R(),n=L.get();e.waitUntil(t.install({event:e,plugins:n}).catch(e=>{throw e}))},K=e=>{const t=R();e.waitUntil(t.activate())};e.precacheAndRoute=function(e,t){!function(e){R().addToCacheList(e),e.length>0&&(self.addEventListener("install",x),self.addEventListener("activate",K))}(e),m(t)}}));
//# sourceMappingURL=workbox-69b5a3b7.js.map
================================================
FILE: demo/public/workbox-aa2f3006.js
================================================
define(["exports"],function(t){"use strict";try{self["workbox:core:7.3.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.3.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:i})}catch(t){a=Promise.reject(t)}const h=r&&r.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch(async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n})),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(i)&&0===i.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},h=t=>[a.prefix,t,a.suffix].filter(t=>t&&t.length>0).join("-"),u=t=>t||h(a.precache),l=t=>t||h(a.runtime);function f(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.3.0"]&&_()}catch(t){}function w(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class d{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class p{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.h.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.h=t}}let y;async function g(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,c=function(){if(void 0===y){const t=new Response("");if("body"in t)try{new Response(t.body),y=!0}catch(t){y=!1}y=!1}return y}()?i.body:await i.blob();return new Response(c,o)}function R(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class m{constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,this.reject=e})}}const v=new Set;try{self["workbox:strategies:7.3.0"]&&_()}catch(t){}function q(t){return"string"==typeof t?new Request(t):t}class U{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new m,this.R=[],this.m=[...t.plugins],this.v=new Map;for(const t of this.m)this.v.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=q(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=q(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},i),{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=q(t);var i;await(i=0,new Promise(t=>setTimeout(t,i)));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const c=await this.q(e);if(!c)return!1;const{cacheName:a,matchOptions:h}=this.l,u=await self.caches.open(a),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const i=R(e.url,s);if(e.url===i)return t.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===R(e.url,s))return t.match(e,n)}(u,r.clone(),["__WB_REVISION__"],h):null;try{await u.put(r,l?c.clone():c)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of v)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:a,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=q(await t({mode:e,request:n,event:this.event,params:this.params}));this.u[s]=n}return this.u[s]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.v.get(e),n=n=>{const i=Object.assign(Object.assign({},n),{state:s});return e[t](i)};yield n}}waitUntil(t){return this.R.push(t),t}async doneWaiting(){for(;this.R.length;){const t=this.R.splice(0),e=(await Promise.allSettled(t)).find(t=>"rejected"===t.status);if(e)throw e.reason}}destroy(){this.p.resolve(null)}async q(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class L{constructor(t={}){this.cacheName=l(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new U(this,{event:e,request:s,params:n}),r=this.U(i,s,e);return[r,this.L(r,i,s,e)]}async U(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this._(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async L(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){t instanceof Error&&(r=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}class b extends L{constructor(t={}){t.cacheName=u(t.cacheName),super(t),this.C=!1!==t.fallbackToNetwork,this.plugins.push(b.copyRedirectedCacheableResponsesPlugin)}async _(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.O(t,e):await this.N(t,e))}async N(t,e){let n;const i=e.params||{};if(!this.C)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=i.integrity,r=t.integrity,o=!r||r===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?r||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.j(),await e.cachePut(t,n.clone()))}return n}async O(t,e){this.j();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}j(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==b.copyRedirectedCacheableResponsesPlugin&&(n===b.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(b.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}b.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},b.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await g(t):t};class C{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.k=new Map,this.K=new Map,this.P=new Map,this.l=new b({cacheName:u(t),plugins:[...e,new p({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.T||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.T=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=w(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.k.has(i)&&this.k.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.k.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.P.has(t)&&this.P.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.P.set(t,n.integrity)}if(this.k.set(i,t),this.K.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return f(t,async()=>{const e=new d;this.strategy.plugins.push(e);for(const[e,s]of this.k){const n=this.P.get(s),i=this.K.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}})}activate(t){return f(t,async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.k.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}})}getURLsToCacheKeys(){return this.k}getCachedURLs(){return[...this.k.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.k.get(e.href)}getIntegrityForCacheKey(t){return this.P.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}let E;const O=()=>(E||(E=new C),E);class x extends i{constructor(t,e){super(({request:s})=>{const n=t.getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some(t=>t.test(s))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(i);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}},t.strategy)}}function N(t){const e=O();!function(t,e,n){let a;if("string"==typeof t){const s=new URL(t,location.href);a=new i(({url:t})=>t.href===s.href,e,n)}else if(t instanceof RegExp)a=new r(t,e,n);else if("function"==typeof t)a=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});a=t}(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c).registerRoute(a)}(new x(e,t))}t.precacheAndRoute=function(t,e){!function(t){O().precache(t)}(t),N(e)}});
//# sourceMappingURL=workbox-aa2f3006.js.map
================================================
FILE: demo/src/interactiveshell.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {AdbClient, IndexedDbKeyStore, Options, Shell, WebUsbTransport} from 'wadb';
const connectButton = document.querySelector('#connect')!;
const disconnectButton = document.querySelector('#disconnect')!;
const output = document.querySelector('#output')!;
const input = (document.querySelector('#input') as HTMLInputElement)!;
const options: Options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
const keyStore = new IndexedDbKeyStore();
let transport: WebUsbTransport | null = null;
let adbClient: AdbClient | null = null;
let shell: Shell | null = null;
function appendToCode(text: string) {
const span = document.createElement('span');
span.innerText = text;
output.appendChild(span);
output.scrollTop = output.scrollHeight;
}
function sendCommand(cmd: string) {
shell!.write(cmd + '\n');
}
connectButton.addEventListener('click', async (_e) => {
try {
transport = await WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
await adbClient.connect();
shell = await adbClient.interactiveShell(appendToCode);
disconnectButton.classList.toggle('hidden');
connectButton.classList.toggle('hidden');
} catch(e) {
console.error('Connection Failed: ', e);
}
});
disconnectButton.addEventListener('click', async (_e) => {
try {
await shell?.close();
await transport?.close();
transport = null;
adbClient = null;
shell = null;
} catch (e) {
console.error('Error closing the connection', e);
}
disconnectButton.classList.toggle('hidden');
connectButton.classList.toggle('hidden');
});
input.addEventListener('keyup', (e) => {
if (e.keyCode === 13) {
e.preventDefault();
sendCommand(input.value);
input.value = '';
return false;
}
return true;
});
================================================
FILE: demo/src/livestream.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {WebUsbTransport, AdbClient, Options, IndexedDbKeyStore, Stream} from 'wadb';
let transport: WebUsbTransport | null;
let adbClient: AdbClient | null;
const connectButton = document.querySelector('#connect')!;
const disconnectButton = document.querySelector('#disconnect')!;
const startButton = document.querySelector('#start')!;
const stopButton = document.querySelector('#stop')!;
const video: HTMLVideoElement = (document.querySelector('#video') as HTMLVideoElement)!;
const download = (document.querySelector('#download') as HTMLAnchorElement)!;
const status = document.querySelector('#status')!;
const options: Options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
const keyStore = new IndexedDbKeyStore();
connectButton.addEventListener('click', async (_event) => {
try {
transport = await WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
status.textContent = 'Accept prompt on device';
const adbConnectionInformation = await adbClient.connect();
status.textContent = 'Connected and ready';
console.log('Connected: ', adbConnectionInformation);
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
} catch(e) {
console.error('Connection Failed: ', e);
status.textContent = 'Failed to connect to a device';
}
});
disconnectButton.addEventListener('click', async (_event) => {
try {
if (adbClient) {
try {
await adbClient.disconnect();
} catch (e) {
console.log('Error disconnecting ADB Client: ', e);
}
adbClient = null;
}
if (transport) {
await transport.close();
transport = null;
}
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
status.textContent = 'Connect to a device to start';
} catch(e) {
console.error('Disconnecting Failed: ', e);
}
});
let shell: Stream | null = null;
startButton.addEventListener('click', async() => {
// const mediaSource = new MediaSource();
// const url = URL.createObjectURL(mediaSource);
// video.src = url;
status.textContent = 'Recording...';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
const textDecoder = new TextDecoder();
// mediaSource.addEventListener('sourceopen', async () => {
shell = await Stream.open(adbClient!, 'exec:screenrecord --output-format=h264 -', options);
// const audioSourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="mp4a.40.2"');
const chunks: Uint8Array<ArrayBuffer>[] = [];
let i = 0;
let msg;
while (true) {
console.log(++i);
msg = await shell!.read();
await shell!.write('OKAY');
if (msg.header.cmd === 'CLSE') {
break;
}
console.log(textDecoder.decode(msg.data!.buffer));
chunks.push(new Uint8Array(msg.data!.buffer as ArrayBuffer));
}
console.log(chunks.length);
const objectUrl = URL.createObjectURL(new Blob(chunks));
video.src = objectUrl;
download.href = objectUrl;
// });
});
stopButton.addEventListener('click', async() => {
await shell?.write('CLSE');
});
================================================
FILE: demo/src/screenrecord.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {AdbClient, WebUsbTransport, Options, IndexedDbKeyStore, Stream} from 'wadb';
let transport: WebUsbTransport | null;
let adbClient: AdbClient | null;
const connectButton = document.querySelector('#connect')!;
const disconnectButton = document.querySelector('#disconnect')!;
const startButton = (document.querySelector('#start') as HTMLButtonElement)!;
const stopButton = (document.querySelector('#stop') as HTMLButtonElement)!;
const screenshotButton = (document.querySelector('#screencapture') as HTMLButtonElement)!;
const video: HTMLVideoElement = (document.querySelector('#video') as HTMLVideoElement)!;
const screenshot = (document.querySelector('#screenshot') as HTMLImageElement)!;
const download = (document.querySelector('#download') as HTMLAnchorElement)!;
const status = document.querySelector('#status')!;
const options: Options = {
debug: true,
useChecksum: false,
dump: false,
keySize: 2048,
};
const keyStore = new IndexedDbKeyStore();
connectButton.addEventListener('click', async (_event) => {
try {
transport = await WebUsbTransport.open(options);
adbClient = new AdbClient(transport, options, keyStore);
status.textContent = 'Accept prompt on device';
const adbConnectionInformation = await adbClient.connect();
status.textContent = 'Connected and ready';
console.log('Connected: ', adbConnectionInformation);
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
startButton.removeAttribute('disabled');
screenshotButton.removeAttribute('disabled');
stopButton.removeAttribute('disabled');
} catch(e) {
console.error('Connection Failed: ', e);
status.textContent = 'Failed to connect to a device';
}
});
disconnectButton.addEventListener('click', async (_event) => {
try {
if (adbClient) {
try {
await adbClient.disconnect();
} catch (e) {
console.log('Error disconnecting ADB Client: ', e);
}
adbClient = null;
}
if (transport) {
await transport.close();
transport = null;
}
connectButton.classList.toggle('hidden');
disconnectButton.classList.toggle('hidden');
startButton.disabled = true;
stopButton.disabled = true;
screenshotButton.disabled = true;
status.textContent = 'Connect to a device to start';
} catch(e) {
console.error('Disconnecting Failed: ', e);
}
});
const RECORD_FILE_NAME = '/data/local/tmp/webadb-record.mp4';
let shell: Stream | null = null;
startButton.addEventListener('click', async() => {
shell = await Stream.open(adbClient!, `shell:screenrecord ${RECORD_FILE_NAME}`, options);
status.textContent = 'Recording...';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
});
stopButton.addEventListener('click', async() => {
// await shell!.write(String.fromCharCode(3) + '\n'); // CTRL+C
status.textContent = 'Finishing Recording...';
await shell!.close();
status.textContent = 'Pulling video...';
// Trying to load the file straight away results in a broken file.
// Waiting for a couple of seconds fixes it. Maybe send STAT before
// attempting download.
setTimeout(async () => {
const result = await adbClient!.pull(RECORD_FILE_NAME);
const videoSrc = window.URL.createObjectURL(result);
video!.src = videoSrc;
download!.href = videoSrc;
download.download = 'recording.mp4';
stopButton.classList.toggle('hidden');
startButton.classList.toggle('hidden');
screenshot.classList.add('hidden');
video.classList.remove('hidden');
download.classList.remove('hidden');
status.textContent = 'Done! Connected and ready';
}, 2000);
});
screenshotButton.addEventListener('click', async() => {
status.textContent = 'Generating Screenshot...';
await adbClient!.shell('screencap -p /data/local/tmp/screenshot.png');
status.textContent = 'Pulling image...';
const result = await adbClient!.pull('/data/local/tmp/screenshot.png');
const imageSrc = window.URL.createObjectURL(result);
screenshot.src = imageSrc;
download.href = imageSrc;
download.download = 'screenshot.png';
download.classList.remove('hidden');
screenshot.classList.remove('hidden');
video.classList.add('hidden');
status.textContent = 'Done! Connected and ready';
});
================================================
FILE: demo/tsconfig.json
================================================
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "es6", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": ["ES2015", "dom"], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./public/js", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
// "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
"skipLibCheck": true,
},
"include": ["**/*.ts"]
}
================================================
FILE: demo/webpack.config.js
================================================
/**
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const path = require('path');
module.exports = {
entry: {
screenrecord: './src/screenrecord.ts',
interactiveshell: './src/interactiveshell.ts',
livestream: './src/livestream.ts'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ],
},
output: {
filename: 'js/[name].bundle.js',
path: path.resolve(__dirname, 'public'),
},
devServer: {
static: path.resolve(__dirname, 'public'),
watchFiles: [path.resolve(__dirname, '../dist/**/*')],
},
};
================================================
FILE: demo/workbox-config.js
================================================
module.exports = {
"globDirectory": "public/",
"globPatterns": [
"**/*.{html,svg,js,ts}"
],
"swDest": "public/sw.js"
};
================================================
FILE: eslint.config.mjs
================================================
// @ts-check
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
export default [
{
files: ['**/*.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2017,
sourceType: 'module',
},
},
plugins: {
'@typescript-eslint': tsPlugin,
},
rules: {
...tsPlugin.configs['eslint-recommended'].overrides[0].rules,
...tsPlugin.configs['recommended'].rules,
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-trailing-spaces': 'error',
'eol-last': 'error',
},
},
];
================================================
FILE: jasmine.json
================================================
{
"spec_dir": "dist/spec",
"spec_files": [
"**/*[sS]pec.js"
],
"helpers": [
"helpers/**/*.js"
],
"stopSpecOnExpectationFailure": false,
"random": true
}
================================================
FILE: package.json
================================================
{
"name": "wadb",
"version": "0.1.0",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"lint": "eslint \"src/**/*.ts\" \"demo/src/**/*.ts\"",
"lint-fix": "eslint \"src/**/*.ts\" \"demo/src/**/*.ts\" --fix",
"build": "tsc -p .",
"test": "tsc -p . && jasmine --config=jasmine.json",
"dev": "concurrently \"tsc -p . --watch\" \"npm run dev --prefix demo\""
},
"files": [
"dist/lib",
"dist/index.d.ts",
"dist/index.js"
],
"author": "André Cipriani Bandarra",
"license": "Apache-2.0",
"devDependencies": {
"concurrently": "^9.0.0",
"@types/jasmine": "^6.0.0",
"@types/node": "^25.3.0",
"@types/w3c-web-usb": "^1.0.13",
"@typescript-eslint/eslint-plugin": "^8.56.1",
"@typescript-eslint/parser": "^8.56.1",
"eslint": "^10.0.2",
"fake-indexeddb": "^6.2.5",
"jasmine": "^6.1.0",
"typescript": "^5.9.3"
}
}
================================================
FILE: src/index.ts
================================================
/**
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './lib/AdbClient';
export * from './lib/AdbConnectionInformation';
export * from './lib/IndexedDbKeyStore';
export * from './lib/KeyStore'
export * from './lib/Options';
export * from './lib/Shell';
export * from './lib/Stream';
export * from './lib/SyncFrame';
export * from './lib/message';
export * from './lib/transport';
================================================
FILE: src/lib/AdbClient.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Transport} from './transport/Transport';
import {Options} from './Options';
import {Message, MessageChannel, MessageListener} from './message';
import {KeyStore} from './KeyStore';
import {privateKeyDump} from './Helpers';
import {AdbConnectionInformation} from './AdbConnectionInformation';
import {Stream} from './Stream';
import {Shell} from './Shell';
import {AsyncBlockingQueue} from './Queues';
import {Framebuffer} from './Framebuffer';
const VERSION = 0x01000000;
const VERSION_NO_CHECKSUM = 0x01000001;
const MAX_PAYLOAD = 256 * 1024;
const MACHINE_BANNER = 'host::\0';
export class AdbClient implements MessageListener {
private messageChannel: MessageChannel;
private messageQueue = new AsyncBlockingQueue<Message>();
private openStreams: Set<Stream> = new Set();
/**
* Creates a new AdbClient
*
* @param {Transport} transport the transport layer.
*/
constructor(
readonly transport: Transport,
readonly options: Options,
readonly keyStore: KeyStore,) {
this.messageChannel = new MessageChannel(transport, options, this);
}
registerStream(stream: Stream): void {
this.openStreams.add(stream);
}
unregisterStream(stream: Stream): void {
this.openStreams.delete(stream);
}
newMessage(msg: Message): void {
// Check if this message matches one of the open streams.
const streams = Array.from(this.openStreams);
for (const stream of streams) {
if (stream.consumeMessage(msg)) {
return;
}
}
this.messageQueue.enqueue(msg);
}
public async awaitMessage(): Promise<Message> {
return this.messageQueue.dequeue();
}
async connect(): Promise<AdbConnectionInformation> {
const version = this.options.useChecksum ? VERSION : VERSION_NO_CHECKSUM;
const cnxn = Message.cnxn(version, MAX_PAYLOAD, MACHINE_BANNER, this.options.useChecksum);
await this.sendMessage(cnxn); // Send the Message
// Response to connect must be CNXN or AUTH. Ignore different responses until the right one
// arrives.
let response;
do {
response = await this.awaitMessage();
} while (response.header.cmd !== 'CNXN' && response.header.cmd !== 'AUTH');
// Server connected
if (response.header.cmd === 'CNXN') {
if (!response.data) {
throw new Error('Connection doesn\'t have data');
}
return AdbConnectionInformation.fromDataView(response.data);
}
// Server asked to authenticate
response = await this.doAuth(response);
if (!response.data) {
throw new Error('Connection doesn\'t have data');
}
return AdbConnectionInformation.fromDataView(response.data);
}
async disconnect(): Promise<void> {
this.messageChannel.close();
}
async shell(command: string): Promise<string> {
const stream = await Stream.open(this, `shell:${command}`, this.options);
const okayMessage = Message.newMessage('OKAY', stream.localId, stream.remoteId, this.options.useChecksum);
let result = '';
let message;
do {
message = await stream.read();
if (message.header.cmd === 'WRTE') {
await this.sendMessage(okayMessage);
result += message.dataAsString() || '';
}
} while (message.header.cmd !== 'CLSE');
stream.client.unregisterStream(stream);
return result;
}
async framebuffer(): Promise<Framebuffer> {
return Framebuffer.create(this, this.options);
}
async interactiveShell(callback?: (result: string) => void): Promise<Shell> {
const stream = await Stream.open(this, 'shell:', this.options);
return new Shell(stream, callback);
}
async sync(): Promise<Stream> {
return await Stream.open(this, 'sync:', this.options);
}
async pull(filename: string): Promise<Blob> {
const syncStream = await this.sync();
const result = await syncStream.pull(filename);
await syncStream.close();
return result;
}
/**
* Pushes a blob of data to the device at the specified remote path.
*
* @param {Blob} blob The data to push.
* @param {string} remotePath The path on the device to write the data to.
* @param {string} mode The mode to set on the file (e.g., "0755").
* @param {number} chunkSize The size of data chunks to send at a time.
*/
async push(blob: Blob, remotePath: string, mode: string, chunkSize: number):
Promise<void> {
const syncStream = await this.sync();
await syncStream.push(blob, remotePath, mode, chunkSize);
await syncStream.close();
}
private async doAuth(authResponse: Message): Promise<Message> {
if (authResponse.header.cmd !== 'AUTH') {
throw new Error('Not an AUTH response');
}
if (authResponse.header.arg0 !== 1) {
throw new Error(`
Invalid AUTH parameter. Expected 1 and received ${authResponse.header.arg0}`);
}
if (!authResponse.data) {
throw new Error('AUTH message doens\'t contain data');
}
const token = authResponse.data.buffer as ArrayBuffer;
// Try signing with one of the stored keys
const keys = await this.keyStore.loadKeys();
for (const key of keys) {
const signed = await crypto.subtle.sign('RSASSA-PKCS1-v1_5', key.privateKey, token);
const signatureMessage =
Message.authSignature(new DataView(signed), this.options.useChecksum);
await this.sendMessage(signatureMessage);
const signatureResponse = await this.awaitMessage();
if (signatureResponse.header.cmd === 'CNXN') {
return signatureResponse;
}
console.log('Received message ', signatureResponse, 'from phone');
}
// None of they saved Keys is usable. Create new key
const key = await AdbClient.generateKey(this.options.dump, this.options.keySize);
await this.keyStore.saveKey(key);
const exportedKey = new DataView(await crypto.subtle.exportKey('spki', key.publicKey));
const keyMessage = Message.authPublicKey(exportedKey, this.options.useChecksum);
await this.sendMessage(keyMessage);
if (this.options.debug) {
console.log('Waiting for key to be accepted on the device.');
}
const keyResponse = await this.awaitMessage()
if (keyResponse.header.cmd !== 'CNXN') {
console.error('AUTH failed. Phone didn\'t accept key', keyResponse);
throw new Error('AUTH failed. Phone didn\'t accept key');
}
return keyResponse;
}
public async sendMessage(m: Message): Promise<void> {
await this.messageChannel.write(m);
}
static async generateKey(dump: boolean, keySize: number): Promise<CryptoKeyPair> {
const extractable = dump;
const key = await crypto.subtle.generateKey({
name: 'RSASSA-PKCS1-v1_5',
modulusLength: keySize,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: 'SHA-1' }
}, extractable, [ 'sign', 'verify' ])
if (dump) {
await privateKeyDump(key);
}
return key;
}
}
================================================
FILE: src/lib/AdbConnectionInformation.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const PRODUCT_NAME_KEY = 'ro.product.name';
const PRODUCT_MODEL_KEY = 'ro.product.model';
const PRODUCT_DEVICE_KEY = 'ro.product.device';
const FEATURES_KEY = 'features';
const DEFAULT_PRODUCT_VALUE = '<unkwnown>';
export class AdbConnectionInformation {
constructor(
readonly productName: string,
readonly productDevice: string,
readonly productModel: string,
readonly features: string[]
){
}
static fromDataView(input: DataView): AdbConnectionInformation {
const textDecoder = new TextDecoder();
const decodedInput = textDecoder.decode(input);
return AdbConnectionInformation.fromString(decodedInput);
}
/**
* Creates an AdbConnectionInformation from a Connection string
* @param input the string sent as data from a Connection response
*/
static fromString(input: string): AdbConnectionInformation {
const start = input.indexOf('::');
const properties = input.substring(start + 2).split(';');
let productName = DEFAULT_PRODUCT_VALUE;
let productDevice = DEFAULT_PRODUCT_VALUE;
let productModel = DEFAULT_PRODUCT_VALUE;
let features: string[] = [];
for (const property of properties) {
if (property.startsWith(PRODUCT_NAME_KEY)) {
productName = property.substring(PRODUCT_NAME_KEY.length + 1);
continue;
}
if (property.startsWith(PRODUCT_MODEL_KEY)) {
productModel = property.substring(PRODUCT_MODEL_KEY.length + 1);
continue;
}
if (property.startsWith(PRODUCT_DEVICE_KEY)) {
productDevice = property.substring(PRODUCT_DEVICE_KEY.length + 1);
continue;
}
if (property.startsWith(FEATURES_KEY)) {
features = property.substring(FEATURES_KEY.length + 1).split(',');
}
}
return new AdbConnectionInformation(productName, productDevice, productModel, features);
}
}
================================================
FILE: src/lib/Framebuffer.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Stream} from './Stream';
import {AdbClient} from './AdbClient';
import {Options} from './Options';
/**
* framebuffer:
* This service is used to send snapshots of the framebuffer to a client.
* It requires sufficient privileges but works as follow:
*
* After the OKAY, the service sends 16-byte binary structure
* containing the following fields (little-endian format):
*
* depth: uint32_t: framebuffer depth
* size: uint32_t: framebuffer size in bytes
* width: uint32_t: framebuffer width in pixels
* height: uint32_t: framebuffer height in pixels
*
* With the current implementation, depth is always 16, and
* size is always width*height*2
*
* Then, each time the client wants a snapshot, it should send
* one byte through the channel, which will trigger the service
* to send it 'size' bytes of framebuffer data.
*
* If the adbd daemon doesn't have sufficient privileges to open
* the framebuffer device, the connection is simply closed immediately.
*
* Definitions from `system/core/adb/daemon/framebuffer_service.cpp`
*
* struct fbinfo {
* unsigned int version;
* unsigned int bpp;
* unsigned int colorSpace;
* unsigned int size;
* unsigned int width;
* unsigned int height;
* unsigned int red_offset;
* unsigned int red_length;
* unsigned int blue_offset;
* unsigned int blue_length;
* unsigned int green_offset;
* unsigned int green_length;
* unsigned int alpha_offset;
* unsigned int alpha_length;
* }
*/
export class Framebuffer {
// static DDMS_RAWIMAGE_VERSION = 2;
static BYTE_LENGTH = 56;
private constructor(
readonly version: number,
readonly bpp: number,
readonly colorSpace: number,
readonly size: number,
readonly width: number,
readonly height: number,
readonly redOffset: number,
readonly redLength: number,
readonly blueOffset: number,
readonly blueLength: number,
readonly greenOffset: number,
readonly greenLength: number,
readonly alphaOffset: number,
readonly alphaLength: number,
readonly imageData: Uint8ClampedArray) {}
static async create(adbClient: AdbClient, options: Options): Promise<Framebuffer> {
const stream = await Stream.open(adbClient, 'framebuffer:', options);
let message = await stream.read();
if (message.header.cmd !== 'WRTE') {
await stream.write('CLSE');
throw new Error(`Expected WRTE message but received ${message.header.cmd}`);
}
if (!message.data) {
await stream.write('CLSE');
throw new Error('message doesn\'t contain data');
}
await stream.write('OKAY');
const version = message.data.getUint32(0, true);
const bpp = message.data.getUint32(4, true);
const colorSpace = message.data.getUint32(8, true);
const size = message.data.getUint32(12, true);
const width = message.data.getUint32(16, true);
const height = message.data.getUint32(20, true);
const redOffset = message.data.getUint32(24, true);
const redLength = message.data.getUint32(28, true);
const blueOffset = message.data.getUint32(32, true);
const blueLength = message.data.getUint32(36, true);
const greenOffset = message.data.getUint32(40, true);
const greenLength = message.data.getUint32(44, true);
const alphaOffset = message.data.getUint32(48, true);
const alphaLength = message.data.getUint32(52, true);
const buffer = new Uint8Array(size);
let bytesReceived = 0;
let data = new Uint8Array(message.data.buffer.slice(Framebuffer.BYTE_LENGTH));
buffer.set(data, 0);
bytesReceived = data.length;
while (bytesReceived < size) {
message = await stream.read();
if (message.header.cmd === 'CLSE') {
break;
}
if (!message.data) {
await stream.write('CLSE');
throw new Error('message doesn\'t contain data');
}
data = new Uint8Array(message.data.buffer as ArrayBuffer);
buffer.set(data, bytesReceived);
bytesReceived += data.length;
await stream.write('OKAY');
}
await stream.close();
return new Framebuffer(
version,
bpp,
colorSpace,
size,
width,
height,
redOffset,
redLength,
blueOffset,
blueLength,
greenOffset,
greenLength,
alphaOffset,
alphaLength,
Uint8ClampedArray.from(buffer),
);
}
}
================================================
FILE: src/lib/Helpers.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function paddit(text: string, width: number, padding: string): string {
const padlen = width - text.length;
let padded = '';
for (let i = 0; i < padlen; i++) {
padded += padding;
}
return padded + text;
}
export function toHex8(num: number): string {
return paddit(num.toString(16), 2, '0');
}
export function toHex16(num: number): string {
return paddit(num.toString(16), 4, '0');
}
export function toHex32(num: number): string {
return paddit(num.toString(16), 8, '0');
}
export function hexdump(view: DataView, prefix = ''): void {
const decoder = new TextDecoder();
for (let i = 0; i < view.byteLength; i += 16) {
const max = (view.byteLength - i) > 16 ? 16 : (view.byteLength - i);
let row = prefix + toHex16(i) + ' ';
let j;
for (j = 0; j < max; j++) {
row += ' ' + toHex8(view.getUint8(i + j));
}
for (; j < 16; j++){
row += ' ';
}
row += ' | ' + decoder.decode(new DataView(view.buffer, i, max));
console.log(row);
}
}
export function toB64(buffer: ArrayBuffer): string {
return btoa(new Uint8Array(buffer).reduce((s, b) => s + String.fromCharCode(b), ''));
}
export async function privateKeyDump(key: CryptoKeyPair): Promise<void> {
if (!key.privateKey.extractable) {
console.log('cannot dump the private key, it\'s not extractable');
return;
}
const privkey = await crypto.subtle.exportKey('pkcs8', key.privateKey);
console.log(`-----BEGIN PRIVATE KEY-----\n${toB64(privkey)}\n-----END PRIVATE KEY-----`);
}
export async function publicKeyDump(key: CryptoKeyPair): Promise<void> {
if (!key.publicKey.extractable) {
console.log('cannot dump the public key, it\'s not extractable');
return;
}
const pubKey = await crypto.subtle.exportKey('spki', key.publicKey);
console.log(`-----BEGIN PUBLIC KEY-----\n${toB64(pubKey)}'\n-----END PUBLIC KEY-----`);
}
export function encodeCmd(cmd: string): number {
const encoder = new TextEncoder();
const buffer = encoder.encode(cmd).buffer;
const view = new DataView(buffer);
return view.getUint32(0, true);
}
export function decodeCmd(cmd: number): string {
const decoder = new TextDecoder();
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint32(0, cmd, true);
return decoder.decode(buffer);
}
================================================
FILE: src/lib/IndexedDbKeyStore.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {KeyStore} from './KeyStore';
const DB_NAME = 'wadb';
const DB_VERSION = 1;
const STORE_NAME = 'keys';
function openDb(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = () => {
request.result.createObjectStore(STORE_NAME, {autoIncrement: true});
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
/**
* A KeyStore implementation that persists keys across page reloads using
* IndexedDB. CryptoKey objects are stored directly, which avoids the need to
* export and re-import them.
*/
export class IndexedDbKeyStore implements KeyStore {
async loadKeys(): Promise<CryptoKeyPair[]> {
const db = await openDb();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readonly');
const request = tx.objectStore(STORE_NAME).getAll();
request.onsuccess = () => resolve(request.result as CryptoKeyPair[]);
request.onerror = () => reject(request.error);
tx.oncomplete = () => db.close();
});
}
async saveKey(key: CryptoKeyPair): Promise<void> {
const db = await openDb();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readwrite');
const request = tx.objectStore(STORE_NAME).add(key);
request.onerror = () => reject(request.error);
tx.oncomplete = () => { db.close(); resolve(); };
});
}
}
================================================
FILE: src/lib/KeyStore.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface KeyStore {
loadKeys(): Promise<CryptoKeyPair[]>;
saveKey(key: CryptoKeyPair): Promise<void>;
}
================================================
FILE: src/lib/Log.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default class Log {
debug(message: string): void {
console.log(message);
}
info(message: string): void {
console.info(message);
}
error(message: string): void {
console.error(message);
}
}
================================================
FILE: src/lib/Options.ts
================================================
/*
* Copyright 2020 Google Inc. All Rights Reserved.
*
*
gitextract_qi4f3tty/ ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── demo/ │ ├── .firebaserc │ ├── .gitignore │ ├── firebase.json │ ├── package.json │ ├── public/ │ │ ├── 404.html │ │ ├── index.html │ │ ├── interactiveshell.html │ │ ├── js/ │ │ │ ├── interactiveshell.bundle.js │ │ │ ├── interactiveshell.d.ts │ │ │ ├── interactiveshell.js │ │ │ ├── livestream.bundle.js │ │ │ ├── livestream.d.ts │ │ │ ├── livestream.js │ │ │ ├── screenrecord.bundle.js │ │ │ ├── screenrecord.d.ts │ │ │ └── screenrecord.js │ │ ├── livestream.html │ │ ├── screenrecord.html │ │ ├── sw.js │ │ ├── video.html │ │ ├── workbox-69b5a3b7.js │ │ └── workbox-aa2f3006.js │ ├── src/ │ │ ├── interactiveshell.ts │ │ ├── livestream.ts │ │ └── screenrecord.ts │ ├── tsconfig.json │ ├── webpack.config.js │ └── workbox-config.js ├── eslint.config.mjs ├── jasmine.json ├── package.json ├── src/ │ ├── index.ts │ ├── lib/ │ │ ├── AdbClient.ts │ │ ├── AdbConnectionInformation.ts │ │ ├── Framebuffer.ts │ │ ├── Helpers.ts │ │ ├── IndexedDbKeyStore.ts │ │ ├── KeyStore.ts │ │ ├── Log.ts │ │ ├── Options.ts │ │ ├── Queues.ts │ │ ├── Shell.ts │ │ ├── Stream.ts │ │ ├── SyncFrame.ts │ │ ├── message/ │ │ │ ├── Message.ts │ │ │ ├── MessageChannel.ts │ │ │ ├── MessageHeader.ts │ │ │ ├── MessageListener.ts │ │ │ └── index.ts │ │ └── transport/ │ │ ├── Transport.ts │ │ ├── WebUsbTransport.ts │ │ └── index.ts │ └── spec/ │ ├── AdbClientSpec.ts │ ├── IndexedDbKeyStoreSpec.ts │ ├── QueuesSpec.ts │ ├── StreamSpec.ts │ ├── SyncFrameSpec.ts │ ├── data/ │ │ └── messages/ │ │ ├── connect/ │ │ │ ├── connect_auth_public_key.json │ │ │ └── connect_simple.json │ │ └── stream/ │ │ └── open.json │ ├── message/ │ │ ├── MessageChannelSpec.ts │ │ ├── MessageHeaderSpec.ts │ │ └── MessageSpec.ts │ └── mock/ │ ├── MockKeyStore.ts │ ├── MockMessageListener.ts │ └── MockTransport.ts └── tsconfig.json
SYMBOL INDEX (338 symbols across 32 files)
FILE: demo/public/js/interactiveshell.bundle.js
method 834 (line 1) | 834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 620 (line 1) | 620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 449 (line 1) | 449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectio...
method 681 (line 1) | 681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 351 (line 1) | 351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 540 (line 1) | 540(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 432 (line 1) | 432(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 364 (line 1) | 364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 16 (line 1) | 16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=P...
method 908 (line 1) | 908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 870 (line 1) | 870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=...
method 397 (line 1) | 397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=vo...
method 734 (line 1) | 734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 864 (line 1) | 864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHea...
method 257 (line 1) | 257(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 858 (line 1) | 858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 225 (line 1) | 225(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 289 (line 1) | 289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 980 (line 1) | 980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
function n (line 1) | function n(i){var s=t[i];if(void 0!==s)return s.exports;var o=t[i]={expo...
function r (line 1) | function r(e){try{c(i.next(e))}catch(e){o(e)}}
function a (line 1) | function a(e){try{c(i.throw(e))}catch(e){o(e)}}
function c (line 1) | function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n(...
method constructor (line 1) | constructor(){this.keys=[]}
method loadKeys (line 1) | loadKeys(){return s(this,void 0,void 0,function*(){return this.keys})}
method saveKey (line 1) | saveKey(e){return s(this,void 0,void 0,function*(){this.keys.push(e),con...
function y (line 1) | function y(e){const t=document.createElement("span");t.innerText=e,a.app...
FILE: demo/public/js/interactiveshell.js
function adopt (line 17) | function adopt(value) { return value instanceof P ? value : new P(functi...
function fulfilled (line 19) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
function rejected (line 20) | function rejected(value) { try { step(generator["throw"](value)); } catc...
function step (line 21) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
class MyKeyStore (line 30) | class MyKeyStore {
method constructor (line 31) | constructor() {
method loadKeys (line 34) | loadKeys() {
method saveKey (line 39) | saveKey(key) {
function appendToCode (line 56) | function appendToCode(text) {
function sendCommand (line 62) | function sendCommand(cmd) {
FILE: demo/public/js/livestream.bundle.js
method 834 (line 1) | 834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 620 (line 1) | 620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 449 (line 1) | 449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectio...
method 681 (line 1) | 681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 351 (line 1) | 351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 540 (line 1) | 540(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 432 (line 1) | 432(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 364 (line 1) | 364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 16 (line 1) | 16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=P...
method 908 (line 1) | 908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 870 (line 1) | 870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=...
method 397 (line 1) | 397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=vo...
method 734 (line 1) | 734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 864 (line 1) | 864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHea...
method 257 (line 1) | 257(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 858 (line 1) | 858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 225 (line 1) | 225(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 289 (line 1) | 289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 980 (line 1) | 980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
function n (line 1) | function n(i){var o=t[i];if(void 0!==o)return o.exports;var s=t[i]={expo...
function r (line 1) | function r(e){try{c(i.next(e))}catch(e){s(e)}}
function a (line 1) | function a(e){try{c(i.throw(e))}catch(e){s(e)}}
function c (line 1) | function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(...
method constructor (line 1) | constructor(){this.keys=[]}
method loadKeys (line 1) | loadKeys(){return o(this,void 0,void 0,function*(){return this.keys})}
method saveKey (line 1) | saveKey(e){return o(this,void 0,void 0,function*(){this.keys.push(e),con...
FILE: demo/public/js/livestream.js
function adopt (line 17) | function adopt(value) { return value instanceof P ? value : new P(functi...
function fulfilled (line 19) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
function rejected (line 20) | function rejected(value) { try { step(generator["throw"](value)); } catc...
function step (line 21) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
class MyKeyStore (line 41) | class MyKeyStore {
method constructor (line 42) | constructor() {
method loadKeys (line 45) | loadKeys() {
method saveKey (line 50) | saveKey(key) {
FILE: demo/public/js/screenrecord.bundle.js
method 834 (line 1) | 834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 620 (line 1) | 620(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 449 (line 1) | 449(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.AdbConnectio...
method 681 (line 1) | 681(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 351 (line 1) | 351(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 540 (line 1) | 540(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 432 (line 1) | 432(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 364 (line 1) | 364(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=...
method 16 (line 1) | 16(e,t){var n=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=P...
method 908 (line 1) | 908(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 870 (line 1) | 870(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SyncFrame=...
method 397 (line 1) | 397(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.Message=vo...
method 734 (line 1) | 734(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 864 (line 1) | 864(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.MessageHea...
method 257 (line 1) | 257(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 858 (line 1) | 858(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
method 225 (line 1) | 225(e,t){Object.defineProperty(t,"__esModule",{value:!0})}
method 289 (line 1) | 289(e,t,n){var i=this&&this.__awaiter||function(e,t,n,i){return new(n||(...
method 980 (line 1) | 980(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t...
function n (line 1) | function n(i){var o=t[i];if(void 0!==o)return o.exports;var s=t[i]={expo...
function r (line 1) | function r(e){try{c(i.next(e))}catch(e){s(e)}}
function a (line 1) | function a(e){try{c(i.throw(e))}catch(e){s(e)}}
function c (line 1) | function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(...
method constructor (line 1) | constructor(){this.keys=[]}
method loadKeys (line 1) | loadKeys(){return o(this,void 0,void 0,function*(){return this.keys})}
method saveKey (line 1) | saveKey(e){return o(this,void 0,void 0,function*(){this.keys.push(e),con...
FILE: demo/public/js/screenrecord.js
function adopt (line 17) | function adopt(value) { return value instanceof P ? value : new P(functi...
function fulfilled (line 19) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
function rejected (line 20) | function rejected(value) { try { step(generator["throw"](value)); } catc...
function step (line 21) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
class MyKeyStore (line 43) | class MyKeyStore {
method constructor (line 44) | constructor() {
method loadKeys (line 47) | loadKeys() {
method saveKey (line 52) | saveKey(key) {
constant RECORD_FILE_NAME (line 105) | const RECORD_FILE_NAME = '/sdcard/webadb-record-2.mp4';
FILE: demo/public/workbox-69b5a3b7.js
class o (line 1) | class o extends Error{constructor(e,t){super(c(e,t)),this.name=e,this.de...
method constructor (line 1) | constructor(e,t){super(c(e,t)),this.name=e,this.details=t}
function d (line 1) | async function d(e,t){const n=e.clone(),s={headers:new Headers(n.headers...
function p (line 1) | function p(e){if(!e)throw new o("add-to-cache-list-unexpected-type",{ent...
class y (line 1) | class y{constructor(e){this.t=s(e),this.s=new Map,this.i=new Map,this.o=...
method constructor (line 1) | constructor(e){this.t=s(e),this.s=new Map,this.i=new Map,this.o=new Map}
method addToCacheList (line 1) | addToCacheList(e){const t=[];for(const n of e){"string"==typeof n?t.pu...
method install (line 1) | async install({event:e,plugins:t}={}){const n=[],s=[],i=await self.cac...
method activate (line 1) | async activate(){const e=await self.caches.open(this.t),t=await e.keys...
method u (line 1) | async u({cacheKey:e,url:t,cacheMode:n,event:s,plugins:i,integrity:c}){...
method getURLsToCacheKeys (line 1) | getURLsToCacheKeys(){return this.s}
method getCachedURLs (line 1) | getCachedURLs(){return[...this.s.keys()]}
method getCacheKeyForURL (line 1) | getCacheKeyForURL(e){const t=new URL(e,location.href);return this.s.ge...
method matchPrecache (line 1) | async matchPrecache(e){const t=e instanceof Request?e.url:e,n=this.get...
method createHandler (line 1) | createHandler(e=!0){return async({request:t})=>{try{const e=await this...
method createHandlerBoundToURL (line 1) | createHandlerBoundToURL(e,t=!0){if(!this.getCacheKeyForURL(e))throw ne...
function m (line 1) | function m(e){U||((({ignoreURLParametersMatching:e=[/^utm_/],directoryIn...
method add (line 1) | add(e){v.push(...e)}
FILE: demo/public/workbox-aa2f3006.js
class s (line 1) | class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.de...
method constructor (line 1) | constructor(t,s){super(e(t,s)),this.name=t,this.details=s}
class i (line 1) | class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.met...
method constructor (line 1) | constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}
method setCatchHandler (line 1) | setCatchHandler(t){this.catchHandler=n(t)}
class r (line 1) | class r extends i{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e....
method constructor (line 1) | constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.o...
class o (line 1) | class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return ...
method constructor (line 1) | constructor(){this.t=new Map,this.i=new Map}
method routes (line 1) | get routes(){return this.t}
method addFetchListener (line 1) | addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=...
method addCacheListener (line 1) | addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CAC...
method handleRequest (line 1) | handleRequest({request:t,event:e}){const s=new URL(t.url,location.href...
method findMatchingRoute (line 1) | findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this...
method setDefaultHandler (line 1) | setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}
method setCatchHandler (line 1) | setCatchHandler(t){this.o=n(t)}
method registerRoute (line 1) | registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t....
method unregisterRoute (line 1) | unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-ro...
function f (line 1) | function f(t,e){const s=e();return t.waitUntil(s),s}
function w (line 1) | function w(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{ent...
class d (line 1) | class d{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.ha...
method constructor (line 1) | constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerW...
class p (line 1) | class p{constructor({precacheController:t}){this.cacheKeyWillBeUsed=asyn...
method constructor (line 1) | constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({req...
function g (line 1) | async function g(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!...
function R (line 1) | function R(t,e){const s=new URL(t);for(const t of e)s.searchParams.delet...
class m (line 1) | class m{constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,th...
method constructor (line 1) | constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,this.rej...
function q (line 1) | function q(t){return"string"==typeof t?new Request(t):t}
class U (line 1) | class U{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.ev...
method constructor (line 1) | constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,th...
method fetch (line 1) | async fetch(t){const{event:e}=this;let n=q(t);if("navigate"===n.mode&&...
method fetchAndCachePut (line 1) | async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();retu...
method cacheMatch (line 1) | async cacheMatch(t){const e=q(t);let s;const{cacheName:n,matchOptions:...
method cachePut (line 1) | async cachePut(t,e){const n=q(t);var i;await(i=0,new Promise(t=>setTim...
method getCacheKey (line 1) | async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=...
method hasCallback (line 1) | hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}
method runCallbacks (line 1) | async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await ...
method iterateCallbacks (line 1) | *iterateCallbacks(t){for(const e of this.l.plugins)if("function"==type...
method waitUntil (line 1) | waitUntil(t){return this.R.push(t),t}
method doneWaiting (line 1) | async doneWaiting(){for(;this.R.length;){const t=this.R.splice(0),e=(a...
method destroy (line 1) | destroy(){this.p.resolve(null)}
method q (line 1) | async q(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWil...
class L (line 1) | class L{constructor(t={}){this.cacheName=l(t.cacheName),this.plugins=t.p...
method constructor (line 1) | constructor(t={}){this.cacheName=l(t.cacheName),this.plugins=t.plugins...
method handle (line 1) | handle(t){const[e]=this.handleAll(t);return e}
method handleAll (line 1) | handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});...
method U (line 1) | async U(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,...
method L (line 1) | async L(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallba...
class b (line 1) | class b extends L{constructor(t={}){t.cacheName=u(t.cacheName),super(t),...
method constructor (line 1) | constructor(t={}){t.cacheName=u(t.cacheName),super(t),this.C=!1!==t.fa...
method _ (line 1) | async _(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"instal...
method N (line 1) | async N(t,e){let n;const i=e.params||{};if(!this.C)throw new s("missin...
method O (line 1) | async O(t,e){this.j();const n=await e.fetch(t);if(!await e.cachePut(t,...
method j (line 1) | j(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==b.copyR...
class C (line 1) | class C{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}...
method constructor (line 1) | constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this...
method strategy (line 1) | get strategy(){return this.l}
method precache (line 1) | precache(t){this.addToCacheList(t),this.T||(self.addEventListener("ins...
method addToCacheList (line 1) | addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.pu...
method install (line 1) | install(t){return f(t,async()=>{const e=new d;this.strategy.plugins.pu...
method activate (line 1) | activate(t){return f(t,async()=>{const t=await self.caches.open(this.s...
method getURLsToCacheKeys (line 1) | getURLsToCacheKeys(){return this.k}
method getCachedURLs (line 1) | getCachedURLs(){return[...this.k.keys()]}
method getCacheKeyForURL (line 1) | getCacheKeyForURL(t){const e=new URL(t,location.href);return this.k.ge...
method getIntegrityForCacheKey (line 1) | getIntegrityForCacheKey(t){return this.P.get(t)}
method matchPrecache (line 1) | async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.get...
method createHandlerBoundToURL (line 1) | createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)thr...
class x (line 1) | class x extends i{constructor(t,e){super(({request:s})=>{const n=t.getUR...
method constructor (line 1) | constructor(t,e){super(({request:s})=>{const n=t.getURLsToCacheKeys();...
function N (line 1) | function N(t){const e=O();!function(t,e,n){let a;if("string"==typeof t){...
FILE: demo/src/interactiveshell.ts
function appendToCode (line 37) | function appendToCode(text: string) {
function sendCommand (line 44) | function sendCommand(cmd: string) {
FILE: demo/src/screenrecord.ts
constant RECORD_FILE_NAME (line 87) | const RECORD_FILE_NAME = '/data/local/tmp/webadb-record.mp4';
FILE: src/lib/AdbClient.ts
constant VERSION (line 28) | const VERSION = 0x01000000;
constant VERSION_NO_CHECKSUM (line 29) | const VERSION_NO_CHECKSUM = 0x01000001;
constant MAX_PAYLOAD (line 30) | const MAX_PAYLOAD = 256 * 1024;
constant MACHINE_BANNER (line 32) | const MACHINE_BANNER = 'host::\0';
class AdbClient (line 34) | class AdbClient implements MessageListener {
method constructor (line 44) | constructor(
method registerStream (line 51) | registerStream(stream: Stream): void {
method unregisterStream (line 55) | unregisterStream(stream: Stream): void {
method newMessage (line 59) | newMessage(msg: Message): void {
method awaitMessage (line 70) | public async awaitMessage(): Promise<Message> {
method connect (line 74) | async connect(): Promise<AdbConnectionInformation> {
method disconnect (line 102) | async disconnect(): Promise<void> {
method shell (line 106) | async shell(command: string): Promise<string> {
method framebuffer (line 122) | async framebuffer(): Promise<Framebuffer> {
method interactiveShell (line 126) | async interactiveShell(callback?: (result: string) => void): Promise<S...
method sync (line 131) | async sync(): Promise<Stream> {
method pull (line 135) | async pull(filename: string): Promise<Blob> {
method push (line 150) | async push(blob: Blob, remotePath: string, mode: string, chunkSize: nu...
method doAuth (line 157) | private async doAuth(authResponse: Message): Promise<Message> {
method sendMessage (line 205) | public async sendMessage(m: Message): Promise<void> {
method generateKey (line 209) | static async generateKey(dump: boolean, keySize: number): Promise<Cryp...
FILE: src/lib/AdbConnectionInformation.ts
constant PRODUCT_NAME_KEY (line 17) | const PRODUCT_NAME_KEY = 'ro.product.name';
constant PRODUCT_MODEL_KEY (line 18) | const PRODUCT_MODEL_KEY = 'ro.product.model';
constant PRODUCT_DEVICE_KEY (line 19) | const PRODUCT_DEVICE_KEY = 'ro.product.device';
constant FEATURES_KEY (line 20) | const FEATURES_KEY = 'features';
constant DEFAULT_PRODUCT_VALUE (line 21) | const DEFAULT_PRODUCT_VALUE = '<unkwnown>';
class AdbConnectionInformation (line 23) | class AdbConnectionInformation {
method constructor (line 24) | constructor(
method fromDataView (line 33) | static fromDataView(input: DataView): AdbConnectionInformation {
method fromString (line 43) | static fromString(input: string): AdbConnectionInformation {
FILE: src/lib/Framebuffer.ts
class Framebuffer (line 63) | class Framebuffer {
method constructor (line 67) | private constructor(
method create (line 84) | static async create(adbClient: AdbClient, options: Options): Promise<F...
FILE: src/lib/Helpers.ts
function paddit (line 17) | function paddit(text: string, width: number, padding: string): string {
function toHex8 (line 28) | function toHex8(num: number): string {
function toHex16 (line 32) | function toHex16(num: number): string {
function toHex32 (line 36) | function toHex32(num: number): string {
function hexdump (line 40) | function hexdump(view: DataView, prefix = ''): void {
function toB64 (line 60) | function toB64(buffer: ArrayBuffer): string {
function privateKeyDump (line 64) | async function privateKeyDump(key: CryptoKeyPair): Promise<void> {
function publicKeyDump (line 74) | async function publicKeyDump(key: CryptoKeyPair): Promise<void> {
function encodeCmd (line 84) | function encodeCmd(cmd: string): number {
function decodeCmd (line 91) | function decodeCmd(cmd: number): string {
FILE: src/lib/IndexedDbKeyStore.ts
constant DB_NAME (line 19) | const DB_NAME = 'wadb';
constant DB_VERSION (line 20) | const DB_VERSION = 1;
constant STORE_NAME (line 21) | const STORE_NAME = 'keys';
function openDb (line 23) | function openDb(): Promise<IDBDatabase> {
class IndexedDbKeyStore (line 39) | class IndexedDbKeyStore implements KeyStore {
method loadKeys (line 40) | async loadKeys(): Promise<CryptoKeyPair[]> {
method saveKey (line 51) | async saveKey(key: CryptoKeyPair): Promise<void> {
FILE: src/lib/KeyStore.ts
type KeyStore (line 17) | interface KeyStore {
FILE: src/lib/Log.ts
class Log (line 17) | class Log {
method debug (line 18) | debug(message: string): void {
method info (line 22) | info(message: string): void {
method error (line 26) | error(message: string): void {
FILE: src/lib/Options.ts
type Options (line 17) | interface Options {
FILE: src/lib/Queues.ts
type Resolver (line 17) | type Resolver<T> = (value: T | PromiseLike<T>) => void;
class QueueEntry (line 19) | class QueueEntry<T> {
method constructor (line 23) | constructor(data: T) {
class Queue (line 31) | class Queue<T> {
method enqueue (line 39) | enqueue(data: T): void {
method dequeue (line 57) | dequeue(): T {
method isEmpty (line 70) | isEmpty(): boolean {
class AsyncBlockingQueue (line 82) | class AsyncBlockingQueue<T> {
method add (line 86) | private add(): void {
method enqueue (line 97) | enqueue(data: T): void {
method dequeue (line 110) | async dequeue(): Promise<T> {
method hasPendingPromises (line 117) | hasPendingPromises(): boolean {
method hasPendingResolvers (line 121) | hasPendingResolvers(): boolean {
FILE: src/lib/Shell.ts
type callbackFunction (line 20) | type callbackFunction = (text: string) => void;
class Shell (line 22) | class Shell {
method constructor (line 28) | constructor(readonly stream: Stream, readonly callbackFunction?: callb...
method loopRead (line 32) | private async loopRead(): Promise<void> {
method waitForMessage (line 58) | private waitForMessage(cmd: string): Promise<Message> {
method write (line 71) | async write(command: string): Promise<void> {
method close (line 77) | async close(): Promise<void> {
FILE: src/lib/Stream.ts
class Stream (line 24) | class Stream {
method constructor (line 28) | constructor(readonly client: AdbClient, readonly service: string, read...
method close (line 32) | async close(): Promise<void> {
method consumeMessage (line 43) | consumeMessage(msg: Message): boolean {
method write (line 52) | async write(cmd: string, data?: DataView): Promise<void> {
method read (line 57) | async read(): Promise<Message> {
method sendReceive (line 68) | async sendReceive(m: Message, responseCmd: string): Promise<void> {
method pull (line 90) | async pull(remotePath: string): Promise<Blob> {
method push (line 157) | async push(blob: Blob, remotePath: string, mode: string, chunkSize: nu...
method newMessage (line 223) | private newMessage(cmd: string, data?: DataView): Message {
method open (line 228) | static async open(adbClient: AdbClient, service: string, options: Opti...
FILE: src/lib/SyncFrame.ts
class SyncFrame (line 19) | class SyncFrame {
method constructor (line 20) | constructor(readonly cmd: string, readonly byteLength: number) {
method toDataView (line 24) | toDataView(): DataView {
method fromDataView (line 34) | static fromDataView(dataView: DataView): SyncFrame {
FILE: src/lib/message/Message.ts
class Message (line 24) | class Message {
method constructor (line 25) | constructor(
method dataAsString (line 34) | dataAsString(): string | null {
method newMessage (line 52) | static newMessage(
method open (line 74) | static open(localId: number, remoteId: number, service: string, useChe...
method cnxn (line 88) | static cnxn(version: number, maxPayload: number, banner: string, useCh...
method authSignature (line 100) | static authSignature(signedToken: DataView, useChecksum: boolean): Mes...
method authPublicKey (line 110) | static authPublicKey(publicKey: DataView, useChecksum: boolean): Messa...
method checksum (line 116) | private static checksum(dataView: DataView): number {
FILE: src/lib/message/MessageChannel.ts
class MessageChannel (line 23) | class MessageChannel {
method constructor (line 26) | constructor(
method readLoop (line 33) | private async readLoop(): Promise<void> {
method readHeader (line 44) | private async readHeader(): Promise<MessageHeader> {
method read (line 49) | private async read(): Promise<Message> {
method close (line 63) | close(): void {
method write (line 67) | async write(m: Message): Promise<void> {
FILE: src/lib/message/MessageHeader.ts
class MessageHeader (line 30) | class MessageHeader {
method constructor (line 42) | constructor(
method toDataView (line 54) | toDataView(): DataView {
method parse (line 72) | static parse(data: DataView, useChecksum = false): MessageHeader {
FILE: src/lib/message/MessageListener.ts
type MessageListener (line 19) | interface MessageListener {
FILE: src/lib/transport/Transport.ts
type Transport (line 20) | interface Transport {
FILE: src/lib/transport/WebUsbTransport.ts
constant ADB_DEVICE (line 21) | const ADB_DEVICE = {classCode: 255, subclassCode: 66, protocolCode: 1} a...
constant FASTBOOT_DEVICE (line 22) | const FASTBOOT_DEVICE = {classCode: 255, subclassCode: 66, protocolCode:...
constant DEVICE_FILTERS (line 23) | const DEVICE_FILTERS = [ADB_DEVICE, FASTBOOT_DEVICE];
type DeviceMatch (line 25) | interface DeviceMatch {
class WebUsbTransport (line 34) | class WebUsbTransport implements Transport {
method constructor (line 35) | private constructor(
method close (line 47) | async close(): Promise<void> {
method write (line 57) | async write(data: ArrayBuffer): Promise<void> {
method read (line 71) | async read(len: number): Promise<DataView> {
method isAdb (line 82) | isAdb(): boolean {
method isFastboot (line 90) | isFastboot(): boolean {
method open (line 100) | static async open(options: Options): Promise<WebUsbTransport> {
method findMatch (line 132) | private static findMatch(device: USBDevice, filter: USBDeviceFilter): ...
method getEndpointNum (line 151) | private static getEndpointNum(endpoints: USBEndpoint[], dir: 'in' | 'o...
FILE: src/spec/IndexedDbKeyStoreSpec.ts
function makeFakeKeyPair (line 21) | function makeFakeKeyPair(id: number): CryptoKeyPair {
FILE: src/spec/mock/MockKeyStore.ts
class MockKeyStore (line 19) | class MockKeyStore implements KeyStore {
method loadKeys (line 20) | loadKeys(): Promise<CryptoKeyPair[]> {
method saveKey (line 24) | saveKey(): Promise<void> {
FILE: src/spec/mock/MockMessageListener.ts
class MockMessageListener (line 20) | class MockMessageListener implements MessageListener {
method newMessage (line 23) | newMessage(msg: Message): void {
FILE: src/spec/mock/MockTransport.ts
class MockTransport (line 21) | class MockTransport implements Transport {
method pushFromFile (line 27) | async pushFromFile(fileName: string): Promise<void> {
method pushData (line 41) | pushData(data: DataView): void {
method pushMessage (line 49) | pushMessage(msg: Message): void {
method read (line 56) | async read(len: number): Promise<DataView> {
method write (line 69) | async write(data: ArrayBuffer): Promise<void> {
method close (line 74) | close(): void {
Condensed preview — 73 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (269K chars).
[
{
"path": ".eslintrc.json",
"chars": 460,
"preview": "{\n \"extends\": [\n \"plugin:@typescript-eslint/eslint-recommended\",\n \"plugin:@typescript-eslint/recommended\"\n ],\n "
},
{
"path": ".gitignore",
"chars": 33,
"preview": "node_modules/\ndist/\n.DS_Store\nwq\n"
},
{
"path": ".npmignore",
"chars": 18,
"preview": "tsconfig.json\nsrc\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 969,
"preview": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guid"
},
{
"path": "LICENSE",
"chars": 11361,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1716,
"preview": "# An ADB Implementation using WebUSB\n\nThis project is a TypeScript implementation of the Android Debug Bridge(ADB) proto"
},
{
"path": "demo/.firebaserc",
"chars": 66,
"preview": "{\n \"projects\": {\n \"default\": \"screenrecord-bandarra-me\"\n }\n}\n"
},
{
"path": "demo/.gitignore",
"chars": 1144,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nfirebase-debug.log*\n\n# Firebase cache\n.firebase/\n\n# Fir"
},
{
"path": "demo/firebase.json",
"chars": 134,
"preview": "{\n \"hosting\": {\n \"public\": \"public\",\n \"ignore\": [\n \"firebase.json\",\n \"**/.*\",\n \"**/node_modules/**"
},
{
"path": "demo/package.json",
"chars": 620,
"preview": "{\n \"name\": \"demo\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"private\": true,\n \"scripts\": {\n "
},
{
"path": "demo/public/404.html",
"chars": 1808,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initia"
},
{
"path": "demo/public/index.html",
"chars": 5322,
"preview": "<!--\n Copyright 2020 Google Inc. All Rights Reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n"
},
{
"path": "demo/public/interactiveshell.html",
"chars": 3031,
"preview": "<!--\n Copyright 2020 Google Inc. All Rights Reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n"
},
{
"path": "demo/public/js/interactiveshell.bundle.js",
"chars": 24495,
"preview": "(()=>{\"use strict\";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n"
},
{
"path": "demo/public/js/interactiveshell.d.ts",
"chars": 57,
"preview": "export {};\n//# sourceMappingURL=interactiveshell.d.ts.map"
},
{
"path": "demo/public/js/interactiveshell.js",
"chars": 3685,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/public/js/livestream.bundle.js",
"chars": 25189,
"preview": "(()=>{\"use strict\";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n"
},
{
"path": "demo/public/js/livestream.d.ts",
"chars": 51,
"preview": "export {};\n//# sourceMappingURL=livestream.d.ts.map"
},
{
"path": "demo/public/js/livestream.js",
"chars": 5098,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/public/js/screenrecord.bundle.js",
"chars": 26102,
"preview": "(()=>{\"use strict\";var e={834(e,t,n){var i=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n"
},
{
"path": "demo/public/js/screenrecord.d.ts",
"chars": 53,
"preview": "export {};\n//# sourceMappingURL=screenrecord.d.ts.map"
},
{
"path": "demo/public/js/screenrecord.js",
"chars": 6460,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/public/livestream.html",
"chars": 3806,
"preview": "<!--\n Copyright 2020 Google Inc. All Rights Reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n"
},
{
"path": "demo/public/screenrecord.html",
"chars": 4448,
"preview": "<!--\n Copyright 2020 Google Inc. All Rights Reserved.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n"
},
{
"path": "demo/public/sw.js",
"chars": 2291,
"preview": "if(!self.define){let e,s={};const r=(r,i)=>(r=new URL(r+\".js\",i).href,s[r]||new Promise(s=>{if(\"document\"in self){const "
},
{
"path": "demo/public/video.html",
"chars": 238,
"preview": "<!doctype html>\n<html>\n<head>\n <meta name=\"viewport\" content=\"initial-scale=1, maximum-scale=1\">\n <meta charset=\"utf-8"
},
{
"path": "demo/public/workbox-69b5a3b7.js",
"chars": 7761,
"preview": "define(\"./workbox-69b5a3b7.js\",[\"exports\"],(function(e){\"use strict\";try{self[\"workbox:core:5.1.4\"]&&_()}catch(e){}const"
},
{
"path": "demo/public/workbox-aa2f3006.js",
"chars": 14365,
"preview": "define([\"exports\"],function(t){\"use strict\";try{self[\"workbox:core:7.3.0\"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;ret"
},
{
"path": "demo/src/interactiveshell.ts",
"chars": 2443,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/src/livestream.ts",
"chars": 3823,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/src/screenrecord.ts",
"chars": 4934,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "demo/tsconfig.json",
"chars": 5965,
"preview": "{\n \"compilerOptions\": {\n /* Basic Options */\n // \"incremental\": true, /* Enable incremental com"
},
{
"path": "demo/webpack.config.js",
"chars": 1251,
"preview": "/**\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licen"
},
{
"path": "demo/workbox-config.js",
"chars": 131,
"preview": "module.exports = {\n \"globDirectory\": \"public/\",\n \"globPatterns\": [\n \"**/*.{html,svg,js,ts}\"\n ],\n \"swDest\": \"publi"
},
{
"path": "eslint.config.mjs",
"chars": 717,
"preview": "// @ts-check\nimport tsPlugin from '@typescript-eslint/eslint-plugin';\nimport tsParser from '@typescript-eslint/parser';\n"
},
{
"path": "jasmine.json",
"chars": 174,
"preview": "{\n \"spec_dir\": \"dist/spec\",\n \"spec_files\": [\n \"**/*[sS]pec.js\"\n ],\n \"helpers\": [\n \"helpers/**/*.js\"\n ],\n \"st"
},
{
"path": "package.json",
"chars": 932,
"preview": "{\n \"name\": \"wadb\",\n \"version\": \"0.1.0\",\n \"description\": \"\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n"
},
{
"path": "src/index.ts",
"chars": 977,
"preview": "/**\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licen"
},
{
"path": "src/lib/AdbClient.ts",
"chars": 7532,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/AdbConnectionInformation.ts",
"chars": 2492,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Framebuffer.ts",
"chars": 5152,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Helpers.ts",
"chars": 2947,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/IndexedDbKeyStore.ts",
"chars": 2151,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/KeyStore.ts",
"chars": 742,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Log.ts",
"chars": 848,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Options.ts",
"chars": 739,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Queues.ts",
"chars": 3175,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Shell.ts",
"chars": 2443,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/Stream.ts",
"chars": 9332,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/SyncFrame.ts",
"chars": 1227,
"preview": "/**\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licen"
},
{
"path": "src/lib/message/Message.ts",
"chars": 4665,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/message/MessageChannel.ts",
"chars": 2196,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/message/MessageHeader.ts",
"chars": 3185,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/message/MessageListener.ts",
"chars": 733,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/message/index.ts",
"chars": 755,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/transport/Transport.ts",
"chars": 1068,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/transport/WebUsbTransport.ts",
"chars": 5125,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/lib/transport/index.ts",
"chars": 690,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/AdbClientSpec.ts",
"chars": 1825,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/IndexedDbKeyStoreSpec.ts",
"chars": 2737,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/QueuesSpec.ts",
"chars": 5071,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/StreamSpec.ts",
"chars": 1496,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/SyncFrameSpec.ts",
"chars": 1501,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/data/messages/connect/connect_auth_public_key.json",
"chars": 130,
"preview": "[\n {\"cmd\": \"AUTH\", \"arg0\": 1, \"arg1\": 0, \"data\": \"auth_token\"},\n {\"cmd\": \"CNXN\", \"arg0\": 1, \"arg1\": 65536, \"data\": \"ho"
},
{
"path": "src/spec/data/messages/connect/connect_simple.json",
"chars": 62,
"preview": "[{\"cmd\": \"CNXN\", \"arg0\": 1, \"arg1\": 65536, \"data\": \"host://\"}]"
},
{
"path": "src/spec/data/messages/stream/open.json",
"chars": 45,
"preview": "[\n {\"cmd\": \"OKAY\", \"arg0\": 34, \"arg1\": 1}\n]\n"
},
{
"path": "src/spec/message/MessageChannelSpec.ts",
"chars": 3898,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/message/MessageHeaderSpec.ts",
"chars": 2506,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/message/MessageSpec.ts",
"chars": 4499,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/mock/MockKeyStore.ts",
"chars": 864,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/mock/MockMessageListener.ts",
"chars": 932,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "src/spec/mock/MockTransport.ts",
"chars": 2568,
"preview": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "tsconfig.json",
"chars": 356,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"es2015\",\n \"module\": \"commonjs\",\n \"outDir\": \"./dist\",\n \"strict\": true,\n "
}
]
About this extraction
This page contains the full source code of the GoogleChromeLabs/wadb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 73 files (251.8 KB), approximately 70.6k tokens, and a symbol index with 338 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.