tasmota-esp-web-tools 11.0.0 → 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/connect.js CHANGED
@@ -1,29 +1,72 @@
1
+ import { connect as esptoolConnect } from "tasmota-webserial-esptool";
2
+ /**
3
+ * Detect if running on Android
4
+ */
5
+ const isAndroid = () => {
6
+ const userAgent = navigator.userAgent || "";
7
+ return /Android/i.test(userAgent);
8
+ };
9
+ /**
10
+ * Load WebUSB serial wrapper for Android
11
+ */
12
+ const loadWebUSBSerial = async () => {
13
+ // Check if already loaded
14
+ if (globalThis.requestSerialPort) {
15
+ return;
16
+ }
17
+ // Dynamically load the WebUSB serial script from the npm package
18
+ return new Promise((resolve, reject) => {
19
+ const script = document.createElement("script");
20
+ script.type = "module";
21
+ script.src =
22
+ "https://unpkg.com/tasmota-webserial-esptool/js/webusb-serial.js";
23
+ script.onload = () => {
24
+ if (globalThis.requestSerialPort) {
25
+ resolve();
26
+ }
27
+ else {
28
+ reject(new Error("WebUSB serial script loaded but requestSerialPort not found"));
29
+ }
30
+ };
31
+ script.onerror = () => reject(new Error("Failed to load WebUSB serial script"));
32
+ document.head.appendChild(script);
33
+ });
34
+ };
1
35
  export const connect = async (button) => {
2
36
  import("./install-dialog.js");
3
- let port;
37
+ // Android: Load WebUSB support first
38
+ if (isAndroid() && "usb" in navigator) {
39
+ try {
40
+ await loadWebUSBSerial();
41
+ }
42
+ catch (err) {
43
+ alert(`Failed to load WebUSB support: ${err.message}`);
44
+ return;
45
+ }
46
+ }
47
+ // Use tasmota-webserial-esptool's connect() - handles ALL port logic
48
+ let esploader;
4
49
  try {
5
- port = await navigator.serial.requestPort();
50
+ esploader = await esptoolConnect({
51
+ log: () => { }, // Silent logger for connection
52
+ debug: () => { },
53
+ error: (msg) => console.error(msg),
54
+ });
6
55
  }
7
56
  catch (err) {
8
57
  if (err.name === "NotFoundError") {
9
58
  import("./no-port-picked/index").then((mod) => mod.openNoPortPickedDialog(() => connect(button)));
10
59
  return;
11
60
  }
12
- alert(`Error: ${err.message}`);
61
+ alert(`Connection failed: ${err.message}`);
13
62
  return;
14
63
  }
15
- if (!port) {
16
- return;
17
- }
18
- try {
19
- await port.open({ baudRate: 115200 });
20
- }
21
- catch (err) {
22
- alert(err.message);
64
+ if (!esploader) {
65
+ alert("Failed to connect to device");
23
66
  return;
24
67
  }
25
68
  const el = document.createElement("ewt-install-dialog");
26
- el.port = port;
69
+ el.esploader = esploader; // Pass ESPLoader instead of port
27
70
  el.manifestPath = button.manifest || button.getAttribute("manifest");
28
71
  el.overrides = button.overrides;
29
72
  el.firmwareFile = button.firmwareFile;
@@ -38,8 +81,13 @@ export const connect = async (button) => {
38
81
  else if (button.baudRate !== undefined) {
39
82
  el.baudRate = button.baudRate;
40
83
  }
41
- el.addEventListener("closed", () => {
42
- port.close();
84
+ el.addEventListener("closed", async () => {
85
+ try {
86
+ await esploader.disconnect();
87
+ }
88
+ catch (err) {
89
+ // Ignore disconnect errors
90
+ }
43
91
  }, { once: true });
44
92
  document.body.appendChild(el);
45
93
  };
package/dist/const.d.ts CHANGED
@@ -72,13 +72,7 @@ export interface ErrorState extends BaseFlashState {
72
72
  details: string | Error;
73
73
  };
74
74
  }
75
- export interface ESP32S2USBReconnectState extends BaseFlashState {
76
- state: FlashStateType.ESP32_S2_USB_RECONNECT;
77
- details: {
78
- oldPort: SerialPort;
79
- };
80
- }
81
- export type FlashState = InitializingState | ManifestState | PreparingState | ErasingState | WritingState | FinishedState | ErrorState | ESP32S2USBReconnectState;
75
+ export type FlashState = InitializingState | ManifestState | PreparingState | ErasingState | WritingState | FinishedState | ErrorState;
82
76
  export declare const enum FlashStateType {
83
77
  INITIALIZING = "initializing",
84
78
  MANIFEST = "manifest",
@@ -86,16 +80,14 @@ export declare const enum FlashStateType {
86
80
  ERASING = "erasing",
87
81
  WRITING = "writing",
88
82
  FINISHED = "finished",
89
- ERROR = "error",
90
- ESP32_S2_USB_RECONNECT = "esp32_s2_usb_reconnect"
83
+ ERROR = "error"
91
84
  }
92
85
  export declare const enum FlashError {
93
86
  FAILED_INITIALIZING = "failed_initialize",
94
87
  FAILED_MANIFEST_FETCH = "fetch_manifest_failed",
95
88
  NOT_SUPPORTED = "not_supported",
96
89
  FAILED_FIRMWARE_DOWNLOAD = "failed_firmware_download",
97
- WRITE_FAILED = "write_failed",
98
- ESP32_S2_USB_RECONNECT = "esp32_s2_usb_reconnect"
90
+ WRITE_FAILED = "write_failed"
99
91
  }
100
92
  declare global {
101
93
  interface HTMLElementEventMap {
package/dist/flash.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Logger } from "tasmota-webserial-esptool";
2
2
  import { FlashState } from "./const";
3
- export declare const flash: (onEvent: (state: FlashState) => void, port: SerialPort, logger: Logger, manifestPath: string, eraseFirst: boolean, firmwareBuffer: Uint8Array, baudRate?: number) => Promise<void>;
3
+ export declare const flash: (onEvent: (state: FlashState) => void, esploader: any, // ESPLoader instance from tasmota-webserial-esptool
4
+ logger: Logger, manifestPath: string, eraseFirst: boolean, firmwareBuffer: Uint8Array, baudRate?: number) => Promise<void>;
package/dist/flash.js CHANGED
@@ -1,13 +1,11 @@
1
- import { ESPLoader } from "tasmota-webserial-esptool";
2
1
  import { getChipFamilyName } from "./util/chip-family-name";
3
2
  import { sleep } from "./util/sleep";
4
- import { isESP32S2NativeUSB, isESP32S2ReconnectError, closeAndForgetPort, } from "./util/esp32s2-reconnect";
5
- export const flash = async (onEvent, port, logger, manifestPath, eraseFirst, firmwareBuffer, baudRate) => {
3
+ export const flash = async (onEvent, esploader, // ESPLoader instance from tasmota-webserial-esptool
4
+ logger, manifestPath, eraseFirst, firmwareBuffer, baudRate) => {
6
5
  let manifest;
7
6
  let build;
8
7
  let chipFamily;
9
8
  let chipVariant = null;
10
- const isS2NativeUSB = isESP32S2NativeUSB(port);
11
9
  const fireStateEvent = (stateUpdate) => onEvent({
12
10
  ...stateUpdate,
13
11
  manifest,
@@ -24,57 +22,31 @@ export const flash = async (onEvent, port, logger, manifestPath, eraseFirst, fir
24
22
  manifestURL = new URL(manifestPath, location.toString()).toString();
25
23
  manifestProm = fetch(manifestURL).then((resp) => resp.json());
26
24
  }
27
- const esploader = new ESPLoader(port, logger);
25
+ // Use the provided ESPLoader instance - NO port logic here!
28
26
  // For debugging
29
27
  window.esploader = esploader;
30
- // ESP32-S2 Native USB event handler - listen on ESPLoader instance
31
- const handleESP32S2Reconnect = () => {
32
- logger.log("ESP32-S2 Native USB disconnect detected - reconnection required");
33
- };
34
- // Register event listener for ESP32-S2 Native USB reconnect on ESPLoader
35
- if (isS2NativeUSB) {
36
- esploader.addEventListener("esp32s2-usb-reconnect", handleESP32S2Reconnect);
37
- logger.log("ESP32-S2 Native USB detected - monitoring for port switch");
38
- }
39
- // Cleanup function to remove event listener
40
- const cleanup = () => {
41
- if (isS2NativeUSB) {
42
- esploader.removeEventListener("esp32s2-usb-reconnect", handleESP32S2Reconnect);
43
- }
44
- };
45
28
  fireStateEvent({
46
29
  state: "initializing" /* FlashStateType.INITIALIZING */,
47
30
  message: "Initializing...",
48
31
  details: { done: false },
49
32
  });
50
- try {
51
- await esploader.initialize();
52
- }
53
- catch (err) {
54
- logger.error(err);
55
- // Check if this is an ESP32-S2 Native USB reconnect situation
56
- if (isS2NativeUSB && isESP32S2ReconnectError(err)) {
57
- cleanup();
58
- // Close and forget the old port
59
- await closeAndForgetPort(port);
60
- // Fire reconnect event to trigger port reselection dialog
33
+ // Only initialize if not already done
34
+ if (!esploader.chipFamily) {
35
+ try {
36
+ await esploader.initialize();
37
+ }
38
+ catch (err) {
39
+ logger.error(err);
61
40
  fireStateEvent({
62
- state: "esp32_s2_usb_reconnect" /* FlashStateType.ESP32_S2_USB_RECONNECT */,
63
- message: "ESP32-S2 USB port changed - please select the new port",
64
- details: { oldPort: port },
41
+ state: "error" /* FlashStateType.ERROR */,
42
+ message: "Failed to initialize. Try resetting your device or holding the BOOT button while clicking INSTALL.",
43
+ details: { error: "failed_initialize" /* FlashError.FAILED_INITIALIZING */, details: err },
65
44
  });
45
+ if (esploader.connected) {
46
+ await esploader.disconnect();
47
+ }
66
48
  return;
67
49
  }
68
- cleanup();
69
- fireStateEvent({
70
- state: "error" /* FlashStateType.ERROR */,
71
- message: "Failed to initialize. Try resetting your device or holding the BOOT button while clicking INSTALL.",
72
- details: { error: "failed_initialize" /* FlashError.FAILED_INITIALIZING */, details: err },
73
- });
74
- if (esploader.connected) {
75
- await esploader.disconnect();
76
- }
77
- return;
78
50
  }
79
51
  chipFamily = getChipFamilyName(esploader);
80
52
  chipVariant = esploader.chipVariant;
@@ -92,7 +64,6 @@ export const flash = async (onEvent, port, logger, manifestPath, eraseFirst, fir
92
64
  manifest = await manifestProm;
93
65
  }
94
66
  catch (err) {
95
- cleanup();
96
67
  fireStateEvent({
97
68
  state: "error" /* FlashStateType.ERROR */,
98
69
  message: `Unable to fetch manifest: ${err}`,
@@ -106,80 +77,74 @@ export const flash = async (onEvent, port, logger, manifestPath, eraseFirst, fir
106
77
  if (b.chipFamily !== chipFamily) {
107
78
  return false;
108
79
  }
109
- // If build specifies a chipVariant, it must match
110
- if (b.chipVariant !== undefined) {
111
- return b.chipVariant === chipVariant;
80
+ // If build specifies chipVariant, it must match
81
+ if (b.chipVariant && b.chipVariant !== chipVariant) {
82
+ return false;
112
83
  }
113
- // If build doesn't specify chipVariant, it matches any variant
114
84
  return true;
115
85
  });
116
- fireStateEvent({
117
- state: "manifest" /* FlashStateType.MANIFEST */,
118
- message: `Found manifest for ${manifest.name}`,
119
- details: { done: true },
120
- });
121
86
  if (!build) {
122
- const chipInfo = chipVariant
123
- ? `${chipFamily} (${chipVariant})`
124
- : chipFamily;
125
- cleanup();
126
87
  fireStateEvent({
127
88
  state: "error" /* FlashStateType.ERROR */,
128
- message: `Your ${chipInfo} board is not supported.`,
129
- details: { error: "not_supported" /* FlashError.NOT_SUPPORTED */, details: chipInfo },
89
+ message: `Your ${chipFamily}${chipVariant ? ` (${chipVariant})` : ""} is not supported by this firmware.`,
90
+ details: { error: "not_supported" /* FlashError.NOT_SUPPORTED */, details: chipFamily },
130
91
  });
131
92
  await esploader.disconnect();
132
93
  return;
133
94
  }
95
+ fireStateEvent({
96
+ state: "manifest" /* FlashStateType.MANIFEST */,
97
+ message: "Manifest fetched",
98
+ details: { done: true },
99
+ });
134
100
  fireStateEvent({
135
101
  state: "preparing" /* FlashStateType.PREPARING */,
136
102
  message: "Preparing installation...",
137
103
  details: { done: false },
138
104
  });
105
+ // The esploader passed in is always a stub (from _ensureStub())
106
+ // Baudrate was already set in _ensureStub()
107
+ const espStub = esploader;
108
+ // Verify stub has chipFamily (should be copied in _ensureStub)
109
+ if (!espStub.chipFamily) {
110
+ logger.error("Stub missing chipFamily - this should not happen!");
111
+ fireStateEvent({
112
+ state: "error" /* FlashStateType.ERROR */,
113
+ message: "Internal error: Stub not properly initialized",
114
+ details: {
115
+ error: "failed_initialize" /* FlashError.FAILED_INITIALIZING */,
116
+ details: "Missing chipFamily",
117
+ },
118
+ });
119
+ return;
120
+ }
121
+ logger.log(`Using stub: IS_STUB=${espStub.IS_STUB}, chipFamily=${espStub.chipFamily}`);
122
+ // Fetch firmware files
139
123
  const filePromises = build.parts.map(async (part) => {
140
- if (firmwareBuffer.length == 0) {
141
- //No firmware buffer provided, now download ...
142
- const url = new URL(part.path, manifestURL).toString();
143
- const resp = await fetch(url);
144
- if (!resp.ok) {
145
- throw new Error(`Downlading firmware ${part.path} failed: ${resp.status}`);
146
- }
147
- return resp.arrayBuffer();
124
+ const url = new URL(part.path, manifestURL || location.toString()).toString();
125
+ const resp = await fetch(url);
126
+ if (!resp.ok) {
127
+ throw new Error(`Downlading firmware ${part.path} failed: ${resp.status}`);
148
128
  }
149
- // buffer from local file upload
150
- return firmwareBuffer;
129
+ return resp.arrayBuffer();
151
130
  });
152
- // Run the stub while we wait for files to download
153
- const espStub = await esploader.runStub();
154
- // Increase baud rate for faster flashing if specified via baud-rate attribute
155
- // Default: No change (115200 baud - stub default)
156
- // Can be set via baud-rate attribute in HTML (e.g., baud-rate="2000000")
157
- if (baudRate !== undefined && baudRate > 115200) {
158
- try {
159
- await espStub.setBaudrate(baudRate);
160
- }
161
- catch (err) {
162
- // If baud rate change fails, continue with default 115200
163
- logger.log(`Could not change baud rate to ${baudRate}: ${err.message}`);
164
- }
131
+ // If firmwareBuffer is provided, use it instead of fetching
132
+ if (firmwareBuffer) {
133
+ filePromises.push(Promise.resolve(firmwareBuffer.buffer));
165
134
  }
166
135
  const files = [];
167
136
  let totalSize = 0;
168
137
  for (const prom of filePromises) {
169
138
  try {
170
139
  const data = await prom;
171
- files.push(data instanceof ArrayBuffer ? new Uint8Array(data) : data);
140
+ files.push(data);
172
141
  totalSize += data.byteLength;
173
142
  }
174
143
  catch (err) {
175
- cleanup();
176
144
  fireStateEvent({
177
145
  state: "error" /* FlashStateType.ERROR */,
178
146
  message: err.message,
179
- details: {
180
- error: "failed_firmware_download" /* FlashError.FAILED_FIRMWARE_DOWNLOAD */,
181
- details: err.message,
182
- },
147
+ details: { error: "failed_firmware_download" /* FlashError.FAILED_FIRMWARE_DOWNLOAD */, details: err },
183
148
  });
184
149
  await esploader.disconnect();
185
150
  return;
@@ -190,78 +155,90 @@ export const flash = async (onEvent, port, logger, manifestPath, eraseFirst, fir
190
155
  message: "Installation prepared",
191
156
  details: { done: true },
192
157
  });
158
+ // CRITICAL: Erase MUST be done BEFORE writing, if requested
193
159
  if (eraseFirst) {
194
160
  fireStateEvent({
195
161
  state: "erasing" /* FlashStateType.ERASING */,
196
- message: "Erasing device...",
162
+ message: "Erasing flash...",
197
163
  details: { done: false },
198
164
  });
199
- await espStub.eraseFlash();
200
- fireStateEvent({
201
- state: "erasing" /* FlashStateType.ERASING */,
202
- message: "Device erased",
203
- details: { done: true },
204
- });
165
+ try {
166
+ logger.log("Erasing flash memory. Please wait...");
167
+ await espStub.eraseFlash();
168
+ logger.log("Flash erased successfully");
169
+ fireStateEvent({
170
+ state: "erasing" /* FlashStateType.ERASING */,
171
+ message: "Flash erased",
172
+ details: { done: true },
173
+ });
174
+ }
175
+ catch (err) {
176
+ logger.error(`Flash erase failed: ${err.message}`);
177
+ fireStateEvent({
178
+ state: "error" /* FlashStateType.ERROR */,
179
+ message: `Failed to erase flash: ${err.message}`,
180
+ details: { error: "write_failed" /* FlashError.WRITE_FAILED */, details: err },
181
+ });
182
+ await esploader.disconnect();
183
+ return;
184
+ }
205
185
  }
206
- let lastPct = 0;
207
186
  fireStateEvent({
208
187
  state: "writing" /* FlashStateType.WRITING */,
209
- message: `Writing progress: ${lastPct}%`,
188
+ message: `Writing progress: 0 %`,
210
189
  details: {
211
190
  bytesTotal: totalSize,
212
191
  bytesWritten: 0,
213
- percentage: lastPct,
192
+ percentage: 0,
214
193
  },
215
194
  });
216
- let totalWritten = 0;
217
- for (const part of build.parts) {
218
- const file = files.shift();
219
- const fileBuffer = file instanceof Uint8Array ? new Uint8Array(file).buffer : file;
220
- try {
221
- await espStub.flashData(fileBuffer, (bytesWritten) => {
222
- const newPct = Math.floor(((totalWritten + bytesWritten) / totalSize) * 100);
195
+ let lastPct = 0;
196
+ let totalBytesWritten = 0;
197
+ try {
198
+ for (let i = 0; i < build.parts.length; i++) {
199
+ const part = build.parts[i];
200
+ const data = files[i];
201
+ await espStub.flashData(data, (bytesWritten, bytesTotal) => {
202
+ const newPct = Math.floor(((totalBytesWritten + bytesWritten) / totalSize) * 100);
223
203
  if (newPct === lastPct) {
224
204
  return;
225
205
  }
226
206
  lastPct = newPct;
227
207
  fireStateEvent({
228
208
  state: "writing" /* FlashStateType.WRITING */,
229
- message: `Writing progress: ${newPct}%`,
209
+ message: `Writing progress: ${newPct} %`,
230
210
  details: {
231
211
  bytesTotal: totalSize,
232
- bytesWritten: totalWritten + bytesWritten,
212
+ bytesWritten: totalBytesWritten + bytesWritten,
233
213
  percentage: newPct,
234
214
  },
235
215
  });
236
- }, part.offset, true);
216
+ }, part.offset);
217
+ totalBytesWritten += data.byteLength;
237
218
  }
238
- catch (err) {
239
- cleanup();
240
- fireStateEvent({
241
- state: "error" /* FlashStateType.ERROR */,
242
- message: err.message,
243
- details: { error: "write_failed" /* FlashError.WRITE_FAILED */, details: err },
244
- });
245
- await esploader.disconnect();
246
- return;
247
- }
248
- totalWritten += file.byteLength;
219
+ }
220
+ catch (err) {
221
+ fireStateEvent({
222
+ state: "error" /* FlashStateType.ERROR */,
223
+ message: err.message,
224
+ details: { error: "write_failed" /* FlashError.WRITE_FAILED */, details: err },
225
+ });
226
+ await esploader.disconnect();
227
+ return;
249
228
  }
250
229
  fireStateEvent({
251
230
  state: "writing" /* FlashStateType.WRITING */,
252
231
  message: "Writing complete",
253
232
  details: {
254
233
  bytesTotal: totalSize,
255
- bytesWritten: totalWritten,
234
+ bytesWritten: totalSize,
256
235
  percentage: 100,
257
236
  },
258
237
  });
259
238
  await sleep(100);
260
- console.log("DISCONNECT");
261
- await esploader.disconnect();
262
- console.log("HARD RESET");
263
- await esploader.hardReset();
264
- cleanup();
239
+ // DON'T release locks after flash!
240
+ // Keep the stub and locks so the port can be used again
241
+ // (e.g., for Improv, Manage Filesystem, or another flash)
265
242
  fireStateEvent({
266
243
  state: "finished" /* FlashStateType.FINISHED */,
267
244
  message: "All done!",
@@ -9,7 +9,7 @@ export class InstallButton extends HTMLElement {
9
9
  this.toggleAttribute("install-unsupported", true);
10
10
  this.renderRoot.innerHTML = !InstallButton.isAllowed
11
11
  ? "<slot name='not-allowed'>You can only install ESP devices on HTTPS websites or on the localhost.</slot>"
12
- : "<slot name='unsupported'>Your browser does not support installing things on ESP devices. Use Google Chrome or Microsoft Edge.</slot>";
12
+ : "<slot name='unsupported'>Your browser does not support installing things on ESP devices. Use Google Chrome or Microsoft Edge (Desktop) or Chrome on Android with USB OTG.</slot>";
13
13
  return;
14
14
  }
15
15
  this.toggleAttribute("install-supported", true);
@@ -36,7 +36,7 @@ export class InstallButton extends HTMLElement {
36
36
  this.renderRoot.append(slot);
37
37
  }
38
38
  }
39
- InstallButton.isSupported = "serial" in navigator;
39
+ InstallButton.isSupported = "serial" in navigator || "usb" in navigator;
40
40
  InstallButton.isAllowed = window.isSecureContext;
41
41
  InstallButton.style = `
42
42
  button {
@@ -14,7 +14,7 @@ import "./pages/ewt-page-message";
14
14
  import { Logger, Manifest } from "./const.js";
15
15
  import { ImprovSerial } from "improv-wifi-serial-sdk/dist/serial";
16
16
  export declare class EwtInstallDialog extends LitElement {
17
- port: SerialPort;
17
+ esploader: any;
18
18
  manifestPath: string;
19
19
  firmwareFile?: File;
20
20
  baudRate?: number;
@@ -33,12 +33,15 @@ export declare class EwtInstallDialog extends LitElement {
33
33
  private _wasProvisioned;
34
34
  private _error?;
35
35
  private _busy;
36
- private _esp32s2ReconnectInProgress;
37
36
  private _ssids?;
38
37
  private _selectedSsid;
39
38
  private _partitions?;
40
39
  private _selectedPartition?;
41
40
  private _espStub?;
41
+ private _improvChecked;
42
+ private get _isAndroid();
43
+ private _ensureStub;
44
+ private get _port();
42
45
  protected render(): TemplateResult<1>;
43
46
  _renderProgress(label: string | TemplateResult, progress?: number): TemplateResult<1>;
44
47
  _renderError(label: string): [string, TemplateResult, boolean];
@@ -50,8 +53,6 @@ export declare class EwtInstallDialog extends LitElement {
50
53
  _renderLogs(): [string | undefined, TemplateResult, boolean];
51
54
  _renderPartitions(): [string | undefined, TemplateResult, boolean];
52
55
  _renderLittleFS(): [string | undefined, TemplateResult, boolean, boolean];
53
- _renderESP32S2Reconnect(): [string | undefined, TemplateResult, boolean];
54
- private _handleESP32S2ReconnectClick;
55
56
  private _readPartitionTable;
56
57
  private _openFilesystem;
57
58
  private _formatSize;
@@ -61,12 +62,6 @@ export declare class EwtInstallDialog extends LitElement {
61
62
  private _focusFormElement;
62
63
  private _initialize;
63
64
  private _startInstall;
64
- /**
65
- * Handle ESP32-S2 Native USB reconnect.
66
- * When the ESP32-S2 switches from ROM bootloader to USB CDC mode,
67
- * the USB port changes and we need to let the user select the new port.
68
- */
69
- private _handleESP32S2Reconnect;
70
65
  private _confirmInstall;
71
66
  _flashFilebuffer(fileBuffer: Uint8Array): Promise<void>;
72
67
  private _doProvision;