@allwright.dev/core 0.1.7 → 0.1.9
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/README.md +4 -0
- package/dist/bootstrap.js +1 -1
- package/dist/mobile.js +195 -1
- package/dist/page.js +81 -4
- package/dist/types.d.ts +86 -7
- package/package.json +1 -1
- package/proto/core/v1/context.proto +41 -0
- package/proto/surfaces/mobile/v1/mobile.proto +9 -0
- package/proto/surfaces/web/v1/web.proto +7 -6
package/README.md
CHANGED
|
@@ -47,6 +47,10 @@ const download = await hook.wait();
|
|
|
47
47
|
await download.saveAs(`artifacts/${download.suggestedFilename}`);
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
Paths passed to `setFiles` and `saveAs` belong to the test process, even when
|
|
51
|
+
the Allwright server is remote. Android apps support the same `fileChooser` and
|
|
52
|
+
`download` hook shape; Android `newPage` hooks are not applicable.
|
|
53
|
+
|
|
50
54
|
Runnable examples live in [examples/web-basic.ts](./examples/web-basic.ts) and [examples/android-basic.ts](./examples/android-basic.ts).
|
|
51
55
|
|
|
52
56
|
Shared config files are stack-agnostic and can live in `allwright.config.yaml` or `allwright.config.json`.
|
package/dist/bootstrap.js
CHANGED
|
@@ -12,7 +12,7 @@ const ALLWRIGHT_HOME_ENV_VAR = "ALLWRIGHT_HOME";
|
|
|
12
12
|
const ALLWRIGHT_REPOSITORY_ENV_VAR = "ALLWRIGHT_REPOSITORY";
|
|
13
13
|
const ALLWRIGHT_VERSION_ENV_VAR = "ALLWRIGHT_VERSION";
|
|
14
14
|
const DEFAULT_RELEASE_REPOSITORY = "allwright-dev/allwright";
|
|
15
|
-
const DEFAULT_RELEASE_VERSION = "0.1.
|
|
15
|
+
const DEFAULT_RELEASE_VERSION = "0.1.9";
|
|
16
16
|
const STARTUP_TIMEOUT_MS = 20_000;
|
|
17
17
|
const PING_TIMEOUT_MS = 1_000;
|
|
18
18
|
const PROTO_ROOT = fileURLToPath(new URL("../proto/", import.meta.url));
|
package/dist/mobile.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createBrowserSessionHandle, createPageHandle, getRuntime } from "./runtime.js";
|
|
2
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { open, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { basename } from "node:path";
|
|
3
5
|
import { chainMobileSelectorForTransport, normalizeMobileSelectorForTransport } from "./mobileSelectors.js";
|
|
4
6
|
function retryOptions(timeoutMs) {
|
|
5
7
|
return timeoutMs ? { timeoutMs } : undefined;
|
|
@@ -17,6 +19,164 @@ class MobileAndroidAppImpl {
|
|
|
17
19
|
locator(selector) {
|
|
18
20
|
return new MobileAndroidLocatorImpl(this, normalizeMobileSelectorForTransport(selector));
|
|
19
21
|
}
|
|
22
|
+
async registerHook(type) {
|
|
23
|
+
if (type.name !== "fileChooser" && type.name !== "download") {
|
|
24
|
+
throw new Error(`hook type ${type.name} is not supported by Android apps`);
|
|
25
|
+
}
|
|
26
|
+
const handle = await this.#getHandle();
|
|
27
|
+
this.#ensureOpen(handle);
|
|
28
|
+
handle.stream.write({
|
|
29
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
30
|
+
contextSessionId: this.sessionId,
|
|
31
|
+
registerHook: type.name === "fileChooser"
|
|
32
|
+
? { mobileFileChooser: {} }
|
|
33
|
+
: { mobileDownload: {} },
|
|
34
|
+
});
|
|
35
|
+
while (true) {
|
|
36
|
+
const event = await handle.queue.next();
|
|
37
|
+
if (event.hookRegistered?.hookId) {
|
|
38
|
+
const hookId = event.hookRegistered.hookId;
|
|
39
|
+
return {
|
|
40
|
+
id: hookId,
|
|
41
|
+
type,
|
|
42
|
+
wait: (options = {}) => this.#waitForHook(hookId, type, options),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (event.error?.message)
|
|
46
|
+
throw new Error(event.error.message);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async #waitForHook(hookId, type, options) {
|
|
50
|
+
const handle = await this.#getHandle();
|
|
51
|
+
this.#ensureOpen(handle);
|
|
52
|
+
handle.stream.write({
|
|
53
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
54
|
+
contextSessionId: this.sessionId,
|
|
55
|
+
waitForHook: { hookId, retryOptions: retryOptions(options.timeoutMs) },
|
|
56
|
+
});
|
|
57
|
+
while (true) {
|
|
58
|
+
const event = await handle.queue.next();
|
|
59
|
+
if (event.hookCompleted?.hookId === hookId) {
|
|
60
|
+
if (type.name === "fileChooser" && event.hookCompleted.mobileFileChooser?.fileChooserId) {
|
|
61
|
+
return new MobileFileChooserImpl(this, event.hookCompleted.mobileFileChooser.fileChooserId, event.hookCompleted.mobileFileChooser.isMultiple ?? false);
|
|
62
|
+
}
|
|
63
|
+
if (type.name === "download" && event.hookCompleted.mobileDownload?.downloadId) {
|
|
64
|
+
return new MobileDownloadImpl(this, event.hookCompleted.mobileDownload.downloadId, event.hookCompleted.mobileDownload.suggestedFilename ?? "download");
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`Android ${type.name} hook returned an invalid result`);
|
|
67
|
+
}
|
|
68
|
+
if (event.error?.message)
|
|
69
|
+
throw new Error(event.error.message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async setChooserFiles(fileChooserId, files, options) {
|
|
73
|
+
const handle = await this.#getHandle();
|
|
74
|
+
this.#ensureOpen(handle);
|
|
75
|
+
const fileIds = [];
|
|
76
|
+
for (const file of files)
|
|
77
|
+
fileIds.push(await this.#uploadLocalFile(handle, file));
|
|
78
|
+
handle.stream.write({
|
|
79
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
80
|
+
contextSessionId: this.sessionId,
|
|
81
|
+
setMobileFileChooserFiles: {
|
|
82
|
+
fileChooserId,
|
|
83
|
+
fileIds,
|
|
84
|
+
retryOptions: retryOptions(options.timeoutMs),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
while (true) {
|
|
88
|
+
const event = await handle.queue.next();
|
|
89
|
+
if (event.mobileFileChooserFilesSet?.fileChooserId === fileChooserId)
|
|
90
|
+
return;
|
|
91
|
+
if (event.error?.message)
|
|
92
|
+
throw new Error(event.error.message);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async saveMobileDownload(downloadId, path, options) {
|
|
96
|
+
const handle = await this.#getHandle();
|
|
97
|
+
this.#ensureOpen(handle);
|
|
98
|
+
handle.stream.write({
|
|
99
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
100
|
+
contextSessionId: this.sessionId,
|
|
101
|
+
saveMobileDownload: { downloadId, retryOptions: retryOptions(options.timeoutMs) },
|
|
102
|
+
});
|
|
103
|
+
while (true) {
|
|
104
|
+
const event = await handle.queue.next();
|
|
105
|
+
if (event.mobileDownloadSaved?.downloadId === downloadId && event.mobileDownloadSaved.fileId) {
|
|
106
|
+
await this.#downloadToLocalFile(handle, event.mobileDownloadSaved.fileId, path);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (event.error?.message)
|
|
110
|
+
throw new Error(event.error.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async #uploadLocalFile(handle, path) {
|
|
114
|
+
const source = await open(path, "r");
|
|
115
|
+
const transferId = randomUUID();
|
|
116
|
+
let offset = 0;
|
|
117
|
+
try {
|
|
118
|
+
const size = (await source.stat()).size;
|
|
119
|
+
do {
|
|
120
|
+
const buffer = Buffer.alloc(Math.min(256 * 1024, Math.max(0, size - offset)) || 1);
|
|
121
|
+
const { bytesRead } = await source.read(buffer, 0, buffer.length, offset);
|
|
122
|
+
const last = offset + bytesRead >= size;
|
|
123
|
+
handle.stream.write({
|
|
124
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
125
|
+
contextSessionId: this.sessionId,
|
|
126
|
+
uploadFileChunk: {
|
|
127
|
+
transferId,
|
|
128
|
+
name: basename(path),
|
|
129
|
+
offset: String(offset),
|
|
130
|
+
data: buffer.subarray(0, bytesRead),
|
|
131
|
+
last,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
offset += bytesRead;
|
|
135
|
+
} while (offset < size);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
await source.close();
|
|
139
|
+
}
|
|
140
|
+
while (true) {
|
|
141
|
+
const event = await handle.queue.next();
|
|
142
|
+
if (event.fileUploaded?.transferId === transferId && event.fileUploaded.fileId) {
|
|
143
|
+
return event.fileUploaded.fileId;
|
|
144
|
+
}
|
|
145
|
+
if (event.error?.message)
|
|
146
|
+
throw new Error(event.error.message);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async #downloadToLocalFile(handle, fileId, path) {
|
|
150
|
+
const temporaryPath = `${path}.allwright-${randomUUID()}.tmp`;
|
|
151
|
+
const destination = await open(temporaryPath, "wx");
|
|
152
|
+
let offset = 0;
|
|
153
|
+
try {
|
|
154
|
+
while (true) {
|
|
155
|
+
handle.stream.write({
|
|
156
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
157
|
+
contextSessionId: this.sessionId,
|
|
158
|
+
readFileChunk: { fileId, offset: String(offset), maxBytes: 256 * 1024 },
|
|
159
|
+
});
|
|
160
|
+
const event = await handle.queue.next();
|
|
161
|
+
if (event.error?.message)
|
|
162
|
+
throw new Error(event.error.message);
|
|
163
|
+
if (event.fileChunk?.fileId !== fileId || Number(event.fileChunk.offset ?? -1) !== offset)
|
|
164
|
+
continue;
|
|
165
|
+
const data = event.fileChunk.data ?? new Uint8Array();
|
|
166
|
+
await destination.write(data, 0, data.length, offset);
|
|
167
|
+
offset += data.length;
|
|
168
|
+
if (event.fileChunk.last)
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
await destination.close();
|
|
172
|
+
await rename(temporaryPath, path);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
await destination.close().catch(() => undefined);
|
|
176
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
20
180
|
async click(selector, options = {}) {
|
|
21
181
|
const handle = await this.#getHandle();
|
|
22
182
|
this.#ensureOpen(handle);
|
|
@@ -322,6 +482,40 @@ class MobileAndroidAppImpl {
|
|
|
322
482
|
}
|
|
323
483
|
}
|
|
324
484
|
}
|
|
485
|
+
class MobileFileChooserImpl {
|
|
486
|
+
page;
|
|
487
|
+
id;
|
|
488
|
+
multiple;
|
|
489
|
+
constructor(page, id, multiple) {
|
|
490
|
+
this.page = page;
|
|
491
|
+
this.id = id;
|
|
492
|
+
this.multiple = multiple;
|
|
493
|
+
}
|
|
494
|
+
isMultiple() {
|
|
495
|
+
return this.multiple;
|
|
496
|
+
}
|
|
497
|
+
async setFiles(files, options = {}) {
|
|
498
|
+
const paths = typeof files === "string" ? [files] : files;
|
|
499
|
+
if (!this.multiple && paths.length > 1) {
|
|
500
|
+
throw new Error("Android file chooser does not accept multiple files");
|
|
501
|
+
}
|
|
502
|
+
await this.page.setChooserFiles(this.id, paths, options);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
class MobileDownloadImpl {
|
|
506
|
+
page;
|
|
507
|
+
id;
|
|
508
|
+
suggestedFilename;
|
|
509
|
+
url = "";
|
|
510
|
+
constructor(page, id, suggestedFilename) {
|
|
511
|
+
this.page = page;
|
|
512
|
+
this.id = id;
|
|
513
|
+
this.suggestedFilename = suggestedFilename;
|
|
514
|
+
}
|
|
515
|
+
async saveAs(path, options = {}) {
|
|
516
|
+
await this.page.saveMobileDownload(this.id, path, options);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
325
519
|
class MobileAndroidLocatorImpl {
|
|
326
520
|
page;
|
|
327
521
|
selector;
|
package/dist/page.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { WebLocatorBuilders } from "./web-locators.js";
|
|
2
2
|
import { LocatorImpl } from "./locator.js";
|
|
3
|
-
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { open, rename, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { basename } from "node:path";
|
|
4
6
|
import { formatActionError } from "./errors.js";
|
|
5
7
|
import { normalizeSelectorForTransport } from "./selectors.js";
|
|
6
8
|
import { createPageHandle } from "./runtime.js";
|
|
@@ -85,12 +87,16 @@ export class PageImpl extends WebLocatorBuilders {
|
|
|
85
87
|
async setFileChooserFiles(fileChooserId, files, options = {}) {
|
|
86
88
|
const handle = await this.#getHandle();
|
|
87
89
|
this.#ensureOpen(handle);
|
|
90
|
+
const fileIds = [];
|
|
91
|
+
for (const file of files) {
|
|
92
|
+
fileIds.push(await this.#uploadLocalFile(handle, file));
|
|
93
|
+
}
|
|
88
94
|
handle.stream.write({
|
|
89
95
|
surfaceSessionId: this.browserSessionId,
|
|
90
96
|
contextSessionId: this.sessionId,
|
|
91
97
|
setFileChooserFiles: {
|
|
92
98
|
fileChooserId,
|
|
93
|
-
|
|
99
|
+
fileIds,
|
|
94
100
|
retryOptions: options.timeoutMs ? { timeoutMs: options.timeoutMs } : undefined,
|
|
95
101
|
},
|
|
96
102
|
});
|
|
@@ -112,13 +118,13 @@ export class PageImpl extends WebLocatorBuilders {
|
|
|
112
118
|
contextSessionId: this.sessionId,
|
|
113
119
|
saveDownload: {
|
|
114
120
|
downloadId,
|
|
115
|
-
path,
|
|
116
121
|
retryOptions: options.timeoutMs ? { timeoutMs: options.timeoutMs } : undefined,
|
|
117
122
|
},
|
|
118
123
|
});
|
|
119
124
|
while (true) {
|
|
120
125
|
const event = await handle.queue.next();
|
|
121
|
-
if (event.downloadSaved?.downloadId === downloadId) {
|
|
126
|
+
if (event.downloadSaved?.downloadId === downloadId && event.downloadSaved.fileId) {
|
|
127
|
+
await this.#downloadToLocalFile(handle, event.downloadSaved.fileId, path);
|
|
122
128
|
return;
|
|
123
129
|
}
|
|
124
130
|
if (event.error?.message) {
|
|
@@ -126,6 +132,77 @@ export class PageImpl extends WebLocatorBuilders {
|
|
|
126
132
|
}
|
|
127
133
|
}
|
|
128
134
|
}
|
|
135
|
+
async #uploadLocalFile(handle, path) {
|
|
136
|
+
const source = await open(path, "r");
|
|
137
|
+
const transferId = randomUUID();
|
|
138
|
+
const name = basename(path);
|
|
139
|
+
let offset = 0;
|
|
140
|
+
try {
|
|
141
|
+
const size = (await source.stat()).size;
|
|
142
|
+
do {
|
|
143
|
+
const buffer = Buffer.alloc(Math.min(256 * 1024, Math.max(0, size - offset)) || 1);
|
|
144
|
+
const { bytesRead } = await source.read(buffer, 0, buffer.length, offset);
|
|
145
|
+
const last = offset + bytesRead >= size;
|
|
146
|
+
handle.stream.write({
|
|
147
|
+
surfaceSessionId: this.browserSessionId,
|
|
148
|
+
contextSessionId: this.sessionId,
|
|
149
|
+
uploadFileChunk: {
|
|
150
|
+
transferId,
|
|
151
|
+
name,
|
|
152
|
+
offset: String(offset),
|
|
153
|
+
data: buffer.subarray(0, bytesRead),
|
|
154
|
+
last,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
offset += bytesRead;
|
|
158
|
+
} while (offset < size);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await source.close();
|
|
162
|
+
}
|
|
163
|
+
while (true) {
|
|
164
|
+
const event = await handle.queue.next();
|
|
165
|
+
if (event.fileUploaded?.transferId === transferId && event.fileUploaded.fileId) {
|
|
166
|
+
return event.fileUploaded.fileId;
|
|
167
|
+
}
|
|
168
|
+
if (event.error?.message) {
|
|
169
|
+
throw formatActionError("upload file", event.error.message);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async #downloadToLocalFile(handle, fileId, path) {
|
|
174
|
+
const temporaryPath = `${path}.allwright-${randomUUID()}.tmp`;
|
|
175
|
+
const destination = await open(temporaryPath, "wx");
|
|
176
|
+
let offset = 0;
|
|
177
|
+
try {
|
|
178
|
+
while (true) {
|
|
179
|
+
handle.stream.write({
|
|
180
|
+
surfaceSessionId: this.browserSessionId,
|
|
181
|
+
contextSessionId: this.sessionId,
|
|
182
|
+
readFileChunk: { fileId, offset: String(offset), maxBytes: 256 * 1024 },
|
|
183
|
+
});
|
|
184
|
+
const event = await handle.queue.next();
|
|
185
|
+
if (event.error?.message) {
|
|
186
|
+
throw formatActionError("download file", event.error.message);
|
|
187
|
+
}
|
|
188
|
+
if (event.fileChunk?.fileId !== fileId || Number(event.fileChunk.offset ?? -1) !== offset) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const data = event.fileChunk.data ?? new Uint8Array();
|
|
192
|
+
await destination.write(data, 0, data.length, offset);
|
|
193
|
+
offset += data.length;
|
|
194
|
+
if (event.fileChunk.last)
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
await destination.close();
|
|
198
|
+
await rename(temporaryPath, path);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
await destination.close().catch(() => undefined);
|
|
202
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
129
206
|
locator(selector, options) {
|
|
130
207
|
const result = new LocatorImpl({ page: this, selector: normalizeSelectorForTransport(selector) });
|
|
131
208
|
return options ? result.filter(options) : result;
|
package/dist/types.d.ts
CHANGED
|
@@ -110,13 +110,13 @@ export interface Hook<T> {
|
|
|
110
110
|
}
|
|
111
111
|
export interface FileChooser {
|
|
112
112
|
readonly id: string;
|
|
113
|
-
readonly page: Page;
|
|
113
|
+
readonly page: Page | MobileAndroidApp;
|
|
114
114
|
isMultiple(): boolean;
|
|
115
115
|
setFiles(files: string | string[], options?: CommandOptions): Promise<void>;
|
|
116
116
|
}
|
|
117
117
|
export interface Download {
|
|
118
118
|
readonly id: string;
|
|
119
|
-
readonly page: Page;
|
|
119
|
+
readonly page: Page | MobileAndroidApp;
|
|
120
120
|
readonly url: string;
|
|
121
121
|
readonly suggestedFilename: string;
|
|
122
122
|
saveAs(path: string, options?: CommandOptions): Promise<void>;
|
|
@@ -192,6 +192,7 @@ export interface MobileAndroidApp {
|
|
|
192
192
|
innerText(selector: string, options?: CommandOptions): Promise<TextResult>;
|
|
193
193
|
waitForSelector(selector: string, options?: WaitForSelectorOptions): Promise<WaitForSelectorResult>;
|
|
194
194
|
screenshot(options?: ScreenshotOptions): Promise<ScreenshotResult>;
|
|
195
|
+
registerHook<T>(type: HookType<T>): Promise<Hook<T>>;
|
|
195
196
|
}
|
|
196
197
|
export interface MobileAndroidDevice {
|
|
197
198
|
readonly sessionId: string;
|
|
@@ -411,15 +412,51 @@ export interface ContextSessionEvent {
|
|
|
411
412
|
suggestedFilename?: string;
|
|
412
413
|
note?: string;
|
|
413
414
|
};
|
|
415
|
+
mobileFileChooser?: {
|
|
416
|
+
fileChooserId?: string;
|
|
417
|
+
isMultiple?: boolean;
|
|
418
|
+
note?: string;
|
|
419
|
+
};
|
|
420
|
+
mobileDownload?: {
|
|
421
|
+
downloadId?: string;
|
|
422
|
+
suggestedFilename?: string;
|
|
423
|
+
note?: string;
|
|
424
|
+
};
|
|
414
425
|
};
|
|
415
426
|
fileChooserFilesSet?: {
|
|
416
427
|
fileChooserId?: string;
|
|
417
|
-
|
|
428
|
+
fileIds?: string[];
|
|
418
429
|
note?: string;
|
|
419
430
|
};
|
|
420
431
|
downloadSaved?: {
|
|
421
432
|
downloadId?: string;
|
|
422
|
-
|
|
433
|
+
fileId?: string;
|
|
434
|
+
suggestedFilename?: string;
|
|
435
|
+
size?: string;
|
|
436
|
+
note?: string;
|
|
437
|
+
};
|
|
438
|
+
fileUploaded?: {
|
|
439
|
+
transferId?: string;
|
|
440
|
+
fileId?: string;
|
|
441
|
+
name?: string;
|
|
442
|
+
size?: string;
|
|
443
|
+
};
|
|
444
|
+
fileChunk?: {
|
|
445
|
+
fileId?: string;
|
|
446
|
+
offset?: string;
|
|
447
|
+
data?: Uint8Array;
|
|
448
|
+
last?: boolean;
|
|
449
|
+
};
|
|
450
|
+
mobileFileChooserFilesSet?: {
|
|
451
|
+
fileChooserId?: string;
|
|
452
|
+
fileIds?: string[];
|
|
453
|
+
note?: string;
|
|
454
|
+
};
|
|
455
|
+
mobileDownloadSaved?: {
|
|
456
|
+
downloadId?: string;
|
|
457
|
+
fileId?: string;
|
|
458
|
+
suggestedFilename?: string;
|
|
459
|
+
size?: string;
|
|
423
460
|
note?: string;
|
|
424
461
|
};
|
|
425
462
|
navigated?: {
|
|
@@ -517,6 +554,8 @@ export interface RegisterHookRequest {
|
|
|
517
554
|
newPage?: Record<string, never>;
|
|
518
555
|
fileChooser?: Record<string, never>;
|
|
519
556
|
download?: Record<string, never>;
|
|
557
|
+
mobileFileChooser?: Record<string, never>;
|
|
558
|
+
mobileDownload?: Record<string, never>;
|
|
520
559
|
};
|
|
521
560
|
}
|
|
522
561
|
export interface SaveDownloadRequest {
|
|
@@ -524,7 +563,6 @@ export interface SaveDownloadRequest {
|
|
|
524
563
|
contextSessionId: string;
|
|
525
564
|
saveDownload: {
|
|
526
565
|
downloadId: string;
|
|
527
|
-
path: string;
|
|
528
566
|
retryOptions?: {
|
|
529
567
|
timeoutMs?: number;
|
|
530
568
|
};
|
|
@@ -535,7 +573,48 @@ export interface SetFileChooserFilesRequest {
|
|
|
535
573
|
contextSessionId: string;
|
|
536
574
|
setFileChooserFiles: {
|
|
537
575
|
fileChooserId: string;
|
|
538
|
-
|
|
576
|
+
fileIds: string[];
|
|
577
|
+
retryOptions?: {
|
|
578
|
+
timeoutMs?: number;
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
export interface UploadFileChunkRequest {
|
|
583
|
+
surfaceSessionId: string;
|
|
584
|
+
contextSessionId: string;
|
|
585
|
+
uploadFileChunk: {
|
|
586
|
+
transferId: string;
|
|
587
|
+
name: string;
|
|
588
|
+
offset: string;
|
|
589
|
+
data: Uint8Array;
|
|
590
|
+
last: boolean;
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
export interface ReadFileChunkRequest {
|
|
594
|
+
surfaceSessionId: string;
|
|
595
|
+
contextSessionId: string;
|
|
596
|
+
readFileChunk: {
|
|
597
|
+
fileId: string;
|
|
598
|
+
offset: string;
|
|
599
|
+
maxBytes: number;
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
export interface SetMobileFileChooserFilesRequest {
|
|
603
|
+
surfaceSessionId: string;
|
|
604
|
+
contextSessionId: string;
|
|
605
|
+
setMobileFileChooserFiles: {
|
|
606
|
+
fileChooserId: string;
|
|
607
|
+
fileIds: string[];
|
|
608
|
+
retryOptions?: {
|
|
609
|
+
timeoutMs?: number;
|
|
610
|
+
};
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
export interface SaveMobileDownloadRequest {
|
|
614
|
+
surfaceSessionId: string;
|
|
615
|
+
contextSessionId: string;
|
|
616
|
+
saveMobileDownload: {
|
|
617
|
+
downloadId: string;
|
|
539
618
|
retryOptions?: {
|
|
540
619
|
timeoutMs?: number;
|
|
541
620
|
};
|
|
@@ -730,7 +809,7 @@ export interface CloseContextRequest {
|
|
|
730
809
|
close: Record<string, never>;
|
|
731
810
|
}
|
|
732
811
|
export type SurfaceSessionRequest = LaunchBrowserRequest | LaunchChromeRequest | OpenContextRequest | ConnectMobileRequest | LaunchAppRequest | SurfacePingRequest | CloseSurfaceRequest;
|
|
733
|
-
export type ContextSessionRequest = ContextPingRequest | RegisterHookRequest | WaitForHookRequest | SetFileChooserFilesRequest | SaveDownloadRequest | NavigateRequest | ClickRequest | CountRequest | HighlightRequest | FocusRequest | FillRequest | HoverRequest | PressRequest | TextContentRequest | InnerTextRequest | WaitForSelectorRequest | AccessibilitySnapshotRequest | ScreenshotRequest | CloseContextRequest;
|
|
812
|
+
export type ContextSessionRequest = ContextPingRequest | RegisterHookRequest | WaitForHookRequest | SetFileChooserFilesRequest | SaveDownloadRequest | UploadFileChunkRequest | ReadFileChunkRequest | SetMobileFileChooserFilesRequest | SaveMobileDownloadRequest | NavigateRequest | ClickRequest | CountRequest | HighlightRequest | FocusRequest | FillRequest | HoverRequest | PressRequest | TextContentRequest | InnerTextRequest | WaitForSelectorRequest | AccessibilitySnapshotRequest | ScreenshotRequest | CloseContextRequest;
|
|
734
813
|
export type SurfaceSessionStream = grpc.ClientDuplexStream<SurfaceSessionRequest, SurfaceSessionEvent>;
|
|
735
814
|
export type ContextSessionStream = grpc.ClientDuplexStream<ContextSessionRequest, ContextSessionEvent>;
|
|
736
815
|
export interface EngineServiceClientShape {
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ option java_package = "dev.allwright.engine.v1";
|
|
|
6
6
|
option java_multiple_files = true;
|
|
7
7
|
|
|
8
8
|
import "core/v1/common.proto";
|
|
9
|
+
import "surfaces/mobile/v1/mobile.proto";
|
|
9
10
|
import "surfaces/web/v1/web.proto";
|
|
10
11
|
|
|
11
12
|
message ContextSessionCommand {
|
|
@@ -32,6 +33,10 @@ message ContextSessionCommand {
|
|
|
32
33
|
WaitForHookCommand wait_for_hook = 19;
|
|
33
34
|
SetFileChooserFilesCommand set_file_chooser_files = 20;
|
|
34
35
|
SaveDownloadCommand save_download = 21;
|
|
36
|
+
UploadFileChunkCommand upload_file_chunk = 22;
|
|
37
|
+
ReadFileChunkCommand read_file_chunk = 23;
|
|
38
|
+
SetMobileFileChooserFilesCommand set_mobile_file_chooser_files = 24;
|
|
39
|
+
SaveMobileDownloadCommand save_mobile_download = 25;
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
|
|
@@ -67,6 +72,10 @@ message ContextSessionEvent {
|
|
|
67
72
|
HookCompletedEvent hook_completed = 21;
|
|
68
73
|
FileChooserFilesSetEvent file_chooser_files_set = 22;
|
|
69
74
|
DownloadSavedEvent download_saved = 23;
|
|
75
|
+
FileUploadedEvent file_uploaded = 24;
|
|
76
|
+
FileChunkEvent file_chunk = 25;
|
|
77
|
+
MobileFileChooserFilesSetEvent mobile_file_chooser_files_set = 26;
|
|
78
|
+
MobileDownloadSavedEvent mobile_download_saved = 27;
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -91,6 +100,8 @@ message RegisterHookCommand {
|
|
|
91
100
|
RegisterNewPageHook new_page = 1;
|
|
92
101
|
RegisterFileChooserHook file_chooser = 2;
|
|
93
102
|
RegisterDownloadHook download = 3;
|
|
103
|
+
RegisterMobileFileChooserHook mobile_file_chooser = 4;
|
|
104
|
+
RegisterMobileDownloadHook mobile_download = 5;
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
|
|
@@ -110,9 +121,39 @@ message HookCompletedEvent {
|
|
|
110
121
|
NewPageHookResult new_page = 2;
|
|
111
122
|
FileChooserHookResult file_chooser = 3;
|
|
112
123
|
DownloadHookResult download = 4;
|
|
124
|
+
MobileFileChooserHookResult mobile_file_chooser = 5;
|
|
125
|
+
MobileDownloadHookResult mobile_download = 6;
|
|
113
126
|
}
|
|
114
127
|
}
|
|
115
128
|
|
|
129
|
+
message UploadFileChunkCommand {
|
|
130
|
+
string transfer_id = 1;
|
|
131
|
+
string name = 2;
|
|
132
|
+
uint64 offset = 3;
|
|
133
|
+
bytes data = 4;
|
|
134
|
+
bool last = 5;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
message FileUploadedEvent {
|
|
138
|
+
string transfer_id = 1;
|
|
139
|
+
string file_id = 2;
|
|
140
|
+
string name = 3;
|
|
141
|
+
uint64 size = 4;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
message ReadFileChunkCommand {
|
|
145
|
+
string file_id = 1;
|
|
146
|
+
uint64 offset = 2;
|
|
147
|
+
uint32 max_bytes = 3;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
message FileChunkEvent {
|
|
151
|
+
string file_id = 1;
|
|
152
|
+
uint64 offset = 2;
|
|
153
|
+
bytes data = 3;
|
|
154
|
+
bool last = 4;
|
|
155
|
+
}
|
|
156
|
+
|
|
116
157
|
message NavigatePageCommand {
|
|
117
158
|
string url = 1;
|
|
118
159
|
optional CommandRetryOptions retry_options = 2;
|
|
@@ -56,3 +56,12 @@ message AppLaunchedEvent {
|
|
|
56
56
|
optional string activity_name = 4;
|
|
57
57
|
optional string webview_context = 5;
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
message RegisterMobileFileChooserHook {}
|
|
61
|
+
message MobileFileChooserHookResult { string file_chooser_id = 1; bool is_multiple = 2; string note = 3; }
|
|
62
|
+
message SetMobileFileChooserFilesCommand { string file_chooser_id = 1; repeated string file_ids = 2; optional CommandRetryOptions retry_options = 3; }
|
|
63
|
+
message MobileFileChooserFilesSetEvent { string file_chooser_id = 1; repeated string file_ids = 2; string note = 3; }
|
|
64
|
+
message RegisterMobileDownloadHook {}
|
|
65
|
+
message MobileDownloadHookResult { string download_id = 1; string suggested_filename = 2; string note = 3; }
|
|
66
|
+
message SaveMobileDownloadCommand { string download_id = 1; optional CommandRetryOptions retry_options = 2; }
|
|
67
|
+
message MobileDownloadSavedEvent { string download_id = 1; string file_id = 2; string suggested_filename = 3; uint64 size = 4; string note = 5; }
|
|
@@ -57,13 +57,13 @@ message FileChooserHookResult {
|
|
|
57
57
|
|
|
58
58
|
message SetFileChooserFilesCommand {
|
|
59
59
|
string file_chooser_id = 1;
|
|
60
|
-
repeated string
|
|
60
|
+
repeated string file_ids = 2;
|
|
61
61
|
optional CommandRetryOptions retry_options = 3;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
message FileChooserFilesSetEvent {
|
|
65
65
|
string file_chooser_id = 1;
|
|
66
|
-
repeated string
|
|
66
|
+
repeated string file_ids = 2;
|
|
67
67
|
string note = 3;
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -78,12 +78,13 @@ message DownloadHookResult {
|
|
|
78
78
|
|
|
79
79
|
message SaveDownloadCommand {
|
|
80
80
|
string download_id = 1;
|
|
81
|
-
|
|
82
|
-
optional CommandRetryOptions retry_options = 3;
|
|
81
|
+
optional CommandRetryOptions retry_options = 2;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
message DownloadSavedEvent {
|
|
86
85
|
string download_id = 1;
|
|
87
|
-
string
|
|
88
|
-
string
|
|
86
|
+
string file_id = 2;
|
|
87
|
+
string suggested_filename = 3;
|
|
88
|
+
uint64 size = 4;
|
|
89
|
+
string note = 5;
|
|
89
90
|
}
|