feat(connectors): callApi for metered connectors - #256
Conversation
Some connectors are backed by paid third-party APIs that charge Base44 per call. For those the OAuth token is not available to app code — getConnection and its siblings reject with a 403 — because the Base44 proxy is the only place those calls can be counted. Adds the three proxy methods that replace them: - callApi(integrationType, request) — shared platform connector - callWorkspaceApi(connectorId, request) — workspace-registered connector - callCurrentAppUserApi(connectorId, request) — per-app-user connector Each mirrors its getConnection counterpart, so the identifier you already use carries over. Two deliberate shape decisions: - An upstream 4xx/5xx resolves with `success: false` and the provider's own `status`/`data` rather than throwing. It is a normal outcome of a call Base44 completed and billed; only Base44-side failures (no connection, credits exhausted, a rejected request) reject. - `query` is always sent, never dropped. The server prices the merged query string, so a client that accepted the field and then discarded it would make the quoted price and the real request disagree. Responses carry `creditsCharged` so callers can see what a call actually cost, and the module docs call out that cost varies sharply by endpoint — an expensive call inside a loop is the failure mode worth warning about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drops callWorkspaceApi and callCurrentAppUserApi. They implied that workspace-registered and app user connectors can be metered, and they can't: both run on the workspace's *own* OAuth app, so the provider invoices the workspace directly. Proxying them would have billed the customer credits on top of a vendor bill they already pay. Only a platform connector runs on Base44's OAuth app, so callApi is the only one of the three that ever had something to meter. The backend's matching routes are gone too (base44-dev/apper#19753). The module docs now say which connectors this applies to and, more usefully, why the other two don't — so the next person doesn't re-add the methods on the assumption they were an oversight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @ChenMachBase's task —— View job Code Review: callApi for metered connectorsThorough, well-tested PR. The two "shape decisions" (upstream errors resolve; Code quality — 👍
Potential bugs / issues
Performance — 👍No concerns. Single POST per call; no extra allocations of note. The docs' warning about expensive calls inside loops is the right place to address the real cost lever, since it's server-priced. Security
Test coverage — strong9 tests cover: normalization, GET default, query forwarding, camelCase mapping, upstream-error-resolves, Base44-error-rejects (402), metered 403 on
Minor nits
Overall: LGTM. The billing-bypass reasoning behind always forwarding |
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/sdk@0.8.43-pr.256.e74a345Prefer not to change any import paths? Install using npm alias so your code still imports npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.43-pr.256.e74a345"Or add it to your {
"dependencies": {
"@base44/sdk": "npm:@base44-preview/sdk@0.8.43-pr.256.e74a345"
}
}
Preview published to npm registry — try new features instantly! |
Summary
Adds
callApifor metered connectors — connectors backed by paid third-party APIs that charge Base44 per call.For those, the OAuth token is deliberately unavailable to app code (
getConnectionrejects with a403), because the Base44 proxy is the only place calls we pay for can be counted.callApiis the replacement:Only platform connectors are affected. A workspace-registered or app user connector runs on your own OAuth app, so the provider invoices you directly and there is nothing for Base44 to meter — those keep normal token access via
getWorkspaceConnection()/getCurrentAppUserConnection(). That is why there is one method here and not three.Two shape decisions worth reviewing
An upstream 4xx/5xx resolves, it does not throw. A provider error is a normal outcome of a call Base44 completed and billed, so it comes back as
success: falsewith the provider's ownstatusanddata. Only Base44-side failures — no connection, credits exhausted, a rejected request — reject the promise. Tests pin both sides of that split.queryis always forwarded, never dropped. The server prices the merged query string, so an SDK that accepted the field and then discarded it would make the quoted price and the real request disagree. (This is the client-side half of a billing bypass caught during review of the backend change.)Responses carry
creditsCharged, and the module docs gain a "Metered connectors" section noting that cost can vary by two orders of magnitude between endpoints on the same connector — an expensive call inside a loop being the failure mode worth warning about.Testing
tests/unit/connectors-proxy.test.ts: payload normalization,snake_case→camelCasemapping, query forwarding, upstream-error-resolves vs Base44-error-rejects, and the metered403surfacing an actionable message.tsc --noEmit,npm run test:types, andeslint src.npm ci(lockfile-exact). Up to date withmain.Notes
package.jsonis at main's0.8.42. Publishing, and bumping the pinned@base44/sdkin the platform's builder prompts, is a separate release step; that pin touches several prompt files including system-prompt ones.preview-publish, so this replaces it.