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.
129 lines • 6.09 kB
TypeScript
/**
* The vault deploy lane, supplied at last (change `vault-deploy-lane`).
*
* `add-vault` 5.6 built `runVaultDeploy` with the lane INJECTED and never
* supplied one, so a project whose `vault_policy` is `required` could not be
* deployed by any published client. This module is that supplier, plus the
* entry point the CLI calls in place of a bare `apply()`:
*
* - {@link createApplyDeployLane} drives the shipped `/apply/v1` routes —
* plan carrying `{capture_id, snapshot_oid_hmac}`, content upload, then a
* commit carrying the activation token — by REUSING `Deploy.apply()` rather
* than reassembling it. Warning gating, CAS dedup, event emission, asset
* re-plan, and terminal polling are the same code every other deploy runs;
* the only difference is two extra wire fields.
* - {@link applyWithVault} decides whether any of that happens at all. A
* project that is not `required` takes the untouched path: no capture, no
* token, no extra refusal, one policy read.
*
* THE COROUTINE, because it is the non-obvious part. `runVaultDeploy` wants
* two separable steps (plan, then commit) with the vault push running between
* them; `Deploy.apply()` is one call. The lane bridges them with a pair of
* deferreds: `apply()`'s `authorize` hook fires once the plan exists and its
* content is uploaded, which RESOLVES `lane.plan(...)`; it then waits for
* `lane.commit(...)` to hand back the activation block. If no commit is ever
* coming — the push failed, or correspondence refused — {@link abandon} rejects
* that wait so the apply unwinds with nothing committed.
*/
import { type NextAction } from "../errors.js";
import type { Deploy } from "../namespaces/deploy.js";
import type { Repos } from "../namespaces/repos.js";
import type { ApplyOptions, DeployResult, LegacyWarningEntry, ReleaseSpec } from "../namespaces/deploy.types.js";
import type { VaultDeployLane, VaultDeployResult } from "./vault-deploy.js";
export interface ApplyDeployLaneOptions {
/** The apply engine (`r._applyEngine`). */
engine: Deploy;
spec: ReleaseSpec;
/** Everything a normal `apply()` takes: events, idempotency key, warning wallets. */
apply?: Omit<ApplyOptions, "vault">;
}
/** A lane that is also cancellable, because `runVaultDeploy` may never commit. */
export interface ApplyDeployLane extends VaultDeployLane {
/**
* Tell the in-flight apply that no commit is coming. Safe to call always —
* a no-op once the apply has settled — and safe to call twice.
*/
abandon(reason: unknown): void;
/** The `DeployResult`, once a commit landed. `null` on every other path. */
result(): DeployResult | null;
}
export declare function createApplyDeployLane(options: ApplyDeployLaneOptions): ApplyDeployLane;
/** What the deploy did about vault, and why. */
export type VaultApplyMode =
/** No vault, or the policy read did not resolve — the plain path ran. */
{
kind: "none";
reason: "no_vault" | "policy_unreadable";
}
/** A vault exists but the policy is `grandfathered` — the plain path ran. */
| {
kind: "grandfathered";
repo_id: string;
}
/**
* A vault exists but `vault_policy` was never set either way — D3:
* allocating a vault no longer flips the policy, so this is the ordinary
* shape for a project whose vault came from `run402 repos create` (or a
* lazy first push) and nobody has opted into gating deploys yet. The plain
* path ran, and the DeployResult carries the offer/warning (see
* {@link decorateUngatedResult}).
*/
| {
kind: "ungated";
repo_id: string;
}
/** The policy is `required` — capture, token, and commit ran. */
| {
kind: "vaulted";
repo_id: string;
};
/** `run402 repos policy required` — the offer D3 attaches to every ungated deploy. */
export declare function vaultPolicyRequiredNextAction(repoId: string): NextAction;
/** The standing `warnings[]` entry D3 attaches to every ungated deploy, until the policy is set either way. */
export declare function vaultUngatedWarning(repoId: string): LegacyWarningEntry;
export interface ApplyWithVaultResult {
mode: VaultApplyMode;
/** The deploy result. `null` when a vaulted deploy did not reach a commit. */
deploy: DeployResult | null;
/** The five-outcome envelope. `null` on every non-`required` path. */
vault: VaultDeployResult | null;
}
export interface ApplyWithVaultOptions {
sdk: {
_applyEngine: Deploy;
repos: Repos;
};
spec: ReleaseSpec;
apply?: Omit<ApplyOptions, "vault">;
/** The work tree to capture. Defaults to the process cwd. */
repo_dir?: string;
/** Override the keystore root (tests, non-default profiles). */
keystore_root?: string;
/** The audited unvaulted override — requires `gitvault.override_unvaulted`. */
allow_unvaulted?: {
reason: string;
};
/**
* Capture a dirty tree anyway. Default `false` — a dirty work tree refuses
* `SNAPSHOT_DIRTY_TREE` before this deploy's capture runs at all (same
* default as the manual `repos capture` lane; see `vault-snapshot.ts`).
* Has no effect on a `none`/`grandfathered`/`ungated` deploy, which never
* captures.
*/
allowDirty?: boolean;
/** Receives the `vault_commit` line the moment the snapshot exists. */
onCommitLine?: (line: string) => void;
/** Target passthrough; a Core target never engages the vault lane. */
target?: "cloud" | "core";
}
/**
* Deploy, taking the project's `vault_policy` into account.
*
* NOT `required` — no vault, an unreadable policy, a Core target, or an
* explicit `grandfathered` — runs `apply()` with the caller's own options and
* nothing else. That path must stay byte-identical: it is every non-vault
* user's deploy, and the only cost this function may add to it is the single
* policy read that determines the project is not `required`.
*/
export declare function applyWithVault(options: ApplyWithVaultOptions): Promise<ApplyWithVaultResult>;
//# sourceMappingURL=vault-apply.d.ts.map