Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions packages/sdk/generated/domain-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
},
"Project": {
"description": "A Stitch project containing screens.",
"constructorParams": [
"projectId"
],
"constructorParams": ["projectId"],
"fieldMapping": {
"projectId": {
"from": "name",
Expand All @@ -26,10 +24,7 @@
},
"Screen": {
"description": "A generated UI screen. Provides access to HTML and screenshots.",
"constructorParams": [
"projectId",
"screenId"
],
"constructorParams": ["projectId", "screenId"],
"fieldMapping": {
"projectId": {
"from": "projectId"
Expand Down Expand Up @@ -103,7 +98,7 @@
"projection": [
{
"prop": "outputComponents",
"index": 0
"find": "design"
},
{
"prop": "design"
Expand Down Expand Up @@ -144,7 +139,7 @@
"projection": [
{
"prop": "outputComponents",
"index": 0
"find": "design"
},
{
"prop": "design"
Expand Down Expand Up @@ -320,4 +315,4 @@
}
}
]
}
}
6 changes: 3 additions & 3 deletions packages/sdk/generated/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* AUTO-GENERATED by scripts/generate-sdk.ts
DO NOT EDIT — changes will be overwritten.

Source: tools-manifest.json (sha256:1f84b31604f9...)
domain-map.json (sha256:99b823ad9306...)
Generated: 2026-03-19T18:56:19.253Z
Source: tools-manifest.json (sha256:30054fa9d9b0...)
domain-map.json (sha256:570af21602ed...)
Generated: 2026-03-22T10:14:00.475Z
*/
export { Stitch } from "./stitch.js";
export { Project } from "./project.js";
Expand Down
8 changes: 4 additions & 4 deletions packages/sdk/generated/src/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* AUTO-GENERATED by scripts/generate-sdk.ts
DO NOT EDIT — changes will be overwritten.

Source: tools-manifest.json (sha256:1f84b31604f9...)
domain-map.json (sha256:99b823ad9306...)
Generated: 2026-03-19T18:56:19.253Z
Source: tools-manifest.json (sha256:30054fa9d9b0...)
domain-map.json (sha256:570af21602ed...)
Generated: 2026-03-22T10:14:00.475Z
*/
import { type StitchToolClient } from "../../src/client.js";
import { StitchError } from "../../src/spec/errors.js";
Expand Down Expand Up @@ -37,7 +37,7 @@ export class Project {
async generate(prompt: string, deviceType?: "DEVICE_TYPE_UNSPECIFIED" | "MOBILE" | "DESKTOP" | "TABLET" | "AGNOSTIC", modelId?: "MODEL_ID_UNSPECIFIED" | "GEMINI_3_PRO" | "GEMINI_3_FLASH"): Promise<Screen> {
try {
const raw = await this.client.callTool<any>("generate_screen_from_text", { projectId: this.projectId, prompt, deviceType, modelId });
return new Screen(this.client, { ...raw.outputComponents[0].design.screens[0], projectId: this.projectId });
return new Screen(this.client, { ...raw.outputComponents.find((c: any) => c.design).design.screens[0], projectId: this.projectId });
} catch (error) {
throw StitchError.fromUnknown(error);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/sdk/generated/src/screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* AUTO-GENERATED by scripts/generate-sdk.ts
DO NOT EDIT — changes will be overwritten.

Source: tools-manifest.json (sha256:1f84b31604f9...)
domain-map.json (sha256:99b823ad9306...)
Generated: 2026-03-19T18:56:19.253Z
Source: tools-manifest.json (sha256:30054fa9d9b0...)
domain-map.json (sha256:570af21602ed...)
Generated: 2026-03-22T10:14:00.475Z
*/
import { type StitchToolClient } from "../../src/client.js";
import { StitchError } from "../../src/spec/errors.js";
Expand Down Expand Up @@ -38,7 +38,7 @@ export class Screen {
async edit(prompt: string, deviceType?: "DEVICE_TYPE_UNSPECIFIED" | "MOBILE" | "DESKTOP" | "TABLET" | "AGNOSTIC", modelId?: "MODEL_ID_UNSPECIFIED" | "GEMINI_3_PRO" | "GEMINI_3_FLASH"): Promise<Screen> {
try {
const raw = await this.client.callTool<any>("edit_screens", { projectId: this.projectId, selectedScreenIds: [this.screenId], prompt, deviceType, modelId });
return new Screen(this.client, { ...raw.outputComponents[0].design.screens[0], projectId: this.projectId });
return new Screen(this.client, { ...raw.outputComponents.find((c: any) => c.design).design.screens[0], projectId: this.projectId });
} catch (error) {
throw StitchError.fromUnknown(error);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/generated/src/stitch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* AUTO-GENERATED by scripts/generate-sdk.ts
DO NOT EDIT — changes will be overwritten.

Source: tools-manifest.json (sha256:1f84b31604f9...)
domain-map.json (sha256:99b823ad9306...)
Generated: 2026-03-19T18:56:19.253Z
Source: tools-manifest.json (sha256:30054fa9d9b0...)
domain-map.json (sha256:570af21602ed...)
Generated: 2026-03-22T10:14:00.475Z
*/
import { type StitchToolClient } from "../../src/client.js";
import { StitchError } from "../../src/spec/errors.js";
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/generated/src/tool-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* AUTO-GENERATED by scripts/generate-sdk.ts
DO NOT EDIT — changes will be overwritten.

Source: tools-manifest.json (sha256:1f84b31604f9...)
domain-map.json (sha256:99b823ad9306...)
Generated: 2026-03-19T18:56:19.253Z
Source: tools-manifest.json (sha256:30054fa9d9b0...)
domain-map.json (sha256:570af21602ed...)
Generated: 2026-03-22T10:14:00.475Z
*/
/** JSON Schema property descriptor for a tool parameter. */
export interface ToolPropertySchema {
Expand Down
10 changes: 5 additions & 5 deletions packages/sdk/generated/stitch-sdk.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
"serverUrl": "https://stitch.googleapis.com/mcp"
},
"generated": {
"generatedAt": "2026-03-19T18:56:19.351Z",
"sourceHash": "sha256:06c97f633a04942efd348aa1634356c9f5f0fd3e16d33802bffe7e8e9a650905",
"generatedAt": "2026-03-22T10:12:33.217Z",
"sourceHash": "sha256:8cc5d1bc07cb437c5cb8f4d9bdd03c3f23d07fc978ac59a709b6c80b5a31f561",
"manifestHash": "sha256:1f84b31604f95580325952f0c150a3e045543fad2596e9a4d8ed15c07e0cbf9b",
"domainMapHash": "sha256:99b823ad930620c571a9443c7b956f90b092d626be9ce2319d7a7bfe3a2e3db4",
"domainMapHash": "sha256:b207e213e3e06c9154884320c78ffc515bb830b3d94403f0c0a54352e3d87145",
"fileCount": 5
},
"domainMap": {
"generatedAt": "2026-03-19T18:56:19.351Z",
"sourceHash": "sha256:99b823ad930620c571a9443c7b956f90b092d626be9ce2319d7a7bfe3a2e3db4",
"generatedAt": "2026-03-22T10:12:33.217Z",
"sourceHash": "sha256:b207e213e3e06c9154884320c78ffc515bb830b3d94403f0c0a54352e3d87145",
"manifestHash": "sha256:1f84b31604f95580325952f0c150a3e045543fad2596e9a4d8ed15c07e0cbf9b",
"classCount": 3,
"bindingCount": 9
Expand Down
120 changes: 85 additions & 35 deletions packages/sdk/test/unit/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ describe("SDK Unit Tests", () => {
});

describe("Screen Class", () => {
const screenData = { id: "screen-123", name: "Login", htmlCode: { downloadUrl: "https://cached.example.com/html" }, screenshot: { downloadUrl: "https://cached.example.com/img.png" }, projectId: "proj-123" };
const screenData = {
id: "screen-123",
name: "Login",
htmlCode: { downloadUrl: "https://cached.example.com/html" },
screenshot: { downloadUrl: "https://cached.example.com/img.png" },
projectId: "proj-123",
};
const projectId = "proj-123";

it("getHtml should return cached HTML from data if available", async () => {
Expand All @@ -45,10 +51,14 @@ describe("SDK Unit Tests", () => {
});

it("getHtml should call get_screen if no cached htmlCode", async () => {
const screen = new Screen(mockClient, { id: "screen-123", name: "Login", projectId });
const screen = new Screen(mockClient, {
id: "screen-123",
name: "Login",
projectId,
});

(mockClient.callTool as Mock).mockResolvedValue({
htmlCode: { downloadUrl: "https://api.example.com/html" }
htmlCode: { downloadUrl: "https://api.example.com/html" },
});

const result = await screen.getHtml();
Expand All @@ -71,10 +81,14 @@ describe("SDK Unit Tests", () => {
});

it("getImage should call get_screen if no cached screenshot", async () => {
const screen = new Screen(mockClient, { id: "screen-123", name: "Login", projectId });
const screen = new Screen(mockClient, {
id: "screen-123",
name: "Login",
projectId,
});

(mockClient.callTool as Mock).mockResolvedValue({
screenshot: { downloadUrl: "https://api.example.com/image.png" }
screenshot: { downloadUrl: "https://api.example.com/image.png" },
});

const result = await screen.getImage();
Expand All @@ -87,13 +101,16 @@ describe("SDK Unit Tests", () => {
expect(result).toBe("https://api.example.com/image.png");
});


it("getHtml should fallback to empty string when raw.htmlCode.downloadUrl is missing", async () => {
const screen = new Screen(mockClient, { id: "screen-123", name: "Login", projectId });
const screen = new Screen(mockClient, {
id: "screen-123",
name: "Login",
projectId,
});

// Mock missing htmlCode / downloadUrl
(mockClient.callTool as Mock).mockResolvedValue({
htmlCode: {}
htmlCode: {},
});

const result = await screen.getHtml();
Expand All @@ -107,8 +124,14 @@ describe("SDK Unit Tests", () => {
});

it("getHtml should throw StitchError on failure", async () => {
const screen = new Screen(mockClient, { id: "screen-123", name: "Login", projectId });
(mockClient.callTool as Mock).mockRejectedValue(new Error("Network failure"));
const screen = new Screen(mockClient, {
id: "screen-123",
name: "Login",
projectId,
});
(mockClient.callTool as Mock).mockRejectedValue(
new Error("Network failure"),
);

await expect(screen.getHtml()).rejects.toThrow("Network failure");
});
Expand All @@ -117,9 +140,20 @@ describe("SDK Unit Tests", () => {
const screen = new Screen(mockClient, screenData);

(mockClient.callTool as Mock).mockResolvedValue({
outputComponents: [{
design: { screens: [{ id: "edited-screen", htmlCode: "<div>Edited</div>", projectId }] },
}],
outputComponents: [
{ designSystem: { name: "ds" } },
{
design: {
screens: [
{
id: "edited-screen",
htmlCode: "<div>Edited</div>",
projectId,
},
],
},
},
],
projectId,
sessionId: "session-1",
});
Expand All @@ -139,14 +173,16 @@ describe("SDK Unit Tests", () => {
const screen = new Screen(mockClient, screenData);

(mockClient.callTool as Mock).mockResolvedValue({
outputComponents: [{
design: {
screens: [
{ id: "var-1", htmlCode: "<div>V1</div>", projectId },
{ id: "var-2", htmlCode: "<div>V2</div>", projectId },
],
outputComponents: [
{
design: {
screens: [
{ id: "var-1", htmlCode: "<div>V1</div>", projectId },
{ id: "var-2", htmlCode: "<div>V2</div>", projectId },
],
},
},
}],
],
projectId,
sessionId: "session-1",
});
Expand Down Expand Up @@ -205,9 +241,17 @@ describe("SDK Unit Tests", () => {

(mockClient.callTool as Mock).mockResolvedValue({
outputComponents: [
{ designSystem: { name: "ds" } },
{
design: {
screens: [{ id: "new-screen-1", name: "Generated", htmlCode: "<div>test</div>", projectId }],
screens: [
{
id: "new-screen-1",
name: "Generated",
htmlCode: "<div>test</div>",
projectId,
},
],
},
},
],
Expand All @@ -217,25 +261,28 @@ describe("SDK Unit Tests", () => {

const result = await project.generate(prompt);

expect(mockClient.callTool).toHaveBeenCalledWith("generate_screen_from_text", {
projectId: projectId,
prompt: prompt,
deviceType: undefined,
modelId: undefined
});
expect(mockClient.callTool).toHaveBeenCalledWith(
"generate_screen_from_text",
{
projectId: projectId,
prompt: prompt,
deviceType: undefined,
modelId: undefined,
},
);

expect(result).toBeInstanceOf(Screen);
expect(result.id).toBe("new-screen-1");
expect(result.projectId).toBe(projectId);
});


it("generate should handle missing design.screens in outputComponents gracefully", async () => {
const project = new Project(mockClient, projectId);

// Mock with missing screens array
(mockClient.callTool as Mock).mockResolvedValue({
outputComponents: [
{ designSystem: { name: "ds" } },
{
design: {
// screens is missing
Expand All @@ -257,16 +304,16 @@ describe("SDK Unit Tests", () => {
const mockResponse = {
screens: [
{ id: "s1", sourceScreen: "S1", projectId },
{ id: "s2", sourceScreen: "S2", projectId }
]
{ id: "s2", sourceScreen: "S2", projectId },
],
};

(mockClient.callTool as Mock).mockResolvedValue(mockResponse);

const result = await project.screens();

expect(mockClient.callTool).toHaveBeenCalledWith("list_screens", {
projectId: projectId
projectId: projectId,
});

expect(result).toHaveLength(2);
Expand All @@ -275,7 +322,6 @@ describe("SDK Unit Tests", () => {
expect(result[0].id).toBe("s1");
});


it("screens should return [] when returned data has no screens array", async () => {
const project = new Project(mockClient, projectId);

Expand All @@ -285,7 +331,7 @@ describe("SDK Unit Tests", () => {
const result = await project.screens();

expect(mockClient.callTool).toHaveBeenCalledWith("list_screens", {
projectId: projectId
projectId: projectId,
});

expect(result).toEqual([]);
Expand All @@ -294,9 +340,13 @@ describe("SDK Unit Tests", () => {
it("generate should throw StitchError on failure", async () => {
const project = new Project(mockClient, projectId);

(mockClient.callTool as Mock).mockRejectedValue(new Error("Generation failed"));
(mockClient.callTool as Mock).mockRejectedValue(
new Error("Generation failed"),
);

await expect(project.generate("test")).rejects.toThrow("Generation failed");
await expect(project.generate("test")).rejects.toThrow(
"Generation failed",
);
});
});
});
Loading