UNPKG

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.

285 lines • 22.2 kB
/** * `@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"; export { ALL_ON_CHAIN_BALANCE_KEYS, railBalanceKeys, readOnChainBalances, sumOnChainBalances, } from "./onchain-balances.js"; export { PATH_USD, TEMPO_MAINNET, TEMPO_MODERATO, requestTempoFaucet } from "./tempo.js"; export { adoptKmsKey, personalMessageSignerFor, resolveWalletAccount, walletCanSign, walletSignerKind, } from "./signers/index.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, ensureCheckpointObjects, 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 { payX402Lightning, readX402LightningOffer } from "./lightning-x402-lnbtc.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, ValueTransferRequiresCliError, 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