@farmslot/adapter-web 0.9.2 → 0.10.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/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ All notable changes to `@farmslot/adapter-web` are tracked here.
6
6
 
7
7
  - Active-development baseline; add user-facing changes here before release or package publication.
8
8
 
9
+ ## 0.10.1 - 2026-10-15
10
+
11
+ - Align the installed dependency closure with protocol 0.45.0 and retained-run stack attachment.
12
+
13
+ ## 0.10.0 - 2026-10-15
14
+
15
+ - Include browser chrome and extension side panels in unrecorded web-dapp screenshots through the owned browser's native capture, with CDP fallback.
16
+
9
17
  ## 0.9.2 - 2026-10-15
10
18
 
11
19
  - Align the installed worker dependency closure with protocol 0.44.0 and provenance-bound branch maintenance.
package/README.md CHANGED
@@ -117,6 +117,7 @@ const binding = createWalletRequestBinding({
117
117
  - **Locked session.** A headful launch refuses while the macOS login session is locked (`SESSION_LOCKED`), before starting, reusing or stopping a browser: macOS stops painting visible windows, so screenshots, video and UI actions would stall. `macosSessionLocked()` reads `ioreg` (3 s bound; `null` off macOS or when unknown). A headless launch never probes.
118
118
  - **Signers.** `signer=injected` needs nothing. `signer=extension` belongs to the host: a signer module exports `signers.extension` with `prepareProfile` (load the extension, seed the profile; returns `{ browserArgs, secrets, state }` and may carry an `afterBrowserStart` step; both steps get `trackSecret` for key-material files), `confirm` (required with `prepareProfile`: without it the wallet host would close the wallet's own windows) and `readinessChecks`. `signers.injected.identity` sets the EIP-6963 identity the injected strict wallet presents. The module path (`signerModule`, `--signer-module` or `RECIPE_WEB_DAPP_SIGNER_MODULE`) is the one source: readiness, launch, verify and the wallet host all load it, and `createWebDappAdapter` throws if given an in-process `signers` object. With no signer requested, the signer is `extension` when a module is configured and `injected` otherwise, so a host whose module exports only `injected` sets the signer explicitly (`--signer injected` or `TERMINAL_SIGNER=injected`).
119
119
  - **Hooks.** The action set, console capture, and network and performance observation are the host's; pass them as `hooks`. `diagnostics`, `readiness` and `harness` merge over the generic members.
120
+ - **Screenshots.** Unrecorded `ui.screenshot` captures the owned browser window through capture-helper, including browser chrome and extension side panels. The host's CDP transport remains the fallback, with `captureProvider`, `fallbackFrom` and `fallbackReason` in artifact metadata. Recorded screenshots use their recording session; full-page requests and `ui.capture_surface` use CDP. The native path reuses the recording target's browser identity checks and the runner's rooted artifact writer.
120
121
  - **Leaves.** `webDappLeafPath('launch' | 'wallet-host' | 'inject' | 'verify' | 'stop' | 'cleanup')` names the CLI scripts.
121
122
  - **Test fixture.** `test/fixtures/web-dapp-test-plugin` is a `test-dapp` adapter for MetaMask's test-dapp-multichain. That dapp needs `signer=extension` with a host signer module: it talks to the wallet through the Multichain API, which the injected EIP-1193 strict wallet cannot drive.
122
123
  - **Kept for compatibility.** These generic-code names still carry the host's old product name, because renaming them needs both sides to change together: the `TERMINAL_*` environment names (`TERMINAL_CHROME_BIN`, `TERMINAL_APP_PORT`, `TERMINAL_SIGNER`, `TERMINAL_ACCOUNT`, `TERMINAL_HEADLESS`, `TERMINAL_SLOW_MO`, `TERMINAL_WINDOW`, `TERMINAL_SCREEN`); `MM_HARNESS_SERVED_TIMEOUT_MS`, `MM_HARNESS_APP_COMMIT_TIMEOUT_MS` and `MM_HARNESS_FOCUS_SETTLE_MS`; the `--mm-harness-owner` process marker (process ownership is matched on argv); the `mm-harness-probe=1` probe marker; and the `mm-harness-hud` overlay element.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @param {import('@farmslot/adapter-sdk').AdapterActions} actions
3
+ * @param {import('@farmslot/adapter-sdk').AdapterRecording} recording
4
+ * @returns {import('@farmslot/adapter-sdk').AdapterActions}
5
+ */
6
+ export function browserWindowScreenshots(actions: import("@farmslot/adapter-sdk").AdapterActions, recording: import("@farmslot/adapter-sdk").AdapterRecording): import("@farmslot/adapter-sdk").AdapterActions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/adapter-web",
3
- "version": "0.9.2",
3
+ "version": "0.10.1",
4
4
  "description": "Web platform adapter for Farmslot recipes: resolve and launch an isolated Chromium, own its CDP port, load unpacked extensions, and keep macOS focus.",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -83,9 +83,9 @@
83
83
  "prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/adapter-web"
84
84
  },
85
85
  "dependencies": {
86
- "@farmslot/adapter-sdk": "0.13.2",
87
- "@farmslot/protocol": "0.44.0",
88
- "@farmslot/recipe-runner": "0.34.3",
86
+ "@farmslot/adapter-sdk": "0.14.0",
87
+ "@farmslot/protocol": "0.45.0",
88
+ "@farmslot/recipe-runner": "0.36.0",
89
89
  "ws": "^8.18.0"
90
90
  },
91
91
  "devDependencies": {
@@ -20,6 +20,7 @@ import { POLICY_ENV, webDappAdapterId, webDappPolicy } from './lib/policy.mjs';
20
20
  import { cdpListenerPids, ownsProcess } from './lib/processes.mjs';
21
21
  import { check, webDappReadiness } from './lib/readiness.mjs';
22
22
  import { cdpPort, readBrowserState, webDappRuntimeDir } from './lib/runtime.mjs';
23
+ import { browserWindowScreenshots } from './lib/screenshots.mjs';
23
24
  import { defaultSigner, loadSigners, SIGNER_MODULE_ENV } from './lib/signers.mjs';
24
25
  import { resolveBrowser } from './launch.mjs';
25
26
 
@@ -332,30 +333,33 @@ export function createWebDappAdapter(factoryOptions = {}) {
332
333
  restart: `${cli} launch`,
333
334
  };
334
335
 
336
+ /** @type {import('@farmslot/adapter-sdk').AdapterRecording} */
337
+ const recording = rest.recording ?? {
338
+ async target(context) {
339
+ const port = cdpPort(context, context.env);
340
+ const state = await readBrowserState(context.projectRoot);
341
+ const pid = state?.browserPid;
342
+ if (
343
+ !Number.isInteger(pid) ||
344
+ pid <= 0 ||
345
+ state.cdpPort !== port ||
346
+ !ownsProcess('browser', pid, webDappRuntimeDir(context.projectRoot)) ||
347
+ !cdpListenerPids(port).includes(pid)
348
+ ) {
349
+ throw new Error(
350
+ `Could not resolve the owned ${webDappAdapterId()} browser for recording on CDP ${port}. Next: launch and verify the selected slot browser.`,
351
+ );
352
+ }
353
+ return { kind: 'pid', pid };
354
+ },
355
+ };
356
+
335
357
  return {
336
358
  id,
337
359
  sdkVersion: 1,
338
360
  headless: false,
339
361
 
340
- recording: {
341
- async target(context) {
342
- const port = cdpPort(context, context.env);
343
- const state = await readBrowserState(context.projectRoot);
344
- const pid = state?.browserPid;
345
- if (
346
- !Number.isInteger(pid) ||
347
- pid <= 0 ||
348
- state.cdpPort !== port ||
349
- !ownsProcess('browser', pid, webDappRuntimeDir(context.projectRoot)) ||
350
- !cdpListenerPids(port).includes(pid)
351
- ) {
352
- throw new Error(
353
- `Could not resolve the owned ${webDappAdapterId()} browser for recording on CDP ${port}. Next: launch and verify the selected slot browser.`,
354
- );
355
- }
356
- return { kind: 'pid', pid };
357
- },
358
- },
362
+ recording,
359
363
 
360
364
  resolveSlotPorts() {
361
365
  // Ports come from the slot (Farmslot {{port}} / {{cdp_port}}) through
@@ -535,15 +539,18 @@ export function createWebDappAdapter(factoryOptions = {}) {
535
539
 
536
540
  // The web-dapp ships no action manifest: the host supplies its action set
537
541
  // (`hooks.actions`).
538
- actions: actions ?? {
539
- manifestPath() {
540
- throw new Error(
541
- `${id} ships no action manifest: pass hooks.actions to createWebDappAdapter.`,
542
- );
542
+ actions: browserWindowScreenshots(
543
+ actions ?? {
544
+ manifestPath() {
545
+ throw new Error(
546
+ `${id} ships no action manifest: pass hooks.actions to createWebDappAdapter.`,
547
+ );
548
+ },
549
+ semantic: [],
550
+ cdpTarget: { transport: 'chrome-cdp', probePath: 'json/version' },
543
551
  },
544
- semantic: [],
545
- cdpTarget: { transport: 'chrome-cdp', probePath: 'json/version' },
546
- },
552
+ recording,
553
+ ),
547
554
 
548
555
  // Built-in bridges inherit verification, without overlay installer leaves.
549
556
  harness:
@@ -606,8 +613,8 @@ export function createWebDappAdapter(factoryOptions = {}) {
606
613
  message: item.detail,
607
614
  }));
608
615
  },
609
- // Screenshots come from the slot browser over CDP.
610
- captureProviders: ['cdp'],
616
+ // Native window capture includes browser chrome and extension side panels.
617
+ captureProviders: ['capture-helper', 'cdp'],
611
618
  ...readiness,
612
619
  },
613
620
 
@@ -0,0 +1,35 @@
1
+ // Keep the host's page/action bindings while preferring the owned browser window.
2
+ import { captureHelperSnapshot } from '@farmslot/recipe-runner';
3
+
4
+ /**
5
+ * @param {import('@farmslot/adapter-sdk').AdapterActions} actions
6
+ * @param {import('@farmslot/adapter-sdk').AdapterRecording} recording
7
+ * @returns {import('@farmslot/adapter-sdk').AdapterActions}
8
+ */
9
+ export function browserWindowScreenshots(actions, recording) {
10
+ const ui = actions.ui;
11
+ if (!ui) return actions;
12
+ return {
13
+ ...actions,
14
+ ui(harness, options) {
15
+ return ui.call(
16
+ actions,
17
+ {
18
+ ...harness,
19
+ createCdpWebUiTransport(config) {
20
+ return harness.createCdpWebUiTransport({
21
+ ...config,
22
+ screenshotProvider: {
23
+ name: 'capture-helper',
24
+ async capture({ context }) {
25
+ return captureHelperSnapshot(await recording.target(context));
26
+ },
27
+ },
28
+ });
29
+ },
30
+ },
31
+ options,
32
+ );
33
+ },
34
+ };
35
+ }