feat(api): add OpenConnector for the self-hosted runtime#5
Conversation
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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
Summary by CodeRabbit
WalkthroughThis PR adds Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches✨ Simplify code
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (16)
README.mdexamples/README.mdexamples/open.tsfixtures/consumer/no-b/index.test-d.tsfixtures/consumer/partial-b/index.test-d.tsfixtures/consumer/with-b/index.test-d.tssrc/connector.tssrc/errors.tssrc/http.tssrc/index.tssrc/open.tssrc/registry.tssrc/types.tstest/helpers.tstest/open.test.tstest/transport.test.ts
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>
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 toConnector(hosted personal) andProjectConnector(hosted project), covering the same personal surface against a server you run — both call paths (open.execute(...)and theopen.gmail.search_threads({...})namespace sugar),catalog/appsintrospection, 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 noAuthorizationheader 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 toCallOptionsso the hostedConnector's published types are byte-for-byte unchanged.OpenConnectorinstantiates them with its narrowerOpenExecuteOptions, so the hosted-onlyorganizationoption is rejected at compile time on the open client whileconnectionName/signal/timeoutMs/retrieswork as usual.http.ts'sparseBodynow 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/v1routes (e.g. its 401) — maps onto the envelope's error fields, soConnectorError.code/.messagestay faithful across both backends.The action metadata returned by this runtime also gets its own
OpenActionMetadatatype: on the wirefollowUpActionsare{ actionId }wrappers (not thestring[]the sharedActionMetadataclaims), andasyncLifecycleis an explicitnullwhen 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.4in 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).