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.
73 lines • 3.35 kB
JavaScript
/**
* Node-only `sites.deployDir` convenience.
*
* **As of v1.34, this is a thin wrapper over `r.project(id).apply`** — bytes ride
* through the unified CAS substrate, the deploy flows through the v2 plan/
* commit endpoints, and the agent-observable result remains a
* {@link SiteDeployResult}. Existing callers keep their input shape
* (`{ project, dir, onEvent? }`), and `onEvent` receives the unified
* `DeployEvent` shapes from the SDK's `deploy` namespace.
*
* Imports `node:fs/promises` via `fileSetFromDir`, so this module remains
* Node-only — V8 isolates use `r.project(id).apply` with in-memory byte sources.
*/
import { Sites } from "../namespaces/sites.js";
import { Deploy } from "../namespaces/deploy.js";
import { summarizeDeployResult } from "../namespaces/deploy.types.js";
import { fileSetFromDir } from "./files.js";
/**
* Sites namespace enriched with the Node-only `deployDir` convenience.
* All existing `Sites` methods are inherited unchanged.
*/
export class NodeSites extends Sites {
/**
* Deploy every file under `dir` as a static site. Walks the tree (skipping
* `.git`/`node_modules`/`.DS_Store`, rejecting symlinks), produces an
* `FsFileSource`-backed `FileSet`, and delegates to `r.project(id).apply` —
* which uploads only the bytes the gateway doesn't already have, applies
* the new release atomically, and polls the operation until terminal.
*/
async deployDir(opts) {
const fileSet = await fileSetFromDir(opts.dir);
const deploy = new Deploy(this.client);
const result = await deploy.apply({ project_id: opts.project, site: { replace: fileSet } }, { onEvent: makeSafeEventForwarder(opts.onEvent) });
const out = {
deployment_id: pickFromUrls(result.urls, "deployment_id") ?? result.release_id,
// v2 commit returns `urls = { project, release }` — no `site` key. Use
// the live project URL as the canonical `url` for the legacy result
// shape; fall back to `urls.site` for forward compat with any gateway
// build that resurrects the old key, and `""` only as a last resort
// (matches prior behaviour).
url: pickFromUrls(result.urls, "project") ??
pickFromUrls(result.urls, "site") ??
"",
};
const summary = summarizeDeployResult(result);
const cas = summary.site?.cas;
if (typeof cas?.newly_uploaded_bytes === "number" &&
typeof cas.reused_bytes === "number") {
out.bytes_uploaded = cas.newly_uploaded_bytes;
out.bytes_total = cas.newly_uploaded_bytes + cas.reused_bytes;
}
return out;
}
}
function makeSafeEventForwarder(consumer) {
if (!consumer)
return () => { };
return (event) => {
try {
consumer(event);
}
catch {
/* swallow — buggy consumer must not abort the deploy */
}
};
}
// ─── Helpers ─────────────────────────────────────────────────────────────────
function pickFromUrls(urls, key) {
if (!urls)
return undefined;
return urls[key];
}
//# sourceMappingURL=sites-node.js.map