run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
120 lines • 4.99 kB
JavaScript
/**
* `domains` namespace — ProjectDomain lifecycle.
*
* Domain operations are project-scoped control-plane actions. They use the
* SDK credential provider's server auth (SIWX, control-plane session, or
* grant key) and deliberately do not require local project-key cache entries.
*/
import { LocalError } from "../errors.js";
function domainPath(projectId, domain) {
return `/projects/v1/${encodeURIComponent(projectId)}/domains/${encodeURIComponent(domain)}`;
}
function authMeta(method, projectId) {
return { method, target: { project_id: projectId } };
}
function waitSatisfied(domain, until) {
if (until === "active")
return domain.status === "active";
if (until === "receive-active") {
const email = domain.effective.email;
return email?.receive?.active === true;
}
return domain.checks.every((check) => !check.blocking || check.status === "passed");
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export class Domains {
client;
constructor(client) {
this.client = client;
}
/**
* Connect a custom domain to a project, or change what an already-connected
* domain should serve: `POST /projects/v1/:project_id/domains { domain, desired }`.
* Returns the ProjectDomain state with `dns_records` and `next_actions`.
*/
async connect(projectId, input) {
return this.client.request(`/projects/v1/${encodeURIComponent(projectId)}/domains`, {
method: "POST",
body: { domain: input.domain, desired: input.desired },
authMeta: authMeta("domains.connect", projectId),
context: "connecting project domain",
});
}
async get(projectId, domain) {
return this.client.request(domainPath(projectId, domain), {
authMeta: authMeta("domains.get", projectId),
context: "getting project domain",
});
}
async list(projectId) {
return this.client.request(`/projects/v1/${encodeURIComponent(projectId)}/domains`, {
authMeta: authMeta("domains.list", projectId),
context: "listing project domains",
});
}
async check(projectId, domain) {
return this.client.request(`${domainPath(projectId, domain)}/actions/check`, {
method: "POST",
authMeta: authMeta("domains.check", projectId),
context: "checking project domain",
});
}
async apply(projectId, domain) {
return this.client.request(`${domainPath(projectId, domain)}/actions/apply`, {
method: "POST",
authMeta: authMeta("domains.apply", projectId),
context: "applying project domain",
});
}
async repair(projectId, domain) {
return this.client.request(`${domainPath(projectId, domain)}/actions/repair`, {
method: "POST",
authMeta: authMeta("domains.repair", projectId),
context: "repairing project domain",
});
}
async testReceive(projectId, domain, to) {
return this.client.request(`${domainPath(projectId, domain)}/actions/test_receive`, {
method: "POST",
body: { to },
authMeta: authMeta("domains.testReceive", projectId),
context: "creating project domain receive test",
});
}
async activate(projectId, domain) {
return this.client.request(`${domainPath(projectId, domain)}/actions/activate_mailbox_addresses`, {
method: "POST",
authMeta: authMeta("domains.activate", projectId),
context: "activating project domain mailbox addresses",
});
}
async disconnect(projectId, domain) {
return this.client.request(domainPath(projectId, domain), {
method: "DELETE",
authMeta: authMeta("domains.disconnect", projectId),
context: "disconnecting project domain",
});
}
async wait(projectId, domain, opts = {}) {
const until = opts.until ?? "active";
const timeoutMs = opts.timeoutMs ?? 120_000;
const intervalMs = opts.intervalMs ?? 5_000;
const started = Date.now();
let last = await this.check(projectId, domain);
while (!waitSatisfied(last, until)) {
if (Date.now() - started >= timeoutMs) {
throw new LocalError(`Timed out waiting for project domain ${domain} to reach ${until}`, "waiting for project domain", {
code: "DOMAIN_WAIT_TIMEOUT",
details: { project_id: projectId, domain, until, last_status: last.status, checks: last.checks },
next_actions: [{ type: "check", command: `run402 domains check ${domain} --project ${projectId}` }],
});
}
await sleep(intervalMs);
last = await this.check(projectId, domain);
}
return last;
}
}
//# sourceMappingURL=domains.js.map