import { type ScopeHost } from '@substrat-run/kernel'; import { type ConnectionProbe, type ConnectionRelayResult, type PlatformActorId } from '@substrat-run/contracts'; /** * The connection relay (connections.md §3.5.2) — the credential half of #574's routed * connector dispatch. A hosted CP-less vertical's tenant admin holds a provider credential * (a Scrive OAuth1 token, a Fortnox key) and needs to hand it to the platform's connection * store from the vertical's OWN admin screen: the vertical permission-checks the act * (`ctx.check`) and its harness POSTs the secret to `/internal/connections/upsert`, the * same shape as the email relay (#303). This module is that endpoint's logic, kept out of * the worker so it can be exercised against a real adapter. * * Trust posture, identical to the email relay: the shared PLATFORM_SECRET only proves "a * platform script is calling" — WHICH vertical is re-derived from the platform's own scope * record for the named `(tenantId, scopeId)`, so a caller cannot plant a credential on a * foreign vertical, and `grantToConnection`'s own checks pin every grant inside the * connection's (tenant, vertical). What the relay adds over a platform-request intent is * the posture connections.md §3.4 demands: the plaintext lives for the length of this call * and is sealed by the host's `SecretBox` — it never rests in a scope row, an event, an * intent payload, or the audit log. * * Upsert keyed (tenant, vertical, provider, externalAccountRef): no live connection → * create under a fresh id; one live → rotate its secret in place, reviving an * expired/errored row. Rotation preserves the connection id, so every grant tuple keyed on * it survives — which is why rotation is never revoke + create. Grants are re-applied on * every upsert (tuples are idempotent), so a re-connect also heals a missing grant. */ export declare class ConnectionRelayError extends Error { /** * `503` is the odd one out and deliberately so (#603): 4xx says the request was * wrong, and this one was not — the DEPLOYMENT cannot store credentials. Answering * 500 (what an unrecognised throw collapses to) sent an operator looking for a bug * in the credential or the relay, when the plane knew at boot that it had no key. */ readonly status: 400 | 404 | 409 | 422 | 503; /** The provider's own answer, when the refusal came from a pre-flight probe (#605). */ readonly probe?: ConnectionProbe | undefined; constructor(message: string, /** * `503` is the odd one out and deliberately so (#603): 4xx says the request was * wrong, and this one was not — the DEPLOYMENT cannot store credentials. Answering * 500 (what an unrecognised throw collapses to) sent an operator looking for a bug * in the credential or the relay, when the plane knew at boot that it had no key. */ status: 400 | 404 | 409 | 422 | 503, /** The provider's own answer, when the refusal came from a pre-flight probe (#605). */ probe?: ConnectionProbe | undefined); } /** * Check a candidate credential against the provider BEFORE it is written (#605). * * The upsert used to mean "store it": the row landed, the console said Connected, and the * first evidence that the provider disagreed arrived on the next dispatch — after a * signature request had already failed. On a ROTATION it is worse than cosmetic, because * writing first replaces a working credential with a broken one. * * Only a definite refusal (the provider answering 401/403) blocks the write. An * unreachable provider does not: rejecting then would make an outage look like every * tenant's keys going bad, and would block the rotation someone is attempting *because* * things are broken. Unverifiable is stored, and reported as unverified. */ export type ConnectionCandidateProbe = (provider: string, secret: Record) => Promise; export declare function relayConnectionUpsert(host: ScopeHost, actor: PlatformActorId, body: unknown, options?: { probeCandidate?: ConnectionCandidateProbe; }): Promise; //# sourceMappingURL=connection-relay.d.ts.map