react-native-web-serial-api 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +23 -0
  2. package/TESTING.md +301 -0
  3. package/android/build.gradle +2 -2
  4. package/android/src/main/java/dev/webserialapi/NativeUsbSerialModule.java +7 -1
  5. package/lib/commonjs/UsbSerial.js +58 -26
  6. package/lib/commonjs/UsbSerial.js.map +1 -1
  7. package/lib/commonjs/WebSerial.js +169 -57
  8. package/lib/commonjs/WebSerial.js.map +1 -1
  9. package/lib/commonjs/index.js +13 -1
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/lib/dom-exception.js +176 -0
  12. package/lib/commonjs/lib/dom-exception.js.map +1 -0
  13. package/lib/commonjs/lib/event-target.js +138 -0
  14. package/lib/commonjs/lib/event-target.js.map +1 -0
  15. package/lib/commonjs/lib/promise.js +23 -0
  16. package/lib/commonjs/lib/promise.js.map +1 -0
  17. package/lib/commonjs/testing/index.js +70 -0
  18. package/lib/commonjs/testing/index.js.map +1 -0
  19. package/lib/commonjs/testing/install.js +54 -0
  20. package/lib/commonjs/testing/install.js.map +1 -0
  21. package/lib/commonjs/testing/serial-device.js +164 -0
  22. package/lib/commonjs/testing/serial-device.js.map +1 -0
  23. package/lib/commonjs/testing/virtual-serial.js +615 -0
  24. package/lib/commonjs/testing/virtual-serial.js.map +1 -0
  25. package/lib/commonjs/transport.js +61 -0
  26. package/lib/commonjs/transport.js.map +1 -0
  27. package/lib/typescript/src/UsbSerial.d.ts +24 -67
  28. package/lib/typescript/src/UsbSerial.d.ts.map +1 -1
  29. package/lib/typescript/src/WebSerial.d.ts +11 -2
  30. package/lib/typescript/src/WebSerial.d.ts.map +1 -1
  31. package/lib/typescript/src/index.d.ts +2 -0
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/lib/dom-exception.d.ts +100 -0
  34. package/lib/typescript/src/lib/dom-exception.d.ts.map +1 -0
  35. package/lib/typescript/src/lib/event-target.d.ts +53 -0
  36. package/lib/typescript/src/lib/event-target.d.ts.map +1 -0
  37. package/lib/typescript/src/lib/promise.d.ts +11 -0
  38. package/lib/typescript/src/lib/promise.d.ts.map +1 -0
  39. package/lib/typescript/src/testing/index.d.ts +23 -0
  40. package/lib/typescript/src/testing/index.d.ts.map +1 -0
  41. package/lib/typescript/src/testing/install.d.ts +25 -0
  42. package/lib/typescript/src/testing/install.d.ts.map +1 -0
  43. package/lib/typescript/src/testing/serial-device.d.ts +127 -0
  44. package/lib/typescript/src/testing/serial-device.d.ts.map +1 -0
  45. package/lib/typescript/src/testing/virtual-serial.d.ts +205 -0
  46. package/lib/typescript/src/testing/virtual-serial.d.ts.map +1 -0
  47. package/lib/typescript/src/transport.d.ts +131 -0
  48. package/lib/typescript/src/transport.d.ts.map +1 -0
  49. package/package.json +38 -2
  50. package/src/UsbSerial.ts +65 -90
  51. package/src/WebSerial.ts +227 -88
  52. package/src/index.ts +2 -7
  53. package/src/lib/dom-exception.ts +129 -60
  54. package/src/lib/event-target.ts +46 -21
  55. package/src/lib/promise.ts +7 -7
  56. package/src/testing/index.ts +42 -0
  57. package/src/testing/install.ts +65 -0
  58. package/src/testing/serial-device.ts +193 -0
  59. package/src/testing/virtual-serial.ts +801 -0
  60. package/src/transport.ts +200 -0
  61. package/babel.config.js +0 -3
  62. package/biome.json +0 -35
  63. package/example/.watchmanconfig +0 -1
  64. package/example/App.tsx +0 -71
  65. package/example/__tests__/App.test.tsx +0 -16
  66. package/example/__tests__/connectEvents.test.tsx +0 -81
  67. package/example/__tests__/getPorts.test.tsx +0 -140
  68. package/example/android/app/build.gradle +0 -120
  69. package/example/android/app/debug.keystore +0 -0
  70. package/example/android/app/proguard-rules.pro +0 -10
  71. package/example/android/app/src/debug/AndroidManifest.xml +0 -9
  72. package/example/android/app/src/main/AndroidManifest.xml +0 -38
  73. package/example/android/app/src/main/java/dev/uzlopak/MainActivity.kt +0 -22
  74. package/example/android/app/src/main/java/dev/uzlopak/MainApplication.kt +0 -41
  75. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  76. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  77. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  78. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  79. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  80. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  81. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  82. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  83. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  84. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  85. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  86. package/example/android/app/src/main/res/values/strings.xml +0 -3
  87. package/example/android/app/src/main/res/values/styles.xml +0 -9
  88. package/example/android/build.gradle +0 -22
  89. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  90. package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  91. package/example/android/gradle.properties +0 -47
  92. package/example/android/gradlew +0 -252
  93. package/example/android/gradlew.bat +0 -94
  94. package/example/android/settings.gradle +0 -6
  95. package/example/app.json +0 -4
  96. package/example/babel.config.js +0 -21
  97. package/example/biome.json +0 -47
  98. package/example/deploy.sh +0 -11
  99. package/example/index.html +0 -26
  100. package/example/index.js +0 -9
  101. package/example/index.web.js +0 -8
  102. package/example/jest.config.js +0 -12
  103. package/example/metro.config.js +0 -58
  104. package/example/package-lock.json +0 -14510
  105. package/example/package.json +0 -48
  106. package/example/react-native.config.js +0 -17
  107. package/example/src/components/AppBar.tsx +0 -73
  108. package/example/src/components/Menu.tsx +0 -90
  109. package/example/src/components/SingleChoiceDialog.tsx +0 -120
  110. package/example/src/screens/ConnectScreen.tsx +0 -195
  111. package/example/src/screens/DevicesScreen.tsx +0 -248
  112. package/example/src/screens/TerminalScreen.tsx +0 -564
  113. package/example/src/settings.ts +0 -43
  114. package/example/src/theme.ts +0 -19
  115. package/example/src/util/TextUtil.ts +0 -129
  116. package/example/tsconfig.json +0 -10
  117. package/example/vite.config.mjs +0 -55
  118. package/scripts/deploy-release.sh +0 -127
  119. package/tsconfig.build.json +0 -7
  120. package/tsconfig.json +0 -20
