Skip to content

Commit 393e14e

Browse files
MajorTalclaude
andcommitted
refactor(sdk)!: require x402/viem deps and align sites.deploy signature
Two related surface changes to improve SDK DX before the next minor. Move @x402/evm, @x402/fetch, mppx, and viem from optionalDependencies to dependencies in sdk/package.json. Optional deps failed silently on fresh installs (e.g. npm ci --omit=optional), leaving run402() looking healthy until the first paid request returned PaymentRequired instead of auto-paying. Hard deps now fail loudly at install time. Align sites.deploy with the rest of the SDK: every other method takes (projectId, opts) with payload inside opts. sites.deploy was the only outlier at (project, files, opts). New shape is sites.deploy(projectId, { files, target?, inherit? }). Updates the MCP tool, CLI, tests, and README example. BREAKING: @run402/sdk sites.deploy callers must pass files inside the options object. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cd06d8b commit 393e14e

6 files changed

Lines changed: 17 additions & 20 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ import { run402 } from "@run402/sdk/node";
3737
const r = run402();
3838
const project = await r.projects.provision({ tier: "prototype" });
3939
await r.blobs.put(project.project_id, "hello.txt", { content: "hi" });
40-
await r.sites.deploy(project.project_id, [
41-
{ file: "index.html", data: "<h1>hello</h1>" },
42-
]);
40+
await r.sites.deploy(project.project_id, {
41+
files: [{ file: "index.html", data: "<h1>hello</h1>" }],
42+
});
4343
```
4444

4545
17 namespaces: `projects`, `blobs`, `functions`, `secrets`, `subdomains`, `domains`, `sites`, `service`, `tier`, `allowance`, `ai`, `auth`, `senderDomain`, `billing`, `apps`, `email` (+ `webhooks`), `contracts`, `admin`.

cli/lib/sites.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ async function deploy(args) {
106106
allowanceAuthHeaders("/deployments/v1");
107107

108108
try {
109-
const data = await getSdk().sites.deploy(projectId, manifest.files, {
109+
const data = await getSdk().sites.deploy(projectId, {
110+
files: manifest.files,
110111
target: opts.target,
111112
inherit: opts.inherit,
112113
});

sdk/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
],
2626
"dependencies": {
2727
"@noble/curves": "^2.0.1",
28-
"@noble/hashes": "^2.0.1"
29-
},
30-
"optionalDependencies": {
28+
"@noble/hashes": "^2.0.1",
3129
"@x402/evm": "^2.6.0",
3230
"@x402/fetch": "^2.6.0",
3331
"mppx": "^0.4.7",

sdk/src/namespaces/secrets.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe("domains (custom)", () => {
132132
describe("sites", () => {
133133
it("deploy POSTs project+files", async () => {
134134
const { fetch, calls } = mockFetch(() => json({ deployment_id: "dpl_1", url: "https://dpl_1.run402.com" }));
135-
await sdk(fetch).sites.deploy("prj_k", [{ file: "index.html", data: "<p>hi</p>" }]);
135+
await sdk(fetch).sites.deploy("prj_k", { files: [{ file: "index.html", data: "<p>hi</p>" }] });
136136
assert.equal(calls[0]!.url, "https://api.test/deployments/v1");
137137
const body = JSON.parse(calls[0]!.body as string);
138138
assert.equal(body.project, "prj_k");
@@ -142,7 +142,7 @@ describe("sites", () => {
142142

143143
it("deploy includes inherit when set", async () => {
144144
const { fetch, calls } = mockFetch(() => json({ deployment_id: "d", url: "u" }));
145-
await sdk(fetch).sites.deploy("prj_k", [{ file: "i.html", data: "x" }], { inherit: true, target: "prod" });
145+
await sdk(fetch).sites.deploy("prj_k", { files: [{ file: "i.html", data: "x" }], inherit: true, target: "prod" });
146146
const body = JSON.parse(calls[0]!.body as string);
147147
assert.equal(body.inherit, true);
148148
assert.equal(body.target, "prod");

sdk/src/namespaces/sites.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export interface SiteFile {
1717
}
1818

1919
export interface SiteDeployOptions {
20+
/** Files to deploy. Paths are relative to the site root. */
21+
files: SiteFile[];
2022
/** Deployment target label, e.g. `"production"`. */
2123
target?: string;
2224
/**
@@ -49,12 +51,8 @@ export class Sites {
4951
* (x402 in Node when a tier purchase is required; typically free with an
5052
* active tier).
5153
*/
52-
async deploy(
53-
project: string,
54-
files: SiteFile[],
55-
opts: SiteDeployOptions = {},
56-
): Promise<SiteDeployResult> {
57-
const body: Record<string, unknown> = { project, files };
54+
async deploy(projectId: string, opts: SiteDeployOptions): Promise<SiteDeployResult> {
55+
const body: Record<string, unknown> = { project: projectId, files: opts.files };
5856
if (opts.target !== undefined) body.target = opts.target;
5957
if (opts.inherit) body.inherit = true;
6058

src/tools/deploy-site.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ export async function handleDeploySite(args: {
4040
if ("error" in auth) return auth.error;
4141

4242
try {
43-
const body = await getSdk().sites.deploy(
44-
args.project,
45-
args.files as Array<{ file: string; data: string; encoding?: "utf-8" | "base64" }>,
46-
{ target: args.target, inherit: args.inherit },
47-
);
43+
const body = await getSdk().sites.deploy(args.project, {
44+
files: args.files as Array<{ file: string; data: string; encoding?: "utf-8" | "base64" }>,
45+
target: args.target,
46+
inherit: args.inherit,
47+
});
4848

4949
// Persist the last deployment ID on the project (MCP-local side effect).
5050
updateProject(args.project, { last_deployment_id: body.deployment_id });

0 commit comments

Comments
 (0)