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.
78 lines • 5.03 kB
JavaScript
import { relative, resolve } from "node:path";
import { LocalError } from "../errors.js";
export function manifestExportUnsupported(path, reason) {
throw new LocalError(`Cannot export ${path}: ${reason}`, "exporting authoring manifest", {
code: "MANIFEST_EXPORT_UNSUPPORTED", details: { field_paths: [path], reason },
next_actions: [{ type: "edit_manifest", why: "Use supported declarative release inputs, then retry --print-manifest. --print-spec is SDK-native inspection only." }],
});
}
/** Export relative to the original manifest directory, never the caller's cwd. */
export function serializeDeployManifest(loaded, baseDir, explicitProject) {
if (loaded.config?.env_accessed.length)
manifestExportUnsupported("config.env", "evaluated environment values may contain secrets; keep them in the trusted config");
const secrets = loaded.spec.secrets;
if (secrets && Object.keys(secrets).some((key) => !["require", "delete"].includes(key)))
manifestExportUnsupported("secrets", "embedded secret values are not exportable");
const aliases = { timeoutSeconds: "timeout_seconds", memoryMb: "memory_mb", contentType: "content_type", requireAuth: "require_auth", requireRole: "require_role", idColumn: "id_column", roleColumn: "role_column", cacheTtl: "cache_ttl", onDeny: "on_deny", signInPath: "sign_in_path", defaultLocale: "default_locale", unknownLocalePolicy: "unknown_locale_policy" };
const seen = new Set();
function visit(value, path, content = false) {
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number")
return value;
if (value instanceof Uint8Array)
return { data: Buffer.from(value).toString("base64"), encoding: "base64" };
if (value instanceof ArrayBuffer)
return { data: Buffer.from(value).toString("base64"), encoding: "base64" };
if (typeof value !== "object" || value === undefined)
return manifestExportUnsupported(path, "executable or non-JSON value");
if (seen.has(value))
return manifestExportUnsupported(path, "cyclic object");
seen.add(value);
try {
if (Array.isArray(value))
return value.map((item, index) => visit(item, `${path}[${index}]`));
const record = value;
if (record.__source === "fs-file")
return { path: relative(baseDir, record.path).split("\\").join("/"), ...(record.contentType ? { content_type: record.contentType } : {}) };
if (record.__source === "local-dir")
return manifestExportUnsupported(path, "directory enumeration is dynamic; use explicit file entries for a reloadable JSON export");
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
return manifestExportUnsupported(path, "streams and runtime objects are not declarative JSON");
const isNamedMap = /^(functions\.(replace|patch\.set)|site\.(replace|patch\.put))$/.test(path) || path.endsWith(".files");
const schemaAliases = path === "i18n" || /^functions\.(?:replace|patch\.set)\.[^.]+(?:\.config|\.requireRole)?$/.test(path) || content;
const result = {};
for (const [key, child] of Object.entries(record)) {
if (child === undefined)
continue;
result[isNamedMap || !schemaAliases ? key : aliases[key] ?? key] = visit(child, path ? `${path}.${key}` : key, (isNamedMap && !path.startsWith("functions.")) || path.endsWith(".files") || (key === "source" && /^(functions|assets)\./.test(path)) || (key === "data" && content));
}
// ContentSource {data: Uint8Array} wraps bytes; its authoring encoding
// belongs alongside data, not in a second nested data wrapper.
if (record.data instanceof Uint8Array || record.data instanceof ArrayBuffer) {
Object.assign(result, visit(record.data, `${path}.data`));
}
return result;
}
finally {
seen.delete(value);
}
}
const { project_id: _projectId, ...spec } = loaded.spec;
const result = visit(spec, "");
const project = explicitProject ?? loaded.manifest.project_id;
if (project)
result.project_id = project;
if (loaded.idempotencyKey)
result.idempotency_key = loaded.idempotencyKey;
if (loaded.verify)
result.verify = visit(loaded.verify, "verify");
const migrations = result.database?.migrations;
loaded.manifest.database?.migrations?.forEach((migration, index) => {
const path = migration.sql_path ?? migration.sql_file;
if (path && migrations?.[index]) {
delete migrations[index].sql;
migrations[index].sql_path = relative(baseDir, resolve(baseDir, path)).split("\\").join("/");
}
});
return result;
}
//# sourceMappingURL=manifest-export.js.map