@@ -1,129 +0,0 @@
1
- // Ported from SimpleUsbTerminal TextUtil.java
2
-
3
- export const NEWLINE_CRLF = '\r\n';
4
- export const NEWLINE_LF = '\n';
5
-
6
- /** A run of text; `caret` runs (^X control-char notation) get a gray background. */
7
- export type Run = {text: string; caret: boolean};
8
-
9
- /** Parse a hex string ("AA BB CC" / "aabbcc") into bytes, ignoring non-hex chars. */
10
- export function fromHexString(s: string): Uint8Array {
11
- const out: number[] = [];
12
- let b = 0;
13
- let nibble = 0;
14
- for (let i = 0; i < s.length; i++) {
15
- if (nibble === 2) {
16
- out.push(b & 0xff);
17
- nibble = 0;
18
- b = 0;
19
- }
20
- const c = s.charCodeAt(i);
21
- if (c >= 0x30 && c <= 0x39) {
22
- nibble++;
23
- b = b * 16 + (c - 0x30);
24
- } else if (c >= 0x41 && c <= 0x46) {
25
- nibble++;
26
- b = b * 16 + (c - 0x41 + 10);
27
- } else if (c >= 0x61 && c <= 0x66) {
28
- nibble++;
29
- b = b * 16 + (c - 0x61 + 10);
30
- }
31
- }
32
- if (nibble > 0) {
33
- out.push(b & 0xff);
34
- }
35
- return Uint8Array.from(out);
36
- }
37
-
38
- /** Format bytes as space-separated uppercase hex: "AA BB CC". */
39
- export function toHexString(buf: Uint8Array | number[]): string {
40
- let sb = '';
41
- for (let i = 0; i < buf.length; i++) {
42
- if (sb.length > 0) {
43
- sb += ' ';
44
- }
45
- sb += (buf[i] & 0xff).toString(16).toUpperCase().padStart(2, '0');
46
- }
47
- return sb;
48
- }
49
-
50
- /** HexWatcher formatting: keep only hex chars, uppercase, group into pairs. */
51
- export function formatHexInput(s: string): string {
52
- let hex = '';
53
- for (let i = 0; i < s.length; i++) {
54
- const c = s[i];
55
- if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
56
- hex += c;
57
- } else if (c >= 'a' && c <= 'f') {
58
- hex += c.toUpperCase();
59
- }
60
- }
61
- let grouped = '';
62
- for (let i = 0; i < hex.length; i++) {
63
- if (i > 0 && i % 2 === 0) {
64
- grouped += ' ';
65
- }
66
- grouped += hex[i];
67
- }
68
- return grouped;
69
- }
70
-
71
- /**
72
- * Caret notation (https://en.wikipedia.org/wiki/Caret_notation) so invisible
73
- * control characters are shown as ^X with a highlighted background.
74
- */
75
- export function toCaretRuns(s: string, keepNewline: boolean): Run[] {
76
- const runs: Run[] = [];
77
- let plain = '';
78
- const flush = () => {
79
- if (plain) {
80
- runs.push({text: plain, caret: false});
81
- plain = '';
82
- }
83
- };
84
- for (let i = 0; i < s.length; i++) {
85
- const ch = s.charCodeAt(i);
86
- if (ch < 32 && !(keepNewline && ch === 10)) {
87
- flush();
88
- runs.push({text: `^${String.fromCharCode(ch + 64)}`, caret: true});
89
- } else {
90
- plain += s[i];
91
- }
92
- }
93
- flush();
94
- return runs;
95
- }
96
-
97
- const decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder() : null;
98
- const encoder = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null;
99
-
100
- /** Decode received bytes to a string (UTF-8 when available, else Latin-1). */
101
- export function bytesToString(data: Uint8Array): string {
102
- if (decoder) {
103
- return decoder.decode(data);
104
- }
105
- let s = '';
106
- for (let i = 0; i < data.length; i++) {
107
- s += String.fromCharCode(data[i]);
108
- }
109
- return s;
110
- }
111
-
112
- /** Encode a string to UTF-8 bytes for sending. */
113
- export function stringToBytes(str: string): Uint8Array {
114
- if (encoder) {
115
- return encoder.encode(str);
116
- }
117
- const out: number[] = [];
118
- for (let i = 0; i < str.length; i++) {
119
- const c = str.charCodeAt(i);
120
- if (c < 0x80) {
121
- out.push(c);
122
- } else if (c < 0x800) {
123
- out.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));
124
- } else {
125
- out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));
126
- }
127
- }
128
- return Uint8Array.from(out);
129
- }
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "@react-native/typescript-config",
3
- "compilerOptions": {
4
- "lib": ["ESNext", "DOM"],
5
- "paths": {
6
- "react-native-web-serial-api": ["../src/index"]
7
- }
8
- },
9
- "include": ["App.tsx", "index.js", "index.web.js", "src", "__tests__"]
10
- }
@@ -1,55 +0,0 @@
1
- import {createRequire} from 'node:module';
2
- import path from 'node:path';
3
- import react from '@vitejs/plugin-react';
4
- import {defineConfig} from 'vite';
5
-
6
- const require = createRequire(import.meta.url);
7
- const rootPkg = require('../package.json');
8
-
9
- // Absolute path to react-native-web so the alias resolves correctly even from
10
- // the library source outside this folder (avoids duplicate-module resolution).
11
- const reactNativeWeb = path.dirname(
12
- require.resolve('react-native-web/package.json'),
13
- );
14
-
15
- // Resolve platform-specific files (.web.ts wins on web) the way Metro does.
16
- const extensions = [
17
- '.web.tsx',
18
- '.web.ts',
19
- '.web.jsx',
20
- '.web.js',
21
- '.tsx',
22
- '.ts',
23
- '.jsx',
24
- '.js',
25
- '.json',
26
- ];
27
-
28
- export default defineConfig({
29
- root: import.meta.dirname,
30
- plugins: [react()],
31
- define: {
32
- // React Native / RNW globals expected at runtime
33
- global: 'globalThis',
34
- __DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
35
- 'process.env.NODE_ENV': JSON.stringify(
36
- process.env.NODE_ENV || 'development',
37
- ),
38
- },
39
- resolve: {
40
- extensions,
41
- alias: [
42
- // Consume the library straight from its TypeScript source (live reload)
43
- {
44
- find: new RegExp(`^${rootPkg.name}$`),
45
- replacement: path.resolve(import.meta.dirname, '..', rootPkg.source),
46
- },
47
- // react-native -> react-native-web (exact match only, so it doesn't
48
- // rewrite react-native-web or react-native-web-serial-api)
49
- {find: /^react-native$/, replacement: reactNativeWeb},
50
- ],
51
- },
52
- optimizeDeps: {
53
- include: ['react-native-web', 'web-streams-polyfill'],
54
- },
55
- });
@@ -1,127 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Build and install a standalone RELEASE build of the example app.
4
- #
5
- # A release build embeds the JS bundle (assets/index.android.bundle) into the
6
- # APK, so the app runs WITHOUT Metro / a dev server. The JS bundler runs once
7
- # at build time; after install the app is fully self-contained.
8
- #
9
- # Usage:
10
- # ./scripts/deploy-release.sh # build, install on the connected device, launch
11
- # ./scripts/deploy-release.sh --build # build the APK only (no install)
12
- # ./scripts/deploy-release.sh --no-launch
13
- # DEVICE=192.168.1.50:5555 ./scripts/deploy-release.sh # target a specific adb device
14
- #
15
- # Environment overrides (auto-detected if unset):
16
- # JAVA_HOME - JDK 17 (RN 0.85 / Gradle 8.13 require JDK 17-21)
17
- # ANDROID_HOME - Android SDK location
18
- # NODE_BIN - directory containing a Node >= 20 binary (RN 0.85 metro needs it)
19
- #
20
- set -euo pipefail
21
-
22
- APP_ID="dev.react_native_web_serial_api.example"
23
- MAIN_ACTIVITY="${APP_ID}/.MainActivity"
24
-
25
- # Resolve paths relative to this script so it works from any CWD.
26
- # This script lives in <repo>/scripts; the buildable app is in <repo>/example
27
- # (the repo-root android/ is the library module and has no gradlew).
28
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
- REPO_ROOT="$(dirname "$SCRIPT_DIR")"
30
- EXAMPLE_DIR="$REPO_ROOT/example"
31
- ANDROID_DIR="$EXAMPLE_DIR/android"
32
- APK="$ANDROID_DIR/app/build/outputs/apk/release/app-release.apk"
33
-
34
- # --- arg parsing ---------------------------------------------------------
35
- DO_INSTALL=1
36
- DO_LAUNCH=1
37
- for arg in "$@"; do
38
- case "$arg" in
39
- --build) DO_INSTALL=0; DO_LAUNCH=0 ;;
40
- --no-launch) DO_LAUNCH=0 ;;
41
- -h|--help) grep '^#' "$0" | grep -v '^#!' | sed 's/^# \{0,1\}//'; exit 0 ;;
42
- *) echo "Unknown option: $arg" >&2; exit 1 ;;
43
- esac
44
- done
45
-
46
- # --- toolchain auto-detection -------------------------------------------
47
- # JDK 17 (only override if the current java isn't already 17-21).
48
- if [ -z "${JAVA_HOME:-}" ]; then
49
- for d in /usr/lib/jvm/java-17-openjdk-amd64 /usr/lib/jvm/java-21-openjdk-amd64 \
50
- /usr/lib/jvm/temurin-17-jdk-amd64; do
51
- [ -d "$d" ] && export JAVA_HOME="$d" && break
52
- done
53
- fi
54
- [ -n "${JAVA_HOME:-}" ] && echo "JAVA_HOME=$JAVA_HOME"
55
-
56
- # Android SDK.
57
- if [ -z "${ANDROID_HOME:-}" ]; then
58
- for d in "$HOME/Android/Sdk" "$HOME/Library/Android/sdk" "${ANDROID_SDK_ROOT:-}"; do
59
- [ -n "$d" ] && [ -d "$d" ] && export ANDROID_HOME="$d" && break
60
- done
61
- fi
62
- if [ -z "${ANDROID_HOME:-}" ]; then
63
- echo "ERROR: Android SDK not found. Set ANDROID_HOME." >&2
64
- exit 1
65
- fi
66
- echo "ANDROID_HOME=$ANDROID_HOME"
67
- export PATH="$ANDROID_HOME/platform-tools:$PATH"
68
-
69
- # Node >= 20 (RN 0.85 metro-config uses Array.prototype.toReversed()).
70
- need_node() { node -e 'process.exit(typeof [].toReversed==="function"?0:1)' 2>/dev/null; }
71
- if [ -n "${NODE_BIN:-}" ]; then
72
- export PATH="$NODE_BIN:$PATH"
73
- fi
74
- if ! command -v node >/dev/null 2>&1 || ! need_node; then
75
- # Try the newest nvm-managed Node >= 20.
76
- if [ -d "$HOME/.nvm/versions/node" ]; then
77
- for v in $(ls -1 "$HOME/.nvm/versions/node" | sort -Vr); do
78
- if "$HOME/.nvm/versions/node/$v/bin/node" -e 'process.exit(typeof [].toReversed==="function"?0:1)' 2>/dev/null; then
79
- export PATH="$HOME/.nvm/versions/node/$v/bin:$PATH"
80
- break
81
- fi
82
- done
83
- fi
84
- fi
85
- if ! need_node; then
86
- echo "ERROR: need Node >= 20 (found $(node -v 2>/dev/null || echo none)). Set NODE_BIN." >&2
87
- exit 1
88
- fi
89
- echo "node=$(node -v)"
90
-
91
- # --- pick adb device -----------------------------------------------------
92
- adb_target=()
93
- if [ -n "${DEVICE:-}" ]; then
94
- adb connect "$DEVICE" >/dev/null 2>&1 || true
95
- adb_target=(-s "$DEVICE")
96
- fi
97
-
98
- # --- build ---------------------------------------------------------------
99
- echo "==> Building release APK (embeds JS bundle)…"
100
- ( cd "$ANDROID_DIR" && ./gradlew :app:assembleRelease )
101
-
102
- if [ ! -f "$APK" ]; then
103
- echo "ERROR: APK not found at $APK" >&2
104
- exit 1
105
- fi
106
- echo "==> Built: $APK ($(du -h "$APK" | cut -f1))"
107
-
108
- [ "$DO_INSTALL" -eq 1 ] || { echo "Build-only mode; done."; exit 0; }
109
-
110
- # --- install -------------------------------------------------------------
111
- echo "==> Installing on device…"
112
- # Capture output instead of piping into `grep -q`: under `set -o pipefail`,
113
- # grep closing the pipe early can make a successful install report failure.
114
- install_out="$(adb "${adb_target[@]}" install -r "$APK" 2>&1)" || true
115
- echo "$install_out"
116
- if ! grep -q "Success" <<<"$install_out"; then
117
- echo "==> Reinstall failed (likely signature mismatch); uninstalling and retrying…"
118
- adb "${adb_target[@]}" uninstall "$APP_ID" >/dev/null 2>&1 || true
119
- adb "${adb_target[@]}" install "$APK"
120
- fi
121
-
122
- [ "$DO_LAUNCH" -eq 1 ] || { echo "Installed (not launched)."; exit 0; }
123
-
124
- # --- launch --------------------------------------------------------------
125
- echo "==> Launching $MAIN_ACTIVITY…"
126
- adb "${adb_target[@]}" shell am start -n "$MAIN_ACTIVITY" >/dev/null
127
- echo "==> Done. The app runs standalone (no Metro needed)."
@@ -1,7 +0,0 @@
1
- {
2
- "extends": "./tsconfig",
3
- "compilerOptions": {
4
- "noEmit": false
5
- },
6
- "exclude": ["example", "lib", "node_modules"]
7
- }
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "rootDir": ".",
4
- "esModuleInterop": true,
5
- "forceConsistentCasingInFileNames": true,
6
- "jsx": "react-jsx",
7
- "lib": ["ESNext", "DOM"],
8
- "module": "ESNext",
9
- "moduleResolution": "bundler",
10
- "noFallthroughCasesInSwitch": true,
11
- "noImplicitReturns": true,
12
- "resolveJsonModule": true,
13
- "skipLibCheck": true,
14
- "strict": true,
15
- "target": "ESNext",
16
- "noEmit": true
17
- },
18
- "include": ["src"],
19
- "exclude": ["example", "lib", "node_modules"]
20
- }