@webhands/core 0.5.0 → 0.6.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.
- package/README.md +20 -4
- package/dist/errors.d.ts +92 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +100 -0
- package/dist/errors.js.map +1 -1
- package/dist/hand-host.d.ts +198 -5
- package/dist/hand-host.d.ts.map +1 -1
- package/dist/hand-host.js +664 -21
- package/dist/hand-host.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/playwright-attach-transport.d.ts +8 -1
- package/dist/playwright-attach-transport.d.ts.map +1 -1
- package/dist/playwright-attach-transport.js +19 -4
- package/dist/playwright-attach-transport.js.map +1 -1
- package/dist/playwright-launch-transport.d.ts.map +1 -1
- package/dist/playwright-launch-transport.js +13 -4
- package/dist/playwright-launch-transport.js.map +1 -1
- package/dist/profile-location.d.ts +19 -0
- package/dist/profile-location.d.ts.map +1 -1
- package/dist/profile-location.js +21 -0
- package/dist/profile-location.js.map +1 -1
- package/dist/seam.d.ts +501 -7
- package/dist/seam.d.ts.map +1 -1
- package/dist/seam.js +31 -0
- package/dist/seam.js.map +1 -1
- package/dist/session-rpc.d.ts +63 -1
- package/dist/session-rpc.d.ts.map +1 -1
- package/dist/session-rpc.js +174 -11
- package/dist/session-rpc.js.map +1 -1
- package/dist/stub-transport.d.ts.map +1 -1
- package/dist/stub-transport.js +74 -6
- package/dist/stub-transport.js.map +1 -1
- package/dist/test-fixtures/fixture-pages.d.ts.map +1 -1
- package/dist/test-fixtures/fixture-pages.js +994 -0
- package/dist/test-fixtures/fixture-pages.js.map +1 -1
- package/dist/test-fixtures/fixture-server.d.ts.map +1 -1
- package/dist/test-fixtures/fixture-server.js +33 -3
- package/dist/test-fixtures/fixture-server.js.map +1 -1
- package/package.json +1 -1
- package/src/errors.ts +134 -1
- package/src/hand-host.ts +797 -21
- package/src/index.ts +20 -1
- package/src/playwright-attach-transport.ts +25 -3
- package/src/playwright-launch-transport.ts +13 -2
- package/src/profile-location.ts +25 -0
- package/src/seam.ts +535 -7
- package/src/session-rpc.ts +276 -14
- package/src/stub-transport.ts +83 -6
- package/src/test-fixtures/fixture-pages.ts +1010 -0
- package/src/test-fixtures/fixture-server.ts +32 -3
package/src/index.ts
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
export type {
|
|
2
|
+
ActionOptions,
|
|
3
|
+
BoundingBox,
|
|
2
4
|
Cookie,
|
|
3
5
|
Driver,
|
|
6
|
+
EvalOptions,
|
|
4
7
|
LocatorString,
|
|
8
|
+
MouseAction,
|
|
9
|
+
MouseButton,
|
|
10
|
+
MouseInput,
|
|
5
11
|
OpenTarget,
|
|
12
|
+
PwExtra,
|
|
13
|
+
QueryOptions,
|
|
14
|
+
QueryRow,
|
|
15
|
+
Screenshot,
|
|
16
|
+
ScreenshotOptions,
|
|
17
|
+
ScreenshotScope,
|
|
18
|
+
ScrollTarget,
|
|
19
|
+
SelectChoice,
|
|
6
20
|
WebHandsPage,
|
|
7
21
|
Session,
|
|
8
22
|
Snapshot,
|
|
@@ -11,7 +25,7 @@ export type {
|
|
|
11
25
|
Transport,
|
|
12
26
|
WaitCondition,
|
|
13
27
|
} from './seam.js';
|
|
14
|
-
export {locator} from './seam.js';
|
|
28
|
+
export {locator, validateSnapshotOptions} from './seam.js';
|
|
15
29
|
|
|
16
30
|
export {
|
|
17
31
|
serializeCookies,
|
|
@@ -68,6 +82,9 @@ export {
|
|
|
68
82
|
AttachNoContextError,
|
|
69
83
|
NoLiveServerError,
|
|
70
84
|
SessionAlreadyActiveError,
|
|
85
|
+
CrossOriginFrameError,
|
|
86
|
+
ScreenshotPathError,
|
|
87
|
+
StaleRefError,
|
|
71
88
|
isControllerError,
|
|
72
89
|
type ControllerErrorCode,
|
|
73
90
|
} from './errors.js';
|
|
@@ -104,9 +121,11 @@ export {
|
|
|
104
121
|
export {
|
|
105
122
|
resolveHomeRoot,
|
|
106
123
|
resolveProfileLocation,
|
|
124
|
+
resolveScreenshotsDir,
|
|
107
125
|
CONTROLLER_HOME_ENV,
|
|
108
126
|
DEFAULT_HOME_DIRNAME,
|
|
109
127
|
PROFILES_DIRNAME,
|
|
128
|
+
SCREENSHOTS_DIRNAME,
|
|
110
129
|
type ProfileLocation,
|
|
111
130
|
type ProfileLocationOptions,
|
|
112
131
|
} from './profile-location.js';
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
} from 'playwright';
|
|
7
7
|
import {AttachNoContextError, AttachNotChromiumError} from './errors.js';
|
|
8
8
|
import {composeWithHands, type Hand, type HandContext} from './hand-host.js';
|
|
9
|
+
import {
|
|
10
|
+
resolveScreenshotsDir,
|
|
11
|
+
type ProfileLocationOptions,
|
|
12
|
+
} from './profile-location.js';
|
|
9
13
|
import type {OpenTarget, Session, Transport} from './seam.js';
|
|
10
14
|
|
|
11
15
|
/**
|
|
@@ -33,15 +37,26 @@ import type {OpenTarget, Session, Transport} from './seam.js';
|
|
|
33
37
|
*/
|
|
34
38
|
export class PlaywrightAttachTransport implements Transport {
|
|
35
39
|
readonly #hands: readonly Hand[];
|
|
40
|
+
readonly #location: ProfileLocationOptions;
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
43
|
* @param hands explicitly-loaded third-party hands to compose alongside the
|
|
39
44
|
* built-ins (Phase 2, ADR-0007). These come from {@link loadHands} against
|
|
40
45
|
* the operator's explicit config; the transport does NOT discover them. Omit
|
|
41
46
|
* for the built-ins-only surface.
|
|
47
|
+
* @param location overrides for the controller home root, used ONLY to resolve
|
|
48
|
+
* the managed SCREENSHOTS dir (`<homeRoot>/screenshots`) the Tier-4
|
|
49
|
+
* `screenshot` verb mints under — attach reuses the user's own browser, so it
|
|
50
|
+
* owns no profile dir, but the screenshot output location still honours the
|
|
51
|
+
* same `root`/`WEBHANDS_HOME` override so a test can isolate it. Omit in
|
|
52
|
+
* production to use `~/.webhands/screenshots`.
|
|
42
53
|
*/
|
|
43
|
-
constructor(
|
|
54
|
+
constructor(
|
|
55
|
+
hands: readonly Hand[] = [],
|
|
56
|
+
location: ProfileLocationOptions = {},
|
|
57
|
+
) {
|
|
44
58
|
this.#hands = hands;
|
|
59
|
+
this.#location = location;
|
|
45
60
|
}
|
|
46
61
|
|
|
47
62
|
async open(target: OpenTarget): Promise<Session> {
|
|
@@ -77,7 +92,8 @@ export class PlaywrightAttachTransport implements Transport {
|
|
|
77
92
|
// browser exposes a context with no page yet (single active session in
|
|
78
93
|
// v1, PRD Out of Scope).
|
|
79
94
|
const pwPage = context.pages()[0] ?? (await context.newPage());
|
|
80
|
-
|
|
95
|
+
const screenshotsDir = resolveScreenshotsDir(this.#location);
|
|
96
|
+
return makeAttachedSession(browser, pwPage, this.#hands, screenshotsDir);
|
|
81
97
|
} catch (cause) {
|
|
82
98
|
// On any open-time refusal, disconnect from the user's browser without
|
|
83
99
|
// closing it (a CDP connection close detaches; it does not kill the
|
|
@@ -107,6 +123,7 @@ function makeAttachedSession(
|
|
|
107
123
|
browser: Browser,
|
|
108
124
|
pwPage: Page,
|
|
109
125
|
extraHands: readonly Hand[],
|
|
126
|
+
screenshotsDir: string,
|
|
110
127
|
): Session {
|
|
111
128
|
const context: BrowserContext = pwPage.context();
|
|
112
129
|
let closed = false;
|
|
@@ -134,7 +151,12 @@ function makeAttachedSession(
|
|
|
134
151
|
// the same shared host the launch transport uses, so the verbs behave
|
|
135
152
|
// identically across both transports. The live `pwPage`/`context` stay
|
|
136
153
|
// in-process and never cross the seam (ADR-0003).
|
|
137
|
-
const handContext: HandContext = {
|
|
154
|
+
const handContext: HandContext = {
|
|
155
|
+
pwPage,
|
|
156
|
+
context,
|
|
157
|
+
ensureOpen,
|
|
158
|
+
screenshotsDir,
|
|
159
|
+
};
|
|
138
160
|
const {page, dispose: disposeHands} = composeWithHands(
|
|
139
161
|
handContext,
|
|
140
162
|
extraHands,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import {composeWithHands, type Hand, type HandContext} from './hand-host.js';
|
|
9
9
|
import {
|
|
10
10
|
resolveProfileLocation,
|
|
11
|
+
resolveScreenshotsDir,
|
|
11
12
|
type ProfileLocationOptions,
|
|
12
13
|
} from './profile-location.js';
|
|
13
14
|
import {hostResolverRulesArg, parseSocksProxy} from './socks-proxy.js';
|
|
@@ -346,7 +347,11 @@ export class PlaywrightLaunchTransport implements Transport {
|
|
|
346
347
|
// the single active page (PRD: single active session in v1). Create one if
|
|
347
348
|
// the build ever changes that invariant.
|
|
348
349
|
const pwPage = context.pages()[0] ?? (await context.newPage());
|
|
349
|
-
|
|
350
|
+
// The managed screenshots dir resolves from the SAME location override as
|
|
351
|
+
// profiles (`<homeRoot>/screenshots`), so a test's temp `root` isolates
|
|
352
|
+
// screenshots too and the real `~/.webhands/screenshots` stays untouched.
|
|
353
|
+
const screenshotsDir = resolveScreenshotsDir(this.#location);
|
|
354
|
+
return makeSession(context, pwPage, this.#hands, screenshotsDir);
|
|
350
355
|
}
|
|
351
356
|
|
|
352
357
|
/**
|
|
@@ -427,6 +432,7 @@ function makeSession(
|
|
|
427
432
|
context: BrowserContext,
|
|
428
433
|
pwPage: Page,
|
|
429
434
|
extraHands: readonly Hand[],
|
|
435
|
+
screenshotsDir: string,
|
|
430
436
|
): Session {
|
|
431
437
|
let closed = false;
|
|
432
438
|
const ensureOpen = () => {
|
|
@@ -453,7 +459,12 @@ function makeSession(
|
|
|
453
459
|
// Build the verb surface from the built-in hands over a live hand-context.
|
|
454
460
|
// The host keeps the live `pwPage`/`context` in-process (they never cross the
|
|
455
461
|
// seam, ADR-0003); the hand-context carries live page access only.
|
|
456
|
-
const handContext: HandContext = {
|
|
462
|
+
const handContext: HandContext = {
|
|
463
|
+
pwPage,
|
|
464
|
+
context,
|
|
465
|
+
ensureOpen,
|
|
466
|
+
screenshotsDir,
|
|
467
|
+
};
|
|
457
468
|
const {page, dispose: disposeHands} = composeWithHands(
|
|
458
469
|
handContext,
|
|
459
470
|
extraHands,
|
package/src/profile-location.ts
CHANGED
|
@@ -30,6 +30,16 @@ export const CONTROLLER_HOME_ENV = 'WEBHANDS_HOME';
|
|
|
30
30
|
/** The subdirectory under the home root that holds dedicated profiles. */
|
|
31
31
|
export const PROFILES_DIRNAME = 'profiles';
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* The subdirectory under the home root where the `screenshot` verb MINTS its
|
|
35
|
+
* PNG files (the Tier-4 managed screenshots dir, prd
|
|
36
|
+
* `broaden-agent-verb-surface`, R3). It lives BESIDE `profiles/` under the SAME
|
|
37
|
+
* overridable home root, so the same `root`/`WEBHANDS_HOME` override that
|
|
38
|
+
* isolates profiles in a test also isolates screenshots — nothing writes to the
|
|
39
|
+
* real `~/.webhands/screenshots` unless the home root points there.
|
|
40
|
+
*/
|
|
41
|
+
export const SCREENSHOTS_DIRNAME = 'screenshots';
|
|
42
|
+
|
|
33
43
|
/** Inputs that influence where a profile resolves (all optional, for tests). */
|
|
34
44
|
export interface ProfileLocationOptions {
|
|
35
45
|
/**
|
|
@@ -90,3 +100,18 @@ export function resolveProfileLocation(
|
|
|
90
100
|
profile,
|
|
91
101
|
};
|
|
92
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resolve the managed SCREENSHOTS directory (`<homeRoot>/screenshots`) the
|
|
106
|
+
* `screenshot` verb mints PNGs under (prd `broaden-agent-verb-surface`, R3).
|
|
107
|
+
* Like {@link resolveProfileLocation} it is PURE (creates no directory) and
|
|
108
|
+
* honours the same `root`/`WEBHANDS_HOME` precedence, so a test that points the
|
|
109
|
+
* home root at a temp dir isolates screenshots there and the real
|
|
110
|
+
* `~/.webhands/screenshots` stays untouched. The verb (in the transport) is
|
|
111
|
+
* responsible for creating the dir lazily on first write.
|
|
112
|
+
*/
|
|
113
|
+
export function resolveScreenshotsDir(
|
|
114
|
+
options: ProfileLocationOptions = {},
|
|
115
|
+
): string {
|
|
116
|
+
return join(resolveHomeRoot(options), SCREENSHOTS_DIRNAME);
|
|
117
|
+
}
|