Skip to content

feat(api): add OpenConnector for the self-hosted runtime#5

Merged
BlackHole1 merged 2 commits into
mainfrom
feat/open-connector
Jul 2, 2026
Merged

feat(api): add OpenConnector for the self-hosted runtime#5
BlackHole1 merged 2 commits into
mainfrom
feat/open-connector

Conversation

@BlackHole1

Copy link
Copy Markdown
Member

The Connector backend now ships as an open-source, self-hostable server that mirrors the personal product — one user, one server, running actions on their own connections. This adds its client, OpenConnector: the third client class next to Connector (hosted personal) and ProjectConnector (hosted project), covering the same personal surface against a server you run — both call paths (open.execute(...) and the open.gmail.search_threads({...}) namespace sugar), catalog / apps introspection, plus the runtime's own extras (health, catalog.search / .services, apps.listByService / .authenticated).

The surface is deliberately personal-only. Connection, credential, OAuth-config, and runtime-token management belong to the runtime's web console — server administration, not SDK territory — so none of that (nor an admin token) appears here. Auth is a single optional runtime token (oct_…): a fresh instance answers without one, and the client sends no Authorization header rather than an empty bearer when unset.

Two supporting changes make the existing machinery serve both clients:

  • registry.ts's namespace types (ServiceNamespaces / LooseNamespace / ActionsOf) are now generic over the per-call options type, defaulting to CallOptions so the hosted Connector's published types are byte-for-byte unchanged. OpenConnector instantiates them with its narrower OpenExecuteOptions, so the hosted-only organization option is rejected at compile time on the open client while connectionName / signal / timeoutMs / retries work as usual.
  • http.ts's parseBody now understands the runtime's non-envelope answers: a bare 2xx JSON body is normalized into { success: true, data }, and the middleware's { error: { code, message } } failure shape — which the server emits even on /v1 routes (e.g. its 401) — maps onto the envelope's error fields, so ConnectorError.code / .message stay faithful across both backends.

The action metadata returned by this runtime also gets its own OpenActionMetadata type: on the wire followUpActions are { actionId } wrappers (not the string[] the shared ActionMetadata claims), and asyncLifecycle is an explicit null when absent.

Verified end to end: 173 unit tests (coverage 99% statements / 96% branches), tsd acceptance in all three registry states — including against the published @oomol-lab/connector-types@0.1.4 in both NodeNext and bundler resolutions — and live checks against a real server instance (catalog, execute, auth enforcement transitions, namespace calls, error mapping for both envelope styles).

The Connector backend now ships as an open-source, self-hostable
server that mirrors the PERSONAL product: one user running actions on
their own connections. OpenConnector is its client — the same two
call paths (`execute` and `open.<service>.<action>` namespace sugar),
`catalog` and `apps` introspection, plus the runtime's own extras
(`health`, `catalog.search` / `.services`, `apps.listByService` /
`.authenticated`).

The surface is deliberately personal-only: connection, credential,
OAuth-config, and token management belong to the runtime's web
console, so none of that (nor an admin token) appears at the SDK
layer. Auth is a single optional runtime token (`oct_…`) — a fresh
instance answers without one.

To keep both clients precise on path 2, the registry namespace types
(`ServiceNamespaces` / `LooseNamespace` / `ActionsOf`) are now generic
over the per-call options type (default `CallOptions`, so the hosted
`Connector` is unchanged); `OpenConnector` passes its narrower
`OpenExecuteOptions`, which rejects the hosted-only `organization`.
The transport also learns the runtime's non-envelope answers: bare
2xx JSON becomes `{ success, data }` and the middleware's
`{ error: { code, message } }` failures (sent even on `/v1` routes,
e.g. 401) map onto the envelope error fields.

Verified end to end: 173 unit tests, tsd acceptance in all three
registry states against the published `@oomol-lab/connector-types`,
and live checks (catalog, execute, auth enforcement, namespace calls)
against a real server instance.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 202395ad-10f2-4d3c-9c7a-fba84ac812d5

