Skip to content

feat: implement canonical page API minimum surface (Phase 4)#102

Open
tnunamak wants to merge 2 commits intomainfrom
feat/connector-contract-unification
Open

feat: implement canonical page API minimum surface (Phase 4)#102
tnunamak wants to merge 2 commits intomainfrom
feat/connector-contract-unification

Conversation

@tnunamak
Copy link
Copy Markdown
Member

@tnunamak tnunamak commented Apr 10, 2026

Summary

Part of the multi-repo connector contract unification plan. See vana-com/data-connectors contract freeze doc for the full background.

Paired PRs:

Changes

  • playwright-runner/index.cjs: implement url(), click(), fill(), press(), waitForSelector() as pass-throughs to the underlying Playwright page object. These were declared as undefined before; the canonical contract now requires them.
  • src-tauri/src/commands/connector.rs: extend ConnectorMetadata with the canonical manifest fields — manifest_version, connector_id (aliased from legacy id), source_id, page_api_version, runtime_requirements, capabilities. Canonical connect_url, connect_selector, and icon now accept both the snake_case and legacy camelCase forms via serde(alias).

No observable behavior change beyond parsing richer manifests. Code that referenced metadata.id now reads metadata.connector_id, backed by the serde alias so both old and new manifests deserialize correctly.

Note on iCloud Notes

The iCloud Notes connector in data-connectors#59 advertises the cg-legacy-page-api capability because its script depends on CG-runtime-only page methods (getInput, frame_click/fill/evaluate/waitForSelector, keyboard_press/type) that are not part of the canonical minimum surface. It is already invisible to this runtime via two independent mechanisms:

  1. It is not listed in src/lib/platform/registry.ts (PLATFORM_REGISTRY), which is the hand-maintained frontend catalog that drives the connect list in data-connect.
  2. It is not listed in the bundled connectors/registry.json, which is the connector manifest allowlist.

No explicit disable code is required in this PR. A belt-and-suspenders follow-up would be to have playwright-runner/index.cjs load the manifest JSON alongside the script and reject any connector whose capabilities array contains cg-legacy-page-api, but that is deferred as Phase 4+ hardening — the runner currently loads only the .js, not the metadata.

Test plan

  • cargo check — clean
  • Paired with data-connectors#59 + context-gateway#95 smoke tests: the canonical minimum surface is exercised end-to-end via CG's client-side runtime (which mirrors this runtime's shape), successfully running GitHub, Instagram, and iCloud Notes canonical scripts against real credentials (see context-gateway#95 PR body for evidence).
  • Manual: run a connector (chatgpt/instagram/etc.) through the actual playwright-runner/index.cjs in data-connect and confirm no regression
  • Manual: run the conformance fixture from feat: normalize manifest + page API contracts (Phase 0 + 4) data-connectors#59 against this runtime and verify every minimum-surface method returns present: true, ok: true
  • Manual: package build + smoke test (macOS)

Phase 4 of the connector contract unification plan:

- playwright-runner/index.cjs: add url(), click(), fill(), press(),
  waitForSelector() as pass-throughs to the underlying Playwright
  page object. These were previously declared but undefined; the
  canonical page API in data-connectors types/connector.d.ts now
  requires them.

- src-tauri/src/commands/connector.rs: add canonical manifest fields
  to the ConnectorMetadata struct — manifest_version, connector_id
  (aliased from legacy `id`), source_id, page_api_version,
  runtime_requirements, capabilities. Canonical connect_url,
  connect_selector, and icon now accept both the canonical snake_case
  and the legacy camelCase form via serde(alias).

No behavior change beyond deserializing richer manifests. The Rust
code that referenced metadata.id now reads metadata.connector_id
(backed by the serde alias so old manifests still parse).
The regex used to prepend `return` to the top-level IIFE required a
leading `\n`, so any canonical connector whose IIFE is on line 1 (e.g.
steam-playwright.js starts with `(async () => {` directly) would fail to
match. The AsyncFunction then resolved to `undefined` immediately while
the script ran fire-and-forget, and the runner reported success with no
data.

Use `(?:^|\n)` and track whether the match started with a newline so
the replacement preserves the original line structure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant