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.
75 lines • 3.68 kB
TypeScript
/**
* vault D6 — push-to-create (repo-first-onramp task 4.5).
*
* `pushToCreateVault` is the primitive the remote helper and `vault
* snapshot` drive when a slug-form remote (`run402::<org-slug>/<name>`)
* resolves to nothing yet: pushing to a name that does not exist allocates it
* (design D6), atomically, through the gateway's `POST /vaults/v1
* {org_slug, repo_name}` push-to-create form — the SAME route the ordinary
* `{project_id}` allocate uses, so the six-stage creation journal
* ({@link createVault}) drives it exactly as it drives an ordinary
* creation, just addressed by `push_to_create` instead of `project_id`.
*
* SHAPE, mirroring the gateway's own `pushToCreateRepo` (run402-private
* `services/repo-names.ts`) one layer up:
*
* 1. Fast path: does `org-slug/name` already resolve
* ({@link VaultTransport.findVaultByRepo})? If so this is an
* ordinary push to an existing repo — return its vault record, allocate
* nothing. This is ALSO how a race LOSER's next call resolves cleanly
* (see step 3): the repo now exists, so a retry never re-enters the
* journal at all.
* 2. Not found: drive the six-stage journal, addressed by
* `push_to_create: {org_slug, repo_name}`. Resumable exactly like the
* ordinary path — {@link findResumablePushToCreateJournal} finds an
* INCOMPLETE local attempt for this exact address and resumes its
* `client_creation_id` rather than starting a second competing one.
* 3. `REPO_CREATION_CONFLICT` (the gateway's atomic name-claim raced a
* concurrent pusher): resolve to the WINNER's project_id (named in the
* error's `details.project_id`) via `findVaultByProject`, and report
* `found: true` — an ordinary push to the repo that now exists. Design
* D6: "no transparent retargeting" — this client never silently
* continues against the winner's genesis; it re-resolves and the
* NEXT call (an ordinary push) proceeds normally. Nothing here loses
* the loser's actual working-tree changes; only its bid to be the
* creator.
* 4. `SLUG_RELEASED` (the org slug is in its post-rename cooldown): NEVER
* auto-followed — rethrown unchanged so the caller sees the typed
* refusal (successor slug named, cooldown_until stated).
*/
import type { VaultCreationResult } from "./vault-creation-journal.js";
import type { VaultKeystore } from "./vault-keystore.js";
import type { VaultTransport } from "./vault-publication.js";
export interface PushToCreateVaultOptions {
keystore: VaultKeystore;
transport: VaultTransport;
org_slug: string;
repo_name: string;
/** Resume a specific creation attempt (or pin it in tests); auto-discovered from the local keystore otherwise. */
client_creation_id?: string;
service_public_key?: Uint8Array | string;
}
export type PushToCreateVaultResult = {
found: true;
repo_id: string;
project_id: string;
org_id: string;
created: null;
} | {
found: false;
repo_id: string;
project_id: string;
org_id: string;
created: {
/** Mirrors `VaultCreationResult.how === "reconciled"`: an existing local journal was resumed to completion, nothing re-minted. */
deduplicated: boolean;
recovery_receipt: VaultCreationResult["recovery_receipt"];
genesis_sha256: string;
};
};
/**
* Resolve `(org_slug, repo_name)`, allocating it (project + vault, atomically)
* when it does not exist yet.
*/
export declare function pushToCreateVault(options: PushToCreateVaultOptions): Promise<PushToCreateVaultResult>;
//# sourceMappingURL=vault-push-to-create.d.ts.map