📥 Commits

Reviewing files that changed from the base of the PR and between fa2a3fe and 7b17833.

📒 Files selected for processing (2)
  • src/open.ts
  • test/open.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/open.test.ts
  • src/open.ts

Summary by CodeRabbit

  • New Features
    • Added a self-hosted runtime client with health checks, catalog browsing/search, connected-app listing, and action execution (including namespace-style calls).
    • Extended SDK exports and added runnable examples demonstrating end-to-end usage.
  • Bug Fixes
    • Improved parsing of non-envelope runtime JSON responses and mapped runtime middleware error shapes into consistent SDK errors.
    • Expanded self-hosted runtime error codes for more complete error reporting.
  • Documentation
    • Updated README and examples to cover self-hosting, optional runtime token authentication, and supported API capabilities.
  • Tests
    • Added/updated test coverage for open runtime behavior and non-envelope JSON normalization.

Walkthrough

This PR adds OpenConnector, a new client for a self-hosted runtime with execute/executeRaw, health, catalog, and apps APIs, plus namespace-style action access. It updates transport parsing to handle envelope and non-envelope JSON responses, expands connector error codes for runtime failures, and generalizes registry namespace typing to accept custom call options. The change also adds top-level exports, docs, an example script, test helpers, unit tests, and type-level fixture coverage.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required type(scope): subject format and accurately summarizes the new OpenConnector runtime client.
Description check ✅ Passed The description is clearly related to the PR and covers the new OpenConnector client and supporting changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/open-connector

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/open.ts`:
- Around line 396-421: The OpenConnectorImpl constructor validates runtimeToken
eagerly, but baseUrl is still deferred until buildOpenSpec/new URL, which can
leak a raw TypeError instead of ConnectorError. Add upfront baseUrl validation
in OpenConnectorImpl’s constructor when resolving cfg.baseUrl, and throw a typed
ConnectorError for malformed or empty values so the error shape matches the
SDK’s documented contract and the err instanceof ConnectorError pattern used by
OpenConnector callers.

In `@test/open.test.ts`:
- Around line 57-68: The test cases are redundantly re-importing OpenConnector
inside the specs, which shadows the top-level import and triggers no-shadow.
Update the two tests to use the existing OpenConnector binding already imported
at the top of the file, and remove the inline await import(...) usages in the
construct-with-no-config and injected-fetch cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 08d5ba62-a2bb-4f20-87a4-c75ad7268432

📥 Commits

Reviewing files that changed from the base of the PR and between 78f9595 and fa2a3fe.

📒 Files selected for processing (16)
  • README.md
  • examples/README.md
  • examples/open.ts
  • fixtures/consumer/no-b/index.test-d.ts
  • fixtures/consumer/partial-b/index.test-d.ts
  • fixtures/consumer/with-b/index.test-d.ts
  • src/connector.ts
  • src/errors.ts
  • src/http.ts
  • src/index.ts
  • src/open.ts
  • src/registry.ts
  • src/types.ts
  • test/helpers.ts
  • test/open.test.ts
  • test/transport.test.ts

Comment thread src/open.ts
Comment thread test/open.test.ts Outdated
An unparsable `baseUrl` previously surfaced only at call time, as a
raw `TypeError` from `new URL()` inside the request builder — outside
the `ConnectorError` contract every other SDK failure honors. Check it
eagerly, next to the existing `runtimeToken` precheck, and throw the
typed `client_invalid_request` instead.

Also drop the redundant dynamic re-imports of `OpenConnector` in the
constructor tests — the symbol is already statically imported at the
top of the file (flagged by no-shadow).

Signed-off-by: Kevin Cui <bh@bugs.cc>
@BlackHole1 BlackHole1 merged commit b5ec99d into main Jul 2, 2026
2 checks passed
@BlackHole1 BlackHole1 deleted the feat/open-connector branch July 2, 2026 15:10
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