Claude-code-plugins-plus-skills ideogram-local-dev-loop
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/ideogram-pack/skills/ideogram-local-dev-loop" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-ideogram-local-dev-loop && rm -rf "$T"
manifest:
plugins/saas-packs/ideogram-pack/skills/ideogram-local-dev-loop/SKILL.mdsource content
Ideogram Local Dev Loop
Overview
Set up a fast local development workflow for Ideogram integrations. Includes a typed client wrapper, mock server for offline development (avoids burning credits), and vitest integration for automated testing.
Prerequisites
- Completed
setupideogram-install-auth - Node.js 18+ with npm/pnpm
environment variable setIDEOGRAM_API_KEY
Instructions
Step 1: Create Project Structure
my-ideogram-project/ ├── src/ │ ├── ideogram/ │ │ ├── client.ts # Typed Ideogram client wrapper │ │ ├── types.ts # Request/response type definitions │ │ └── mock-server.ts # Local mock for offline dev │ └── index.ts ├── tests/ │ └── ideogram.test.ts ├── .env.local # Local secrets (git-ignored) ├── .env.example # Template for team ├── tsconfig.json └── package.json
Step 2: Install Dependencies
set -euo pipefail npm install dotenv npm install -D typescript tsx vitest @types/node
Step 3: Type Definitions
// src/ideogram/types.ts export type StyleType = "AUTO" | "GENERAL" | "REALISTIC" | "DESIGN" | "RENDER_3D" | "ANIME"; export type AspectRatio = "ASPECT_1_1" | "ASPECT_16_9" | "ASPECT_9_16" | "ASPECT_3_2" | "ASPECT_2_3" | "ASPECT_4_3" | "ASPECT_3_4" | "ASPECT_10_16" | "ASPECT_16_10" | "ASPECT_1_3" | "ASPECT_3_1"; export type Model = "V_1" | "V_1_TURBO" | "V_2" | "V_2_TURBO" | "V_2A" | "V_2A_TURBO"; export type MagicPrompt = "AUTO" | "ON" | "OFF"; export interface GenerateRequest { prompt: string; model?: Model; style_type?: StyleType; aspect_ratio?: AspectRatio; magic_prompt_option?: MagicPrompt; negative_prompt?: string; num_images?: number; seed?: number; } export interface ImageResult { url: string; prompt: string; resolution: string; is_image_safe: boolean; seed: number; style_type: StyleType; } export interface GenerateResponse { created: string; data: ImageResult[]; }
Step 4: Client Wrapper
// src/ideogram/client.ts import type { GenerateRequest, GenerateResponse } from "./types"; const IDEOGRAM_API = "https://api.ideogram.ai"; export class IdeogramClient { constructor(private apiKey: string) { if (!apiKey) throw new Error("IDEOGRAM_API_KEY is required"); } async generate(request: GenerateRequest): Promise<GenerateResponse> { const response = await fetch(`${IDEOGRAM_API}/generate`, { method: "POST", headers: { "Api-Key": this.apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ image_request: request }), }); if (!response.ok) { const body = await response.text(); throw new IdeogramError(response.status, body); } return response.json(); } } export class IdeogramError extends Error { constructor(public status: number, public body: string) { super(`Ideogram API error ${status}: ${body}`); this.name = "IdeogramError"; } }
Step 5: Mock Server for Offline Development
// src/ideogram/mock-server.ts import type { GenerateResponse } from "./types"; // Use this in development to avoid burning real credits export function mockGenerate(prompt: string): GenerateResponse { return { created: new Date().toISOString(), data: [{ url: `https://placehold.co/1024x1024/333/fff?text=${encodeURIComponent(prompt.slice(0, 30))}`, prompt, resolution: "1024x1024", is_image_safe: true, seed: Math.floor(Math.random() * 100000), style_type: "GENERAL", }], }; }
Step 6: Vitest Tests
// tests/ideogram.test.ts import { describe, it, expect, vi } from "vitest"; import { IdeogramClient, IdeogramError } from "../src/ideogram/client"; import { mockGenerate } from "../src/ideogram/mock-server"; describe("IdeogramClient", () => { it("should reject missing API key", () => { expect(() => new IdeogramClient("")).toThrow("IDEOGRAM_API_KEY is required"); }); it("should construct generate request correctly", async () => { const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue( new Response(JSON.stringify(mockGenerate("test")), { status: 200 }) ); const client = new IdeogramClient("test-key"); const result = await client.generate({ prompt: "test", model: "V_2" }); expect(fetchSpy).toHaveBeenCalledWith( "https://api.ideogram.ai/generate", expect.objectContaining({ method: "POST", headers: expect.objectContaining({ "Api-Key": "test-key" }), }) ); expect(result.data[0].prompt).toBe("test"); fetchSpy.mockRestore(); }); it("should throw IdeogramError on 401", async () => { vi.spyOn(globalThis, "fetch").mockResolvedValue( new Response("Unauthorized", { status: 401 }) ); const client = new IdeogramClient("bad-key"); await expect(client.generate({ prompt: "test" })).rejects.toThrow(IdeogramError); }); }); describe("mockGenerate", () => { it("should return valid response shape", () => { const result = mockGenerate("hello world"); expect(result.data).toHaveLength(1); expect(result.data[0].is_image_safe).toBe(true); expect(result.data[0].seed).toBeGreaterThan(0); }); });
Step 7: Development Scripts
{ "scripts": { "dev": "tsx watch src/index.ts", "test": "vitest run", "test:watch": "vitest --watch", "generate": "tsx src/index.ts" } }
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Module not found | Missing dependency | Run |
| Env not loaded | Missing | Copy from |
| Test timeout | Mocking not set up | Use in tests |
| Credits burned in tests | Using real API in CI | Mock in test files |
Output
- Typed client wrapper for Ideogram API
- Mock server for offline development
- Vitest test suite with fetch mocking
- Fast iteration cycle without spending credits
Resources
Next Steps
See
ideogram-sdk-patterns for production-ready code patterns.