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.
281 lines • 21.7 kB
JavaScript
/**
* `@run402/sdk/node` — zero-config Node entry point.
*
* Wires the isomorphic SDK kernel with:
* - default API base from `RUN402_API_BASE` (via core/config)
* - {@link NodeCredentialsProvider} backed by the local keystore + wallet
* - an x402-wrapped fetch built lazily on first request
* - {@link NodeSites}: the `sites` namespace enriched with `deployDir(dir)`
*
* Usage:
* ```ts
* import { run402 } from "@run402/sdk/node";
* const r = run402();
* const project = await r.projects.provision({ tier: "prototype" });
* await r.sites.deployDir({ project: project.project_id, dir: "./my-site" });
* ```
*
* `deployDir` is a thin wrapper over `r.project(id).apply` — bytes ride through
* the unified CAS substrate, so only files the gateway doesn't already have
* are uploaded. Re-deploying an unchanged tree issues no S3 PUTs.
*/
import { readFileSync } from "node:fs";
export { fundingRecovery, fundingBlocksBootstrap } from "./funding-recovery.js";
import { DEFAULT_API_BASE, getApiBase, getApiBaseSource, getActiveProfile, getApiTargetKind, } from "../../core-dist/config.js";
import { Run402 } from "../index.js";
import { installNodeVaultAeadBackend, installNodeVaultHashBackend } from "./vault-native-crypto.js";
import { sdkFetch } from "./http-dispatcher.js";
// vault-native-bulk-crypto (design D1): the bulk frame AEAD is sync and
// isomorphic, so Node's faster OpenSSL implementation of the SAME construction
// can only be INSTALLED at the entry point, never sniffed from the core. A
// build whose OpenSSL lacks the cipher keeps the `@noble/ciphers` default —
// correct, just slower — so this is deliberately not asserted.
installNodeVaultAeadBackend();
// vault-native-hash: same doctrine, second slot — the protocol SHA-256
// moves to `node:crypto` after a live probe; any failure keeps `@noble`.
installNodeVaultHashBackend();
import { LocalError } from "../errors.js";
import { NodeCredentialsProvider } from "./credentials.js";
import { createLazyPaidFetch, } from "./paid-fetch.js";
import { NodeSites } from "./sites-node.js";
import { NodeAssets } from "./assets-node.js";
import { NodeArchives } from "./archives-node.js";
import { NodeActions } from "./actions-node.js";
import { NodeWallets } from "./wallets.js";
import { NodeOrgs } from "./org-context.js";
import { Diagnostics } from "./diagnostics.js";
import { NodeBuzz } from "./buzz-doctor.js";
import { runDoctor } from "./doctor.js";
import { initApiTarget, runInit } from "./init.js";
import { runStatus } from "./status.js";
/**
* Construct a Run402 client wired with Node defaults.
*
* Behavior matches today's `run402-mcp` / `run402` CLI: reads keystore and
* wallet from disk, signs SIWX headers, and retries 402 responses via
* `@x402/fetch` when the wallet has USDC balance.
*
* The returned instance's `sites` namespace is a {@link NodeSites}, which
* exposes the `deployDir({ dir })` helper.
*/
export function run402(opts = {}) {
if (opts.paymentSigner && opts.walletPath) {
throw new LocalError("Configure exactly one explicit payment source: paymentSigner or walletPath", "constructing client", {
code: "PAYMENT_SOURCE_CONFLICT",
details: { fields: ["paymentSigner", "walletPath"] },
});
}
const apiBase = opts.apiBase ?? getApiBase();
const credentials = opts.credentials ?? new NodeCredentialsProvider({
walletPath: opts.walletPath,
keystorePath: opts.keystorePath,
profileStatePath: opts.profileStatePath,
surface: opts.surface,
authMode: opts.authMode,
grantKey: opts.grantKey,
});
let lazyPaidFetch;
if (!opts.fetch && !opts.disablePaidFetch) {
lazyPaidFetch = createLazyPaidFetch({
walletPath: opts.walletPath,
credentials: opts.credentials ? credentials : undefined,
paymentSigner: opts.paymentSigner,
apiBase,
});
}
const runOpts = {
apiBase,
credentials,
fetch: opts.fetch ??
(opts.disablePaidFetch
? // The owned dispatcher (vault-owned-dispatcher): single
// multiplexed API connection + persisted TLS resumption; defers to
// an overridden globalThis.fetch so test seams keep working.
sdkFetch
: lazyPaidFetch),
payExecutor: opts.payExecutor ?? lazyPaidFetch?.pay,
clientMetadata: nodeClientMetadata(opts),
capabilities: { returnSecrets: opts.surface !== "sandbox" },
};
const base = new Run402(runOpts);
// Upgrade `sites` to the Node-aware variant, sharing the kernel `Client`
// that the isomorphic Sites was constructed with. Access to `client` goes
// through a cast because it is `private` on `Sites` — runtime still exposes
// the field; this keeps a single Client per instance (no divergent state).
const client = base.sites.client;
base.sites = new NodeSites(client);
// v1.48 unified-apply: upgrade `assets` to the Node-aware variant.
// Same single-Client pattern as the sites upgrade above.
base.assets = new NodeAssets(client);
base.archives = new NodeArchives(client);
base.orgs = new NodeOrgs(client);
const diagnostics = new Diagnostics();
base.diagnostics = diagnostics;
base.buzz = new NodeBuzz(client, diagnostics);
// Named-wallet management; the label push signs as the TARGET wallet, so it
// builds a sibling client over that wallet's own files.
base.wallets = new NodeWallets(client, {
clientFor: ({ walletPath, keystorePath }) => run402({ ...opts, credentials: undefined, paymentSigner: undefined, walletPath, keystorePath }),
});
const explicitApiBase = opts.apiBase !== undefined || getApiBaseSource() === "env";
const actions = new NodeActions(base, {
targetKind: inferTargetKind(apiBase, explicitApiBase),
profile: getActiveProfile(),
});
base.actions = actions;
base.up = actions.up.bind(actions);
base.doctor = (doctorOpts) => runDoctor(base, doctorOpts);
base.init = async (initOpts = {}) => {
if (initOpts.apiBase) {
return initApiTarget((o) => run402({ ...opts, credentials: undefined, paymentSigner: undefined, walletPath: undefined, ...o }), initOpts.apiBase, initOpts.onLine);
}
return runInit(base, client, initOpts);
};
base.status = () => runStatus(base);
base.paymentPayer = async () => lazyPaidFetch?.getPayer() ?? null;
return base;
}
function inferTargetKind(apiBase, explicitApiBase) {
const configured = getApiTargetKind();
if (!explicitApiBase && configured !== "unknown")
return configured;
if (stripSlash(apiBase) === stripSlash(DEFAULT_API_BASE))
return "cloud";
try {
return new URL(apiBase).protocol === "http:" ? "core" : "cloud";
}
catch {
return "unknown";
}
}
function stripSlash(value) {
return value.replace(/\/+$/, "");
}
const SDK_PACKAGE_VERSION = readSdkPackageVersion();
function nodeClientMetadata(opts) {
if (opts.clientMetadata === false)
return false;
const base = opts.clientMetadata && typeof opts.clientMetadata === "object" ? opts.clientMetadata : {};
const version = opts.clientVersion ?? base.version ?? SDK_PACKAGE_VERSION;
const sdkVersion = opts.sdkVersion ?? base.sdkVersion ?? SDK_PACKAGE_VERSION;
return {
surface: base.surface ?? opts.surface ?? "sdk",
...(version ? { version } : {}),
...(sdkVersion ? { sdkVersion } : {}),
};
}
function readSdkPackageVersion() {
try {
const pkg = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
return typeof pkg.version === "string" ? pkg.version : undefined;
}
catch {
return undefined;
}
}
export { NodeSites } from "./sites-node.js";
export { fileSetFromDir, normalizeRelPath } from "./files.js";
// v1.48 unified-apply: Node-only `assets.{uploadDir,syncDir,prepareDir,
// putMany}` ergonomics + `dir(path)` LocalDirRef helper. The
// `dir(path)` call is synchronous (per design D12); the filesystem
// walk happens at apply() submission time.
export { NodeAssets, dir, PruneConfirmationRequired } from "./assets-node.js";
export { assertLocalFileReferencesExist, collectLocalFileReferences, findMissingLocalFileReferences, loadDeployManifest, loadExecutableDeployConfig, manifestFileMissingError, manifestNotFoundError, normalizeDeployManifest, } from "./deploy-manifest.js";
export { defineConfig, emailTrigger, file, nodeFunction, scheduleTrigger, sqlFile, } from "../config.js";
export { resolveRun402TargetProfile } from "./target-profile.js";
// vault (r402s/v0) — Node-only: the principal keystore (§5.1) and the
// six-stage creation journal (§5.2). The isomorphic crypto core is re-exported
// at the bottom of this file so Node consumers need a single import.
export { VaultKeystore, getVaultKeystoreRoot, readFileNoFollow, writeFileAtomic0600, } from "./vault-keystore.js";
export { VAULT_CREATION_STAGES, VaultCreation, createVault, findResumableVaultJournal, findResumablePushToCreateJournal, vaultDoctorRecoveryText, vaultJournalPath, listIncompleteVaultJournals, readVaultJournal, } from "./vault-creation-journal.js";
export { VAULT_DEPLOY_REF, VAULT_HANDOFF_SENSITIVE_DENYLIST, VAULT_MAX_GIT_OBJECT_BYTES, VAULT_MIN_GIT_VERSION, HARDENED_GIT_ARGV_PREFIX, captureHandoffSnapshot, captureSnapshot, capturedSetDigest, capturedSetUnchanged, deriveCapturedSet, detectActiveFilters, diffCapturedSets, discoverGlobalExcludes, findOversizeObjects, vaultCommitLine, globMatchesGitPath, hardenedGit, hardenedGitEnv, run402PassthroughEnv, hasObject, inspectRepository, isAncestor, isHandoffSensitivePath, materializeSnapshot, parseGitConfigAsData, probeGitVersion, resolveGitInvocationRepo, snapshotCommitment, } from "./vault-snapshot.js";
export { VAULT_INLINE_UPLOAD_MAX_OBJECT_BYTES, VAULT_INLINE_UPLOAD_MAX_REQUEST_BYTES, VAULT_MAX_CANONICAL_REFS, VAULT_MAX_CHECKPOINT_PACKS, VAULT_MAX_CHECKPOINT_TOTAL_STORED_BYTES, VAULT_MAX_HEADS_PER_LISTING_PAGE, VAULT_MAX_REF_STATE_OBJECT_BYTES, VAULT_MAX_REF_UPDATES_PER_TRANSACTION, VAULT_MAX_REPAIR_ADDED_ROOTS, VAULT_MAX_RETENTION_ROOT_ENTRIES, VAULT_MAX_WAL_RECEIPTS_PER_HEAD, VAULT_MULTI_OBJECT_PACK_TARGET_BYTES, VAULT_PUSH_CONFLICT_RETRIES, VAULT_R402_REF_NAMESPACE, VAULT_RETAIN_REF_PREFIX, VAULT_RETENTION_MIN_DAYS, VAULT_VERIFICATION_BUDGET_HEADS, Vault, assertNoTransition, assertRefMapCardinality, bigIntToGeneration, captureBinding, checkChainLink, checkClaimSetEquality, checkGenerationRegression, checkOpenBinding, compareRoots, createVaultHttpTransport, deployRefTransaction, effectiveAdmittedAt, evaluateRefTransaction, evolveRetentionRoots, generationToBigInt, vaultInlineUploadEligible, vaultPaths, vaultRetainedRefName, isRootEligibleForRemoval, nextGeneration, nextListingRequest, vaultLedgerId, vaultManifestEntry, vaultWireRefForPath, openBindingDigest, reconcileRetainedTipRefs, validateHeadsListingRequest, verifyHeadsListingPage, readVaultRestoreMarker, VAULT_AUTO_GC_GENERATIONS_DEFAULT, readVaultAutoGcThreshold, writeVaultAutoGcThreshold, } from "./vault-publication.js";
export { VAULT_DEPLOY_OUTCOMES, SNAPSHOT_MOVED_DURING_DEPLOY, checkActivationTokenBinding, checkAuthorizationEpoch, drainOverrideJournals, listPendingOverrideJournals, matchCaptureReceipt, overrideJournalDir, overrideJournalPath, readOverrideJournal, runVaultDeploy, writeOverrideJournal, } from "./vault-deploy.js";
// kygit-handoff (design D3) — the Handoff Key: assemble/parse, HKDF
// derivations, the sealed envelope, the note schema + client-side secret
// scan. `Repos.handoff`/`.resume` delegate to this. kygit-invite (design
// D3) widens the SAME module to a second row, `kgi1_` — the Invite Key —
// sharing the one parser/HKDF/envelope/scan machinery by kind.
export { HANDOFF_ENVELOPE_KIND, HANDOFF_KEY_PREFIXES, HANDOFF_ENVELOPE_V2_KIND, INVITE_ENVELOPE_V2_KIND, assembleHandoffKey, assembleInviteKey, assertHandoffNoteHasNoSecret, assertInviteNoteHasNoSecret, deriveHandoffSecrets, deriveInviteSecrets, isKygitHandoffNote, isKygitInviteNote, openHandoffEnvelope, openHandoffEnvelopeV2, openInviteEnvelope, parseRedeemKey, parseHandoffKey, parseInviteKey, scanHandoffNoteForSecrets, scanInviteNoteForSecrets, sealHandoffEnvelope, sealHandoffEnvelopeV2, sealInviteEnvelope, uuidToBytes, } from "./vault-handoff.js";
// add-room-invite (design D3) — the Room Invite Key: `kri1_`, its own
// registry row, and its own (single-secret, envelope-free) HKDF derivation.
// Lives directly in `bearer-redeem-key.ts` rather than riding the vault-
// shaped `vault-handoff.js` re-export above, since a room invite is not a
// vault kind. `r.rooms.invite`/`.join` delegate to this module internally.
export { assembleRoomInviteKey, computeRoomInviteAuthHash, deriveRoomInviteAuthSecret, parseRoomInviteKey, randomRedeemId, } from "./bearer-redeem-key.js";
// vault-multi-writer (rev 47, task 5.4/5.10) — the writer-admission grant
// chain: mint an admission seed from a handoff's own master_secret (never
// auth_secret/wrap_key), the grantor-signed grant, and the two-signature
// acceptance a redeemer builds. `Repos.handoff`/`.resume` delegate to
// these; exported here so an external programmatic consumer can build or
// verify the SAME objects without reaching into the node-only module path.
export { HANDOFF_WRITER_ACCEPT_DOMAIN, buildWriterAcceptance, buildWriterAdmissionGrant, deriveRedeemWriterAdmissionSeed, deriveInviteWriterAdmissionSeed, deriveWriterAdmissionSeed, verifyWriterAcceptance, verifyWriterAdmissionGrant, } from "./vault-handoff.js";
// vault-multi-writer (rev 47, task 5.1/5.10) — the writer set as CHAIN
// STATE (protocol §4.15), the pure cryptographic half of `add_writer_key` /
// `rotate_epoch{writer_set_update}` admission (§4.16-§4.18). Deliberately
// isomorphic (no Node-only APIs) despite living under `node/` — a
// recovering client, the browser viewer, and `r402s-verify` all replay
// writer state from nothing but genesis + admitted chain objects using
// these SAME functions; `Vault`'s own writer-door/handoff-door
// admission and reconcile methods delegate to this module already.
// `WriterChainState` is this module's own name for what the task list
// calls `VaultWriterState` — exported under its established name rather
// than introduced as a redundant alias.
export { MAX_VAULT_WRITERS, ORG_ROLE_RANK, WRITER_ELIGIBLE_ROLE_RANK, applyAddWriterKey, applyWriterSetUpdate, buildAddWriterKeyActivationPayload, buildWriterDoorAddWriterKeyPayload, initialWriterState, meetsWriterEligibleRole, predictMintedRole, replayWriterState, resolveActiveWriter, validateAddWriterKeyPayload, validateWriterSetUpdate, writerKeyIdOf, writerSetSha256, } from "./vault-writer-state.js";
// kygit-handoff (design D1) — restore: `git clone` at the base then
// `git stash apply --index <oid>`. `Repos.resume`/`.join` delegate to
// this. kygit-invite (design D3/D5) adds the `.git/info/exclude` write both
// verbs share.
export { applyHandoffCheckpoint, cloneVaultRemote, excludeMessagingCacheFromGit, isMessagingCacheExcludedFromGit, readGitCommitMessage, resolveResumeTargetDir } from "./vault-restore.js";
// vault D2 (repo-first-onramp task 2.2) — lazy allocation on first push;
// the orchestration `Repos.openOrCreate` delegates to.
export { openOrCreateVault } from "./vault-open-or-create.js";
// vault D6 — push-to-create (repo-first-onramp task 4.4/4.5), the
// orchestration `Repos.resolveOrCreateAddress` delegates to.
export { pushToCreateVault } from "./vault-push-to-create.js";
// vault D6 — named-address resolution + id-pinning (repo-first-onramp
// task 4.5): local git-config pin read/write, and the resolve-or-create
// orchestrator `Repos.resolveOrCreateAddress` delegates to.
export { readPinnedVaultRepo, pinVaultRepo, resolveVaultAddress, pinRoomBinding, readPinnedRoomBinding } from "./vault-address.js";
export { prewarmVaultConnection, predialVaultObjectStore } from "./vault-prewarm.js";
// vault cross-profile repo-key scan — shared by
// every keystore-miss enrichment point; see the module doc for why this is
// a directory/filename read, never key material.
export { findLocalProfilesHoldingVaultRepo, crossProfileVaultHint } from "./vault-profile-scan.js";
// The deploy lane the interface above was always missing (change
// `vault-deploy-lane`): apply-v1 plan + commit driven through `Deploy`,
// and the entry point that engages it only for a `required` project.
export { applyWithVault, createApplyDeployLane } from "./vault-apply.js";
export * from "../namespaces/vault.crypto.js";
export { signCiDelegation } from "./ci.js";
export { signOrgAdopt, adoptOrg } from "./org-adopt.js";
export { importArchiveToCore, inspectArchive, NodeArchives, readEnvFile, verifyArchive, } from "./archives-node.js";
export { NodeCredentialsProvider } from "./credentials.js";
export { ACTIVE_WALLET_CONTEXT_ENV, NodeWallets, WalletSelectionError, assertWalletExists, findWalletBinding, readActiveWalletContext, resolveWalletSelection, selectWallet, } from "./wallets.js";
export { Diagnostics, classifyTransportFailure } from "./diagnostics.js";
export { BUZZ_DOCTOR_MAX_RESPONSE_BYTES, BUZZ_DOCTOR_MIN_NODE_MAJOR, BUZZ_DOCTOR_MIN_RUN402_VERSION, BUZZ_DOCTOR_REPAIR_MATRIX, BUZZ_DOCTOR_TIMEOUT_MS, NodeBuzz, buildBuzzDoctorReport, defaultPinnedRelayRead, isPublicAddress, normalizeNostrSubject, pinnedLookup, } from "./buzz-doctor.js";
export { BUZZ_CLI_CAPABILITIES, BUZZ_DOCTOR_ACTION_SURFACES, BUZZ_DOCTOR_CHECK_ORDER, BUZZ_DOCTOR_CONTRACT, BUZZ_DOCTOR_CONTRACT_ID, BUZZ_DOCTOR_MAX_AGE_MS, BUZZ_DOCTOR_STATUSES, validateBuzzDoctorAction, validateBuzzDoctorReport, } from "./buzz-doctor-contract.js";
export { initApiTarget, resolveScaffoldProject, runInit } from "./init.js";
export { runStatus } from "./status.js";
export { LIGHTNING_MINT_TIMEOUT_MS, describeLightning, ensureLightningWallet, readLightningBalance, revokeLightningWallet, } from "./lightning-wallet.js";
export { DOCTOR_CHECK_NAMES, assertDoctorCheckNames, buildDoctorReport, runDoctor } from "./doctor.js";
export { repoOwnVaultTarget, resolveVaultTarget } from "./vault-target.js";
export { NodeOrgs, ORG_ENV, ORG_ID_RE, PROJECT_ENV, ROOM_ENV, assertOrgIdShape, listOrgsAction, orgProvenance, orgRequiredActions, orgRequiredError, } from "./org-context.js";
export { NodeActions, resolveDeploymentTarget } from "./actions-node.js";
export { setupPaidFetch, createLazyPaidFetch, X402BalanceError } from "./paid-fetch.js";
export { listPaymentAttempts, readPaymentAttempt, PAYMENT_ATTEMPT_HEADER, } from "./payment-attempts.js";
export { Run402Action } from "../actions.js";
export * from "../app-up.js";
// Re-export the isomorphic surface so Node consumers don't need two imports.
export { Run402, Run402Error, PaymentRequired, ProjectCredentialNotFound, ProjectNotFound, Unauthorized, NotAuthorizedError, StepUpRequiredError, ApiError, NetworkError, PaymentAttemptError, PaymentBuyerError, PaymentPolicyError, X402_COMMERCE_RESULT_SCHEMA_VERSION, X402_EVIDENCE_STATUSES, X402_GATEWAY_AVAILABILITY_ERROR_CODE, X402_MUTATION_STATES, X402_PAYMENT_POLICY_ERROR_CODES, X402_RECOVERY_ACTIONS, LocalError, SecretRequiresCliError, Run402DeployError, EMPTY_STATIC_MANIFEST_METADATA, ROUTE_HTTP_METHODS, Ci, Deploy, CI_SESSION_CREDENTIALS, Orgs, ScopedOrg, Grants, PROJECT_CREDENTIAL_ERROR_CODES, PROJECT_OPERATION_AUTH_CLASSIFICATIONS, files, CI_AUDIENCE, CI_GITHUB_ACTIONS_ISSUER, CI_GITHUB_ACTIONS_PROVIDER, DEFAULT_CI_DELEGATION_CHAIN_ID, V1_CI_ALLOWED_ACTIONS, V1_CI_ALLOWED_EVENTS_DEFAULT, assertCiDeployableSpec, buildCiDelegationResourceUri, buildCiDelegationStatement, buildDeployResolveSummary, createCiSessionCredentials, githubActionsCredentials, isRun402Error, isPaymentRequired, isProjectCredentialError, isProjectCredentialExpired, isProjectCredentialInvalid, isProjectCredentialNotFound, isProjectCredentialProjectMismatch, isProjectNotFound, isUnauthorized, isNotAuthorized, isStepUpRequired, isWriteApprovalRequired, isApiError, isNetworkError, isPaymentAttemptError, isPaymentBuyerError, isPaymentPolicyError, isLocalError, isSecretRequiresCli, SECRET_RETURNING_METHODS, isDeployError, isRetryableRun402Error, isCiSessionCredentials, isGrantKeyCredentials, grantKeyFromEnv, GRANT_KEY_ENV, projectOperationAuthClassification, isDeployResolveRouteHit, isDeployResolveStaticHit, normalizeCiRouteScopes, normalizeCiDelegationValues, normalizeDeployResolveRequest, normalizeStaticManifestMetadata, summarizeDeployResult, validateCiNonce, validateCiRouteScope, validateCiSubjectMatch, withRetry, } from "../index.js";
// mpp-lightning-over-nwc: the agent's Lightning wallet client and the rail's buyer.
export { NwcWallet, NwcError, closeNwcConnections, parseNwcUri } from "./nwc.js";
export { createLightningFetch, readLightningChallenge, isLightningChargedRequest, LightningPaymentError, RUN402_MPP_LIGHTNING_PROFILE, LIGHTNING_MAX_DEBIT_SATS, } from "./lightning-paid-fetch.js";
export { scanFileContent, scanSourceTree, scanSourceFiles, resolveScanRoot, readDeclaredCapabilities, SCAN_SEVERITY, _testOnly_hallucinatedNames, _testOnly_authProperties } from "./source-scan.js";
export { resolveApplicationScope, loadApplicationScanInput } from "./app-scope.js";
export { scanDeploymentSources } from "./source-scan.js";
export { describeLocalPreflight } from "./preflight.js";
export { serializeDeployManifest } from "./manifest-export.js";
export { prepareWorkflowOutput } from "./workflow-output.js";
export { readRemoteStatus } from "./remote-status.js";
//# sourceMappingURL=index.js.map