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.
225 lines • 9.91 kB
TypeScript
/**
* Node-only `Assets` namespace enrichments (v1.48 unified-apply).
*
* `NodeAssets` extends the isomorphic {@link Assets} with directory-walking
* helpers — `uploadDir` (additive), `syncDir` (declarative prune), and
* `prepareDir` (pre-commit URL injection) — that read bytes from disk
* lazily, compute SHA-256s in streaming chunks, and submit through the
* single hero `r.project(id).apply(spec)` engine. See design D8/D10/D11.
*
* Imports `node:fs/promises` via `fileSetFromDir`, so this module is
* Node-only — V8 isolates use `r.project(id).assets.putMany(items)` with
* in-memory byte sources.
*/
import { Assets } from "../namespaces/assets.js";
import { LocalError } from "../errors.js";
import type { AssetPutEntryInput, AssetSpec, AssetSyncPruneConfirm, ContentSource, DeployEvent, LocalDirRef } from "../namespaces/deploy.types.js";
/**
* SDK-input-only marker for "walk this directory at submission time." The
* canonical type now lives in `deploy.types.ts` so the isomorphic SDK can
* reference it from `SiteSpec` / `AssetSpec` without a dependency on this
* Node-only module. Re-exported here for backwards compatibility with
* `@run402/sdk/node` callers (and to keep `dir()` co-located with its
* return type).
*
* The gateway never sees a `LocalDirRef` — submitting one in a JSON body
* is rejected with HTTP 400 `INVALID_WIRE_SCHEMA`. The kind discriminator
* `"local-dir"` is stable for type-narrowing.
*/
export type { LocalDirRef };
export interface DirOptions {
/** Optional key prefix applied to every walked entry. `"static/"` →
* every file's relative path becomes `"static/<path>"`. */
prefix?: string;
/** Additional file/dir names to skip at any depth. Merged with the
* defaults (`.git`, `node_modules`, `.DS_Store`, and sensitive
* filenames unless `includeSensitive: true`). */
ignore?: ReadonlyArray<string>;
/** Opt in to collecting `.env`-style files. Same semantics as
* `fileSetFromDir`. */
includeSensitive?: boolean;
}
/**
* Build a `LocalDirRef` for the given filesystem path. Synchronous — the
* actual filesystem walk happens at `apply()` submission time per design
* D12 ("dir(path) returns synchronous LocalDirRef; SDK-input-only").
*
* Accepted as `site.replace` and `site.patch.put` on `r.project(p).apply`.
* For assets, use `r.project(p).assets.uploadDir(path)` /
* `syncDir` / `prepareDir` — those wrap a `LocalDirRef` walk into the
* unified-apply pipeline with directory-specific options (prune, prepare,
* progress events).
*
* @example
* import { dir, run402 } from "@run402/sdk/node";
* const r = run402();
* await r.project(p).apply({
* site: dir("./dist"),
* });
* await r.project(p).assets.uploadDir("./assets", { prefix: "static/" });
*/
export declare function dir(path: string, opts?: DirOptions): LocalDirRef;
/**
* Walk a `LocalDirRef` and emit `AssetPutEntryInput[]` carrying a
* `ContentSource` per file (rather than a pre-computed SHA). The actual
* hashing + byte-reader registration happens inside the SDK's
* `normalizeAssetSlice` pipeline so the bytes are uploaded via the shared
* `byteReaders` map (v1.48 unified-apply). Returning wire-shaped entries
* here would skip byte-reader registration and the deploy would fail with
* `Missing bytes for sha=<...>` at upload time.
*
* The prefix is applied to relative keys. content_type/visibility/immutable
* are left to the normalizer's defaults (visibility=public, immutable=true,
* content_type derived from extension).
*/
export declare function entriesFromLocalDir(ref: LocalDirRef): Promise<AssetPutEntryInput[]>;
export interface AssetManifestEntry {
key: string;
sha256: string;
size_bytes: number;
content_type: string;
visibility: "public" | "private";
url: string | null;
immutable_url: string | null;
cdn_url: string | null;
cdn_immutable_url: string | null;
sri: string | null;
etag: string | null;
content_digest: string | null;
}
export interface AssetManifestTotals {
files: number;
bytes_uploaded: number;
bytes_reused: number;
duration_ms: number;
}
/**
* Batch asset operation result (per design D9). `list` and `byKey`
* share the same `AssetManifestEntry` instances in memory; `manifest`
* is a plain-data shallow copy suitable for JSON serialization.
* `byKey` and `manifest` are constructed with `Object.create(null)` so
* attacker-controlled keys like `__proto__` don't collide with
* `Object.prototype`.
*
* Note: v1.48 surfaces plain-data entries (URLs + sha + metadata) only.
* The richer `AssetRef` shape with HTML tag emitters lands once the
* gateway plan-response enrichment is wired (Phase 3.5 follow-up).
*/
export interface AssetManifest {
list: AssetManifestEntry[];
byKey: Record<string, AssetManifestEntry>;
manifest: Record<string, AssetManifestEntry>;
totals: AssetManifestTotals;
/** Present when `syncDir({ prune: true })` ran. */
pruned?: string[];
}
export interface PutManyItem {
key: string;
source: ContentSource;
contentType?: string;
visibility?: "public" | "private";
immutable?: boolean;
/** v1.50: per-item caller-provided metadata. Same shape and validation
* as {@link AssetPutEntryInput.metadata}. */
metadata?: Record<string, string | number | boolean | string[]>;
/** v1.50: per-item EXIF policy override. */
exifPolicy?: "keep" | "strip";
}
export interface UploadDirOptions extends DirOptions {
/** Project id the apply targets. */
project: string;
/** Optional progress callback. */
onEvent?: (event: DeployEvent) => void;
/** v1.50: default metadata applied to every entry walked from the
* directory. Per-call default — entries that need per-key metadata
* should use {@link NodeAssets.putMany} instead. */
metadata?: Record<string, string | number | boolean | string[]>;
/** v1.50: default EXIF policy applied to every entry walked from the
* directory. */
exifPolicy?: "keep" | "strip";
}
export interface SyncDirOptions extends UploadDirOptions {
/** Without `prune: true`, behaves additively (equivalent to
* `uploadDir`). With `prune: true`, the apply is destructive and
* requires a confirmation token from a prior plan call. */
prune?: boolean;
/** When the caller already has a confirmation block from a prior plan,
* passing it commits in one round-trip. Without it on a destructive
* call, the SDK throws `LocalError` with code
* `PRUNE_CONFIRMATION_REQUIRED` carrying the values to acknowledge. */
confirm?: AssetSyncPruneConfirm;
}
export interface PrepareDirOptions extends DirOptions {
/** Project id the apply targets. */
project: string;
}
/**
* Error thrown by `syncDir({ prune: true })` when called without a
* `confirm` token. Carries the values the caller must echo back to
* commit the destructive operation. The SDK auto-throws this before the
* destructive apply lands so the agent has a chance to surface the
* planned delete set to the user.
*/
export declare class PruneConfirmationRequired extends LocalError {
readonly code: "PRUNE_CONFIRMATION_REQUIRED";
readonly base_revision: string;
readonly delete_set_digest: string;
readonly expected_delete_count: number;
readonly sample_keys: string[];
constructor(args: {
base_revision: string;
delete_set_digest: string;
expected_delete_count: number;
sample_keys: string[];
});
}
export declare class NodeAssets extends Assets {
/**
* Additive directory upload. Existing keys under the (optional) prefix
* that aren't in the new directory are left untouched. Per design
* D10. Wraps `r._applyEngine.apply({ project, assets: { put: ... } })`.
*/
uploadDir(path: string, opts: UploadDirOptions): Promise<AssetManifest>;
/**
* Declarative directory sync. Per design D10:
* - Without `prune: true`, behaves identically to {@link uploadDir}
* (additive only).
* - With `prune: true` AND no `confirm` token, runs a plan first and
* throws {@link PruneConfirmationRequired} carrying the values the
* caller must echo back to commit.
* - With `prune: true` AND a `confirm` token, commits the destructive
* sync. The gateway's activation-time drift check
* (`ASSET_SYNC_DRIFT`) catches the narrower race where inventory
* mutates between commit and activation.
*/
syncDir(path: string, opts: SyncDirOptions): Promise<AssetManifest>;
/**
* Pre-commit URL injection helper (design D8 / spec Requirement
* "assets.prepareDir"). Runs a plan against `r.project(id).apply.plan`
* and returns `{ manifest, applySlice }` so the caller can render HTML
* against the final resolved URLs and submit the same `applySlice` to
* the commit step without re-uploading. Currently a thin shim — the
* full plan-response enrichment lands in a follow-up.
*/
prepareDir(path: string, opts: PrepareDirOptions): Promise<{
manifest: AssetManifest;
applySlice: AssetSpec;
}>;
/**
* In-memory batch upload. Each item carries the key + an in-memory
* `ContentSource` (string, Uint8Array, ArrayBuffer, Blob). SHA-256 is
* computed locally, then a single apply call submits all entries.
* Returns `AssetManifest`.
*/
putMany(items: PutManyItem[], opts: {
project: string;
onEvent?: (event: DeployEvent) => void;
}): Promise<AssetManifest>;
/**
* Internal: instantiate a Deploy (engine) bound to the same Client
* this Assets instance was constructed with. Avoids requiring a
* separate apply-engine parameter on the namespace constructor.
*/
private applyEngine;
}
//# sourceMappingURL=assets-node.d.ts.map