@allwright.dev/core 0.1.3 → 0.1.5
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 +13 -0
- package/dist/bootstrap.js +1 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.js +42 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -0
- package/dist/mobile.js +32 -0
- package/dist/types.d.ts +38 -1
- package/package.json +1 -1
- package/proto/core/v1/common.proto +2 -0
- package/proto/core/v1/context.proto +15 -1
- package/proto/core/v1/surface.proto +29 -0
- package/proto/engine/v1/engine.proto +2 -0
- package/proto/surfaces/mobile/v1/mobile.proto +2 -0
- package/proto/surfaces/web/v1/web.proto +4 -12
package/README.md
CHANGED
|
@@ -20,6 +20,19 @@ await page.click(
|
|
|
20
20
|
await browser.close();
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
Register a typed hook before an action that opens a tab, then wait for its
|
|
24
|
+
typed result afterward:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { firefox, hooks } from "@allwright.dev/core";
|
|
28
|
+
|
|
29
|
+
const browser = await firefox.launch();
|
|
30
|
+
const page = browser.page();
|
|
31
|
+
const hook = await browser.registerHook(hooks.newPage);
|
|
32
|
+
await page.click("a[target=_blank]");
|
|
33
|
+
const newPage = await hook.wait();
|
|
34
|
+
```
|
|
35
|
+
|
|
23
36
|
Runnable examples live in [examples/web-basic.ts](./examples/web-basic.ts) and [examples/android-basic.ts](./examples/android-basic.ts).
|
|
24
37
|
|
|
25
38
|
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.5";
|
|
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/browser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Browser, BrowserInfo, BrowserKind, BrowserLaunchState, BrowserType, CommandOptions, LaunchOptions, Page } from "./types.js";
|
|
1
|
+
import type { Browser, BrowserInfo, BrowserKind, BrowserLaunchState, BrowserType, CommandOptions, Hook, HookType, LaunchOptions, Page } from "./types.js";
|
|
2
2
|
export declare class BrowserTypeImpl implements BrowserType {
|
|
3
3
|
#private;
|
|
4
4
|
constructor(browserKind?: BrowserKind);
|
|
@@ -16,6 +16,7 @@ export declare class BrowserImpl implements Browser {
|
|
|
16
16
|
initialPage(): Page;
|
|
17
17
|
pages(): Page[];
|
|
18
18
|
newPage(options?: CommandOptions): Promise<Page>;
|
|
19
|
+
registerHook<T>(type: HookType<T>): Promise<Hook<T>>;
|
|
19
20
|
close(): Promise<void>;
|
|
20
21
|
ping(message?: string): Promise<string>;
|
|
21
22
|
browserInfo(): BrowserInfo;
|
package/dist/browser.js
CHANGED
|
@@ -66,6 +66,48 @@ export class BrowserImpl {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
async registerHook(type) {
|
|
70
|
+
this.#ensureOpen();
|
|
71
|
+
if (type.name !== "newPage") {
|
|
72
|
+
throw formatActionError("register hook", `unsupported hook type: ${type.name}`);
|
|
73
|
+
}
|
|
74
|
+
this.#stream.write({ registerHook: { newPage: {} } });
|
|
75
|
+
while (true) {
|
|
76
|
+
const event = await this.#queue.next();
|
|
77
|
+
if (event.hookRegistered?.hookId) {
|
|
78
|
+
const hookId = event.hookRegistered.hookId;
|
|
79
|
+
return {
|
|
80
|
+
id: hookId,
|
|
81
|
+
type,
|
|
82
|
+
wait: (options = {}) => this.#waitForHook(hookId, type, options),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (event.error?.message) {
|
|
86
|
+
throw formatActionError(`register ${type.name} hook`, event.error.message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async #waitForHook(hookId, type, options) {
|
|
91
|
+
this.#ensureOpen();
|
|
92
|
+
this.#stream.write({
|
|
93
|
+
waitForHook: {
|
|
94
|
+
hookId,
|
|
95
|
+
retryOptions: options.timeoutMs ? { timeoutMs: options.timeoutMs } : undefined,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
while (true) {
|
|
99
|
+
const event = await this.#queue.next();
|
|
100
|
+
if (event.hookCompleted?.hookId === hookId) {
|
|
101
|
+
if (type.name === "newPage" && event.hookCompleted.newPage?.contextSessionId) {
|
|
102
|
+
return this.#createPage(event.hookCompleted.newPage.contextSessionId);
|
|
103
|
+
}
|
|
104
|
+
throw formatActionError(`wait for ${type.name} hook`, "hook returned an invalid result");
|
|
105
|
+
}
|
|
106
|
+
if (event.error?.message) {
|
|
107
|
+
throw formatActionError(`wait for ${type.name} hook`, event.error.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
69
111
|
async close() {
|
|
70
112
|
if (this.#closed) {
|
|
71
113
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,14 @@ import { findConfigFile, loadConfigFile, resolveConfig } from "./config.js";
|
|
|
3
3
|
import { mobile } from "./mobile.js";
|
|
4
4
|
import { PageImpl } from "./page.js";
|
|
5
5
|
import { setServerAddr, shutdown } from "./runtime.js";
|
|
6
|
-
import type { Browser, BrowserKind, BrowserType, LaunchOptions, Page, ResolveConfigOptions, ResolvedAllwrightConfig } from "./types.js";
|
|
6
|
+
import type { Browser, BrowserKind, BrowserType, LaunchOptions, Page, HookType, ResolveConfigOptions, ResolvedAllwrightConfig } from "./types.js";
|
|
7
7
|
export { findConfigFile, loadConfigFile, resolveConfig, setServerAddr, shutdown };
|
|
8
|
-
export type { AccessibilitySnapshotOptions, AllwrightConfig, Browser, BrowserInfo, BrowserKind, BrowserType, ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, LaunchOptions, MobileAndroidConnectOptions, MobileAndroidDevice, MobileAndroidLaunchOptions, MobileAndroidLocator, MobileAndroidApp, Locator, LocatorInfo, MobileSurfaceNamespace, NavigateResult, Page, PageInfo, PressOptions, PressResult, ResolveConfigOptions, ResolvedAllwrightConfig, RetryConfig, ScreenshotOptions, ScreenshotResult, TextResult, WaitForSelectorOptions, WaitForSelectorResult, } from "./types.js";
|
|
8
|
+
export type { AccessibilitySnapshotOptions, AllwrightConfig, Browser, BrowserInfo, BrowserKind, BrowserType, Hook, HookType, ClickResult, CommandOptions, CountResult, ElementResult, FillResult, HighlightOptions, HighlightResult, LaunchOptions, MobileAndroidConnectOptions, MobileAndroidDevice, MobileAndroidLaunchOptions, MobileAndroidLocator, MobileAndroidApp, Locator, LocatorInfo, MobileSurfaceNamespace, NavigateResult, Page, PageInfo, PressOptions, PressResult, ResolveConfigOptions, ResolvedAllwrightConfig, RetryConfig, ScreenshotOptions, ScreenshotResult, TextResult, WaitForSelectorOptions, WaitForSelectorResult, } from "./types.js";
|
|
9
9
|
export declare const chromium: BrowserType;
|
|
10
10
|
export declare const firefox: BrowserType;
|
|
11
|
+
export declare const hooks: {
|
|
12
|
+
newPage: HookType<Page>;
|
|
13
|
+
};
|
|
11
14
|
export { mobile };
|
|
12
15
|
export type Tab = Page;
|
|
13
16
|
export declare function ping(): Promise<string>;
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ import { createBrowserSessionHandle, getRuntime, launchConfiguredBrowser as laun
|
|
|
7
7
|
export { findConfigFile, loadConfigFile, resolveConfig, setServerAddr, shutdown };
|
|
8
8
|
export const chromium = new BrowserTypeImpl("chromium");
|
|
9
9
|
export const firefox = new BrowserTypeImpl("firefox");
|
|
10
|
+
export const hooks = {
|
|
11
|
+
newPage: Object.freeze({ name: "newPage" }),
|
|
12
|
+
};
|
|
10
13
|
export { mobile };
|
|
11
14
|
export async function ping() {
|
|
12
15
|
return runtimePing();
|
package/dist/mobile.js
CHANGED
|
@@ -200,6 +200,38 @@ class MobileAndroidAppImpl {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
+
async accessibilitySnapshot(options = {}) {
|
|
204
|
+
const mode = options.mode ?? "default";
|
|
205
|
+
if (!["default", "ai", "autoexpect", "codegen"].includes(mode)) {
|
|
206
|
+
throw new Error("invalid accessibility snapshot mode");
|
|
207
|
+
}
|
|
208
|
+
const format = options.format ?? "json";
|
|
209
|
+
if (format !== "json" && format !== "yaml") {
|
|
210
|
+
throw new Error("accessibility snapshot format must be 'json' or 'yaml'");
|
|
211
|
+
}
|
|
212
|
+
const handle = await this.#getHandle();
|
|
213
|
+
this.#ensureOpen(handle);
|
|
214
|
+
handle.stream.write({
|
|
215
|
+
surfaceSessionId: this.#surfaceSessionId,
|
|
216
|
+
contextSessionId: this.sessionId,
|
|
217
|
+
accessibilitySnapshot: {
|
|
218
|
+
format,
|
|
219
|
+
mode,
|
|
220
|
+
retryOptions: options.timeoutMs ? { timeoutMs: options.timeoutMs } : undefined,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
while (true) {
|
|
224
|
+
const event = await handle.queue.next();
|
|
225
|
+
if (event.accessibilitySnapshotCaptured)
|
|
226
|
+
return event.accessibilitySnapshotCaptured.snapshot ?? "";
|
|
227
|
+
if (event.error?.message)
|
|
228
|
+
throw new Error(event.error.message);
|
|
229
|
+
if (event.closed) {
|
|
230
|
+
handle.closed = true;
|
|
231
|
+
throw new Error(`android app session ${this.sessionId} closed while waiting for accessibility snapshot`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
203
235
|
async screenshot(options = {}) {
|
|
204
236
|
const handle = await this.#getHandle();
|
|
205
237
|
this.#ensureOpen(handle);
|
package/dist/types.d.ts
CHANGED
|
@@ -98,6 +98,16 @@ export interface LocatorInfo {
|
|
|
98
98
|
export interface BrowserType {
|
|
99
99
|
launch(options?: LaunchOptions): Promise<Browser>;
|
|
100
100
|
}
|
|
101
|
+
declare const hookOutput: unique symbol;
|
|
102
|
+
export interface HookType<T> {
|
|
103
|
+
readonly name: string;
|
|
104
|
+
readonly [hookOutput]: T;
|
|
105
|
+
}
|
|
106
|
+
export interface Hook<T> {
|
|
107
|
+
readonly id: string;
|
|
108
|
+
readonly type: HookType<T>;
|
|
109
|
+
wait(options?: CommandOptions): Promise<T>;
|
|
110
|
+
}
|
|
101
111
|
export interface Browser extends BrowserInfo {
|
|
102
112
|
page(): Page;
|
|
103
113
|
initialPage(): Page;
|
|
@@ -105,6 +115,7 @@ export interface Browser extends BrowserInfo {
|
|
|
105
115
|
pages(): Page[];
|
|
106
116
|
newPage(options?: CommandOptions): Promise<Page>;
|
|
107
117
|
newTab(options?: CommandOptions): Promise<Page>;
|
|
118
|
+
registerHook<T>(type: HookType<T>): Promise<Hook<T>>;
|
|
108
119
|
close(): Promise<void>;
|
|
109
120
|
ping(message?: string): Promise<string>;
|
|
110
121
|
browserInfo(): BrowserInfo;
|
|
@@ -156,6 +167,7 @@ export interface MobileAndroidLocator {
|
|
|
156
167
|
locator(selector: string): MobileAndroidLocator;
|
|
157
168
|
}
|
|
158
169
|
export interface MobileAndroidApp {
|
|
170
|
+
accessibilitySnapshot(options?: AccessibilitySnapshotOptions): Promise<string>;
|
|
159
171
|
readonly sessionId: string;
|
|
160
172
|
locator(selector: string): MobileAndroidLocator;
|
|
161
173
|
click(selector: string, options?: CommandOptions): Promise<ClickResult>;
|
|
@@ -337,6 +349,18 @@ export interface SurfaceSessionEvent {
|
|
|
337
349
|
contextSessionId?: string;
|
|
338
350
|
note?: string;
|
|
339
351
|
};
|
|
352
|
+
hookRegistered?: {
|
|
353
|
+
hookId?: string;
|
|
354
|
+
hookType?: number;
|
|
355
|
+
};
|
|
356
|
+
hookCompleted?: {
|
|
357
|
+
hookId?: string;
|
|
358
|
+
hookType?: number;
|
|
359
|
+
newPage?: {
|
|
360
|
+
contextSessionId?: string;
|
|
361
|
+
note?: string;
|
|
362
|
+
};
|
|
363
|
+
};
|
|
340
364
|
pong?: {
|
|
341
365
|
message?: string;
|
|
342
366
|
};
|
|
@@ -454,6 +478,19 @@ export interface OpenContextRequest {
|
|
|
454
478
|
};
|
|
455
479
|
};
|
|
456
480
|
}
|
|
481
|
+
export interface RegisterHookRequest {
|
|
482
|
+
registerHook: {
|
|
483
|
+
newPage?: Record<string, never>;
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
export interface WaitForHookRequest {
|
|
487
|
+
waitForHook: {
|
|
488
|
+
hookId: string;
|
|
489
|
+
retryOptions?: {
|
|
490
|
+
timeoutMs?: number;
|
|
491
|
+
};
|
|
492
|
+
};
|
|
493
|
+
}
|
|
457
494
|
export interface ConnectMobileRequest {
|
|
458
495
|
connectMobile: {
|
|
459
496
|
platform: number;
|
|
@@ -632,7 +669,7 @@ export interface CloseContextRequest {
|
|
|
632
669
|
contextSessionId: string;
|
|
633
670
|
close: Record<string, never>;
|
|
634
671
|
}
|
|
635
|
-
export type SurfaceSessionRequest = LaunchBrowserRequest | LaunchChromeRequest | OpenContextRequest | ConnectMobileRequest | LaunchAppRequest | SurfacePingRequest | CloseSurfaceRequest;
|
|
672
|
+
export type SurfaceSessionRequest = LaunchBrowserRequest | LaunchChromeRequest | OpenContextRequest | RegisterHookRequest | WaitForHookRequest | ConnectMobileRequest | LaunchAppRequest | SurfacePingRequest | CloseSurfaceRequest;
|
|
636
673
|
export type ContextSessionRequest = ContextPingRequest | NavigateRequest | ClickRequest | CountRequest | HighlightRequest | FocusRequest | FillRequest | HoverRequest | PressRequest | TextContentRequest | InnerTextRequest | WaitForSelectorRequest | AccessibilitySnapshotRequest | ScreenshotRequest | CloseContextRequest;
|
|
637
674
|
export type SurfaceSessionStream = grpc.ClientDuplexStream<SurfaceSessionRequest, SurfaceSessionEvent>;
|
|
638
675
|
export type ContextSessionStream = grpc.ClientDuplexStream<ContextSessionRequest, ContextSessionEvent>;
|
package/package.json
CHANGED
|
@@ -6,7 +6,6 @@ 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/web/v1/web.proto";
|
|
10
9
|
|
|
11
10
|
message ContextSessionCommand {
|
|
12
11
|
string surface_session_id = 1;
|
|
@@ -218,3 +217,18 @@ message ScreenshotCapturedEvent {
|
|
|
218
217
|
bytes png_data = 1;
|
|
219
218
|
string note = 2;
|
|
220
219
|
}
|
|
220
|
+
|
|
221
|
+
// Empty format defaults to JSON. Accepted values are "json" and "yaml".
|
|
222
|
+
message AccessibilitySnapshotCommand {
|
|
223
|
+
// Empty mode defaults to default. AI assigns queryable references; reference storage is surface-owned.
|
|
224
|
+
// Supported: default, ai, autoexpect, codegen.
|
|
225
|
+
string mode = 3;
|
|
226
|
+
string format = 1;
|
|
227
|
+
optional CommandRetryOptions retry_options = 2;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Both formats encode the same versioned, structured document.
|
|
231
|
+
message AccessibilitySnapshotCapturedEvent {
|
|
232
|
+
string snapshot = 1;
|
|
233
|
+
string format = 2;
|
|
234
|
+
}
|
|
@@ -2,6 +2,8 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package allwright.engine.v1;
|
|
4
4
|
option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
|
|
5
|
+
option java_package = "dev.allwright.engine.v1";
|
|
6
|
+
option java_multiple_files = true;
|
|
5
7
|
|
|
6
8
|
import "core/v1/common.proto";
|
|
7
9
|
import "surfaces/mobile/v1/mobile.proto";
|
|
@@ -16,6 +18,8 @@ message SurfaceSessionCommand {
|
|
|
16
18
|
LaunchBrowserCommand launch_browser = 5;
|
|
17
19
|
ConnectMobileCommand connect_mobile = 6;
|
|
18
20
|
LaunchAppCommand launch_app = 7;
|
|
21
|
+
RegisterHookCommand register_hook = 8;
|
|
22
|
+
WaitForHookCommand wait_for_hook = 9;
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
|
|
@@ -29,6 +33,17 @@ message SessionPingCommand {
|
|
|
29
33
|
|
|
30
34
|
message CloseSurfaceSessionCommand {}
|
|
31
35
|
|
|
36
|
+
message RegisterHookCommand {
|
|
37
|
+
oneof hook {
|
|
38
|
+
RegisterNewPageHook new_page = 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message WaitForHookCommand {
|
|
43
|
+
string hook_id = 1;
|
|
44
|
+
optional CommandRetryOptions retry_options = 2;
|
|
45
|
+
}
|
|
46
|
+
|
|
32
47
|
message SurfaceSessionEvent {
|
|
33
48
|
string session_id = 1;
|
|
34
49
|
|
|
@@ -41,6 +56,8 @@ message SurfaceSessionEvent {
|
|
|
41
56
|
BrowserLaunchedEvent browser_launched = 7;
|
|
42
57
|
MobileConnectedEvent mobile_connected = 8;
|
|
43
58
|
AppLaunchedEvent app_launched = 9;
|
|
59
|
+
HookRegisteredEvent hook_registered = 10;
|
|
60
|
+
HookCompletedEvent hook_completed = 11;
|
|
44
61
|
}
|
|
45
62
|
}
|
|
46
63
|
|
|
@@ -60,3 +77,15 @@ message SurfaceSessionClosedEvent {
|
|
|
60
77
|
message SurfaceSessionErrorEvent {
|
|
61
78
|
string message = 1;
|
|
62
79
|
}
|
|
80
|
+
|
|
81
|
+
message HookRegisteredEvent {
|
|
82
|
+
string hook_id = 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
message HookCompletedEvent {
|
|
86
|
+
string hook_id = 1;
|
|
87
|
+
|
|
88
|
+
oneof result {
|
|
89
|
+
NewPageHookResult new_page = 2;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -2,6 +2,8 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package allwright.engine.v1;
|
|
4
4
|
option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
|
|
5
|
+
option java_package = "dev.allwright.engine.v1";
|
|
6
|
+
option java_multiple_files = true;
|
|
5
7
|
|
|
6
8
|
import "core/v1/surface.proto";
|
|
7
9
|
import "core/v1/common.proto";
|
|
@@ -40,17 +40,9 @@ message ChromeLaunchedEvent {
|
|
|
40
40
|
string initial_page_session_id = 5;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
message AccessibilitySnapshotCommand {
|
|
45
|
-
// Empty mode defaults to default. AI injects queryable aria-ref attributes.
|
|
46
|
-
// Supported: default, ai, autoexpect, codegen.
|
|
47
|
-
string mode = 3;
|
|
48
|
-
string format = 1;
|
|
49
|
-
optional CommandRetryOptions retry_options = 2;
|
|
50
|
-
}
|
|
43
|
+
message RegisterNewPageHook {}
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
string
|
|
55
|
-
string format = 2;
|
|
45
|
+
message NewPageHookResult {
|
|
46
|
+
string context_session_id = 1;
|
|
47
|
+
string note = 2;
|
|
56
48
|
}
|