climage 0.1.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -111,9 +111,17 @@ var xaiProvider = {
111
111
  const results = [];
112
112
  for (let i = 0; i < json.data.length; i++) {
113
113
  const img = json.data[i];
114
+ if (!img) continue;
114
115
  if (img.url) {
115
116
  const { bytes, mimeType } = await downloadBytes(img.url);
116
- results.push({ provider: "xai", model, index: i, url: img.url, bytes, mimeType });
117
+ results.push({
118
+ provider: "xai",
119
+ model,
120
+ index: i,
121
+ url: img.url,
122
+ bytes,
123
+ ...mimeType !== void 0 ? { mimeType } : {}
124
+ });
117
125
  continue;
118
126
  }
119
127
  if (img.b64_json) {
@@ -173,7 +181,15 @@ var falProvider = {
173
181
  const img = images[i];
174
182
  if (!img?.url) continue;
175
183
  const { bytes, mimeType } = await downloadBytes2(img.url);
176
- out.push({ provider: "fal", model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType });
184
+ const finalMimeType = img.content_type ?? mimeType;
185
+ out.push({
186
+ provider: "fal",
187
+ model,
188
+ index: i,
189
+ url: img.url,
190
+ bytes,
191
+ ...finalMimeType !== void 0 ? { mimeType: finalMimeType } : {}
192
+ });
177
193
  }
178
194
  if (!out.length) throw new Error("fal returned images but none were downloadable");
179
195
  return out;
@@ -224,15 +240,108 @@ var googleProvider = {
224
240
  const rawBytes = img?.image?.imageBytes;
225
241
  if (!rawBytes) continue;
226
242
  const bytes = typeof rawBytes === "string" ? Uint8Array.from(Buffer.from(rawBytes, "base64")) : rawBytes;
227
- out.push({ provider: "google", model, index: i, bytes, mimeType: mimeForFormat(req.format) });
243
+ out.push({
244
+ provider: "google",
245
+ model,
246
+ index: i,
247
+ bytes,
248
+ mimeType: mimeForFormat(req.format)
249
+ });
228
250
  }
229
251
  if (!out.length) throw new Error("Google returned images but no bytes were present");
230
252
  return out;
231
253
  }
232
254
  };
233
255
 
256
+ // src/providers/openai.ts
257
+ var OPENAI_API_BASE = "https://api.openai.com/v1";
258
+ function getOpenAIApiKey(env) {
259
+ return env.OPENAI_API_KEY || env.OPENAI_KEY;
260
+ }
261
+ async function downloadBytes3(url) {
262
+ const res = await fetch(url);
263
+ if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);
264
+ const ab = await res.arrayBuffer();
265
+ const ct = res.headers.get("content-type");
266
+ return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };
267
+ }
268
+ function mapAspectRatioToSize(aspectRatio, model) {
269
+ if (!aspectRatio) return void 0;
270
+ const ar = aspectRatio.trim();
271
+ if (model?.startsWith("gpt-image")) {
272
+ if (ar === "1:1") return "1024x1024";
273
+ if (ar === "3:2" || ar === "4:3" || ar === "16:9") return "1536x1024";
274
+ if (ar === "2:3" || ar === "3:4" || ar === "9:16") return "1024x1536";
275
+ } else if (model === "dall-e-3") {
276
+ if (ar === "1:1") return "1024x1024";
277
+ if (ar === "16:9" || ar === "4:3") return "1792x1024";
278
+ if (ar === "9:16" || ar === "3:4") return "1024x1792";
279
+ }
280
+ return void 0;
281
+ }
282
+ var openaiProvider = {
283
+ id: "openai",
284
+ displayName: "OpenAI (GPT Image / DALL-E)",
285
+ isAvailable(env) {
286
+ return Boolean(getOpenAIApiKey(env));
287
+ },
288
+ async generate(req, env) {
289
+ const apiKey = getOpenAIApiKey(env);
290
+ if (!apiKey) throw new Error("Missing OpenAI API key. Set OPENAI_API_KEY.");
291
+ const model = req.model ?? "gpt-image-1";
292
+ const size = mapAspectRatioToSize(req.aspectRatio, model);
293
+ const body = {
294
+ model,
295
+ prompt: req.prompt,
296
+ n: req.n,
297
+ ...size ? { size } : {},
298
+ // gpt-image-1 doesn't support response_format, defaults to b64_json
299
+ // dall-e-2/3 support response_format
300
+ ...!model.startsWith("gpt-image") ? { response_format: "url" } : {}
301
+ };
302
+ const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {
303
+ method: "POST",
304
+ headers: {
305
+ authorization: `Bearer ${apiKey}`,
306
+ "content-type": "application/json"
307
+ },
308
+ body: JSON.stringify(body)
309
+ });
310
+ if (!res.ok) {
311
+ const txt = await res.text().catch(() => "");
312
+ throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);
313
+ }
314
+ const json = await res.json();
315
+ if (!json.data?.length) throw new Error("OpenAI returned no images");
316
+ const results = [];
317
+ for (let i = 0; i < json.data.length; i++) {
318
+ const img = json.data[i];
319
+ if (!img) continue;
320
+ if (img.url) {
321
+ const dl = await downloadBytes3(img.url);
322
+ results.push({
323
+ provider: "openai",
324
+ model,
325
+ index: i,
326
+ url: img.url,
327
+ bytes: dl.bytes,
328
+ ...dl.mimeType ? { mimeType: dl.mimeType } : {}
329
+ });
330
+ continue;
331
+ }
332
+ if (img.b64_json) {
333
+ const bytes = Uint8Array.from(Buffer.from(img.b64_json, "base64"));
334
+ results.push({ provider: "openai", model, index: i, bytes });
335
+ continue;
336
+ }
337
+ throw new Error("OpenAI returned image without url or b64_json");
338
+ }
339
+ return results;
340
+ }
341
+ };
342
+
234
343
  // src/core/router.ts
235
- var providers = [googleProvider, xaiProvider, falProvider];
344
+ var providers = [googleProvider, xaiProvider, falProvider, openaiProvider];
236
345
  function listProviders() {
237
346
  return [...providers];
238
347
  }
@@ -244,7 +353,10 @@ function pickProvider(id, env) {
244
353
  return p2;
245
354
  }
246
355
  const p = providers.find((pp) => pp.isAvailable(env));
247
- if (!p) throw new Error("No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.");
356
+ if (!p)
357
+ throw new Error(
358
+ "No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment."
359
+ );
248
360
  return p;
249
361
  }
250
362
  function normalizeOptions(prompt, opts) {
@@ -309,6 +421,7 @@ Env:
309
421
  GEMINI_API_KEY (or GOOGLE_API_KEY)
310
422
  XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)
311
423
  FAL_KEY (or FAL_API_KEY)
424
+ OPENAI_API_KEY
312
425
 
313
426
  Examples:
314
427
  npx climage "make image of kitten"
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process'\n\nimport { generateImage, listProviders } from './index.js'\nimport type { GenerateOptions, ProviderId } from './core/types.js'\n\nfunction usage(code = 0) {\n const providers = listProviders()\n .map((p) => `${p.id}`)\n .join(', ')\n\n // eslint-disable-next-line no-console\n console.log(`climage\n\nUsage:\n climage \"prompt\"\n\nOptions:\n --provider <auto|${providers}> Provider (default: auto)\n --model <id> Model id (provider-specific)\n --n <1..10> Number of images (default: 1)\n --format <png|jpg|webp> Output format (default: png)\n --out <path> Output file path (only when n=1)\n --outDir <dir> Output directory (default: .)\n --name <text> Base name (slugified); default: prompt\n --aspect-ratio <w:h> Aspect ratio (xAI supports e.g. 4:3)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\n\nEnv:\n GEMINI_API_KEY (or GOOGLE_API_KEY)\n XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)\n FAL_KEY (or FAL_API_KEY)\n\nExamples:\n npx climage \"make image of kitten\"\n npx climage \"A cat in a tree\" --provider xai --n 4\n`)\n process.exit(code)\n}\n\nfunction parseArgs(argv: string[]): { prompt: string; opts: GenerateOptions; json: boolean } {\n const args = [...argv]\n const opts: GenerateOptions = {}\n let json = false\n\n const take = (name: string): string => {\n const v = args.shift()\n if (!v) throw new Error(`Missing value for ${name}`)\n return v\n }\n\n while (args.length) {\n const a = args[0]\n if (!a) break\n if (a === '-h' || a === '--help') usage(0)\n if (a === '--json') {\n json = true\n args.shift()\n continue\n }\n if (!a.startsWith('-')) break\n\n args.shift()\n switch (a) {\n case '--provider':\n opts.provider = take(a) as ProviderId\n break\n case '--model':\n opts.model = take(a)\n break\n case '--n':\n opts.n = Number(take(a))\n break\n case '--format':\n opts.format = take(a) as any\n break\n case '--out':\n opts.out = take(a)\n break\n case '--outDir':\n opts.outDir = take(a)\n break\n case '--name':\n opts.name = take(a)\n break\n case '--aspect-ratio':\n opts.aspectRatio = take(a)\n break\n case '--verbose':\n opts.verbose = true\n break\n default:\n throw new Error(`Unknown option: ${a}`)\n }\n }\n\n const prompt = args.join(' ').trim()\n if (!prompt) throw new Error('Missing prompt')\n\n return { prompt, opts, json }\n}\n\nasync function main() {\n try {\n const { prompt, opts, json } = parseArgs(process.argv.slice(2))\n const images = await generateImage(prompt, opts)\n\n if (json) {\n process.stdout.write(JSON.stringify({ images }, null, 2) + '\\n')\n return\n }\n\n for (const img of images) {\n process.stdout.write(img.filePath + '\\n')\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n process.stderr.write(`climage: ${msg}\\n`)\n process.stderr.write(`Run: climage --help\\n`)\n process.exit(1)\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain()\n","import path from 'node:path'\n\nimport type { GenerateOptions, GenerateRequest, GeneratedImage, GeneratedImagePartial, Provider, ProviderEnv, ProviderId } from './types.js'\nimport { loadEnv } from './env.js'\nimport { makeOutputPath, resolveOutDir, writeImageFile } from './output.js'\nimport { slugify, timestampLocalCompact } from './strings.js'\nimport { xaiProvider } from '../providers/xai.js'\nimport { falProvider } from '../providers/fal.js'\nimport { googleProvider } from '../providers/google.js'\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider]\n\nexport function listProviders(): Provider[] {\n return [...providers]\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id)\n if (!p) throw new Error(`Unknown provider: ${id}`)\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`)\n return p\n }\n\n const p = providers.find((pp) => pp.isAvailable(env))\n if (!p) throw new Error('No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.')\n return p\n}\n\nfunction normalizeOptions(prompt: string, opts: GenerateOptions): GenerateRequest {\n const nRaw = opts.n ?? 1\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)))\n\n const format = opts.format ?? 'png'\n const outDir = resolveOutDir(opts.outDir ?? '.')\n const timestamp = timestampLocalCompact()\n\n const nameBase = slugify(opts.name ?? prompt)\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n }\n}\n\nexport async function generateImage(prompt: string, opts: GenerateOptions = {}): Promise<GeneratedImage[]> {\n const { env } = loadEnv(process.cwd())\n const req = normalizeOptions(prompt, opts)\n const provider = pickProvider(req.provider, env)\n\n const partials = await provider.generate(req, env)\n const images: GeneratedImage[] = []\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedImagePartial | undefined = partials[i]\n if (!p) continue\n const filePath = makeOutputPath(req, i)\n await writeImageFile(filePath, p.bytes)\n images.push({ ...p, filePath })\n }\n\n return images\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport dotenv from 'dotenv'\n\nimport type { ProviderEnv } from './types.js'\n\nexport type EnvLoadResult = {\n env: ProviderEnv\n loadedFiles: string[]\n}\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local']\n const loadedFiles: string[] = []\n\n for (const name of candidates) {\n const p = path.join(cwd, name)\n if (!fs.existsSync(p)) continue\n dotenv.config({ path: p, override: false })\n loadedFiles.push(p)\n }\n\n return { env: process.env as ProviderEnv, loadedFiles }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { GeneratedImage, GenerateRequest } from './types.js'\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg'\n case 'png':\n return 'png'\n case 'webp':\n return 'webp'\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir)\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format)\n if (req.out) return path.resolve(process.cwd(), req.out)\n\n const base = `${req.nameBase}-${req.timestamp}`\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : ''\n const filename = `${base}${suffix}.${ext}`\n return path.join(req.outDir, filename)\n}\n\nexport async function writeImageFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n await fs.writeFile(filePath, bytes)\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url)\n u.search = ''\n return u.toString()\n } catch {\n return url\n }\n}\n\nexport function toJsonResult(images: GeneratedImage[]) {\n return {\n images: images.map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n })),\n }\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n if (!s) return 'image'\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0')\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n )\n}\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nconst XAI_API_BASE = 'https://api.x.ai/v1'\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY\n}\n\ntype XaiImage = {\n url?: string\n b64_json?: string\n}\n\ntype XaiImagesResponse = {\n created?: number\n data: XaiImage[]\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`xAI image download failed (${res.status})`)\n const ab = await res.arrayBuffer()\n const ct = res.headers.get('content-type') || undefined\n return { bytes: new Uint8Array(ab), mimeType: ct }\n}\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI (grok-imagine-image)',\n isAvailable(env) {\n return Boolean(getXaiApiKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env)\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).')\n\n const model = req.model ?? 'grok-imagine-image'\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n }\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '')\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`)\n }\n\n const json = (await res.json()) as XaiImagesResponse\n if (!json.data?.length) throw new Error('xAI returned no images')\n\n const results = [] as Array<{ provider: 'xai'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i]\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url)\n results.push({ provider: 'xai', model, index: i, url: img.url, bytes, mimeType })\n continue\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'))\n results.push({ provider: 'xai', model, index: i, bytes })\n continue\n }\n throw new Error('xAI returned image without url or b64_json')\n }\n\n return results\n },\n}\n","import { fal } from '@fal-ai/client'\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY\n}\n\ntype FalImage = {\n url: string\n content_type?: string\n}\n\ntype FalResult = {\n images?: FalImage[]\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`fal image download failed (${res.status})`)\n const ab = await res.arrayBuffer()\n const ct = res.headers.get('content-type') || undefined\n return { bytes: new Uint8Array(ab), mimeType: ct }\n}\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n isAvailable(env) {\n return Boolean(getFalKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env)\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).')\n\n // Configure credentials at runtime\n fal.config({ credentials: key })\n\n // Default model: Flux dev (fast + popular). Can be overridden via --model.\n const model = req.model ?? 'fal-ai/flux/dev'\n\n // Map common aspect ratios to fal enums when possible.\n // If user passes e.g. 4:3, use landscape_4_3.\n let image_size: any = undefined\n if (req.aspectRatio) {\n const ar = req.aspectRatio.trim()\n if (ar === '1:1') image_size = 'square'\n else if (ar === '4:3') image_size = 'landscape_4_3'\n else if (ar === '16:9') image_size = 'landscape_16_9'\n else if (ar === '3:4') image_size = 'portrait_4_3'\n else if (ar === '9:16') image_size = 'portrait_16_9'\n }\n\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n ...(image_size ? { image_size } : {}),\n // Some fal models support \"num_images\"; flux/dev returns images array length.\n ...(req.n ? { num_images: req.n } : {}),\n }\n\n const result = (await fal.subscribe(model, { input })) as { data: FalResult }\n\n const images = result?.data?.images\n if (!images?.length) throw new Error('fal returned no images')\n\n const out = [] as Array<{ provider: 'fal'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < Math.min(images.length, req.n); i++) {\n const img = images[i]\n if (!img?.url) continue\n const { bytes, mimeType } = await downloadBytes(img.url)\n out.push({ provider: 'fal', model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType })\n }\n\n if (!out.length) throw new Error('fal returned images but none were downloadable')\n\n return out\n },\n}\n","import { GoogleGenAI } from '@google/genai'\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY\n}\n\nfunction mimeForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg'\n case 'webp':\n return 'image/webp'\n case 'png':\n default:\n return 'image/png'\n }\n}\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen)',\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env)\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).')\n\n const ai = new GoogleGenAI({ apiKey })\n\n // Default to Imagen for pure text-to-image.\n const model = req.model ?? 'imagen-4.0-generate-001'\n\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForFormat(req.format),\n // Note: aspect ratio / size varies by model. Add later.\n },\n })\n\n const imgs = res.generatedImages\n if (!imgs?.length) throw new Error('Google generateImages returned no images')\n\n const out = [] as Array<{ provider: 'google'; model?: string; index: number; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i]\n const rawBytes = img?.image?.imageBytes\n if (!rawBytes) continue\n // SDK returns base64 string, decode to binary\n const bytes = typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes\n out.push({ provider: 'google', model, index: i, bytes, mimeType: mimeForFormat(req.format) })\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present')\n return out\n },\n}\n"],"mappings":"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","names":["process","path","process","fs","path","downloadBytes","p","path","providers","process"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process';\n\nimport { generateImage, listProviders } from './index.js';\nimport type { GenerateOptions, ProviderId } from './core/types.js';\n\nfunction usage(code = 0) {\n const providers = listProviders()\n .map((p) => `${p.id}`)\n .join(', ');\n\n // eslint-disable-next-line no-console\n console.log(`climage\n\nUsage:\n climage \"prompt\"\n\nOptions:\n --provider <auto|${providers}> Provider (default: auto)\n --model <id> Model id (provider-specific)\n --n <1..10> Number of images (default: 1)\n --format <png|jpg|webp> Output format (default: png)\n --out <path> Output file path (only when n=1)\n --outDir <dir> Output directory (default: .)\n --name <text> Base name (slugified); default: prompt\n --aspect-ratio <w:h> Aspect ratio (xAI supports e.g. 4:3)\n --json Print machine-readable JSON\n --verbose Verbose logging\n -h, --help Show help\n\nEnv:\n GEMINI_API_KEY (or GOOGLE_API_KEY)\n XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)\n FAL_KEY (or FAL_API_KEY)\n OPENAI_API_KEY\n\nExamples:\n npx climage \"make image of kitten\"\n npx climage \"A cat in a tree\" --provider xai --n 4\n`);\n process.exit(code);\n}\n\nfunction parseArgs(argv: string[]): { prompt: string; opts: GenerateOptions; json: boolean } {\n const args = [...argv];\n const opts: GenerateOptions = {};\n let json = false;\n\n const take = (name: string): string => {\n const v = args.shift();\n if (!v) throw new Error(`Missing value for ${name}`);\n return v;\n };\n\n while (args.length) {\n const a = args[0];\n if (!a) break;\n if (a === '-h' || a === '--help') usage(0);\n if (a === '--json') {\n json = true;\n args.shift();\n continue;\n }\n if (!a.startsWith('-')) break;\n\n args.shift();\n switch (a) {\n case '--provider':\n opts.provider = take(a) as ProviderId;\n break;\n case '--model':\n opts.model = take(a);\n break;\n case '--n':\n opts.n = Number(take(a));\n break;\n case '--format':\n opts.format = take(a) as any;\n break;\n case '--out':\n opts.out = take(a);\n break;\n case '--outDir':\n opts.outDir = take(a);\n break;\n case '--name':\n opts.name = take(a);\n break;\n case '--aspect-ratio':\n opts.aspectRatio = take(a);\n break;\n case '--verbose':\n opts.verbose = true;\n break;\n default:\n throw new Error(`Unknown option: ${a}`);\n }\n }\n\n const prompt = args.join(' ').trim();\n if (!prompt) throw new Error('Missing prompt');\n\n return { prompt, opts, json };\n}\n\nasync function main() {\n try {\n const { prompt, opts, json } = parseArgs(process.argv.slice(2));\n const images = await generateImage(prompt, opts);\n\n if (json) {\n process.stdout.write(JSON.stringify({ images }, null, 2) + '\\n');\n return;\n }\n\n for (const img of images) {\n process.stdout.write(img.filePath + '\\n');\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`climage: ${msg}\\n`);\n process.stderr.write(`Run: climage --help\\n`);\n process.exit(1);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain();\n","import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedImage,\n GeneratedImagePartial,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport { makeOutputPath, resolveOutDir, writeImageFile } from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction normalizeOptions(prompt: string, opts: GenerateOptions): GenerateRequest {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const format = opts.format ?? 'png';\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n };\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedImage[]> {\n const { env } = loadEnv(process.cwd());\n const req = normalizeOptions(prompt, opts);\n const provider = pickProvider(req.provider, env);\n\n const partials = await provider.generate(req, env);\n const images: GeneratedImage[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedImagePartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i);\n await writeImageFile(filePath, p.bytes);\n images.push({ ...p, filePath });\n }\n\n return images;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GeneratedImage, GenerateRequest } from './types.js';\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format);\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeImageFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(images: GeneratedImage[]) {\n return {\n images: images.map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n })),\n };\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI (grok-imagine-image)',\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n const model = req.model ?? 'grok-imagine-image';\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n const results = [] as Array<{\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalImage = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalImage[];\n};\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Default model: Flux dev (fast + popular). Can be overridden via --model.\n const model = req.model ?? 'fal-ai/flux/dev';\n\n // Map common aspect ratios to fal enums when possible.\n // If user passes e.g. 4:3, use landscape_4_3.\n let image_size: any = undefined;\n if (req.aspectRatio) {\n const ar = req.aspectRatio.trim();\n if (ar === '1:1') image_size = 'square';\n else if (ar === '4:3') image_size = 'landscape_4_3';\n else if (ar === '16:9') image_size = 'landscape_16_9';\n else if (ar === '3:4') image_size = 'portrait_4_3';\n else if (ar === '9:16') image_size = 'portrait_16_9';\n }\n\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n ...(image_size ? { image_size } : {}),\n // Some fal models support \"num_images\"; flux/dev returns images array length.\n ...(req.n ? { num_images: req.n } : {}),\n };\n\n const result = (await fal.subscribe(model, { input })) as { data: FalResult };\n\n const images = result?.data?.images;\n if (!images?.length) throw new Error('fal returned no images');\n\n const out = [] as Array<{\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(images.length, req.n); i++) {\n const img = images[i];\n if (!img?.url) continue;\n const { bytes, mimeType } = await downloadBytes(img.url);\n const finalMimeType = img.content_type ?? mimeType;\n out.push({\n provider: 'fal',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('fal returned images but none were downloadable');\n\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen)',\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n const ai = new GoogleGenAI({ apiKey });\n\n // Default to Imagen for pure text-to-image.\n const model = req.model ?? 'imagen-4.0-generate-001';\n\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForFormat(req.format),\n // Note: aspect ratio / size varies by model. Add later.\n },\n });\n\n const imgs = res.generatedImages;\n if (!imgs?.length) throw new Error('Google generateImages returned no images');\n\n const out = [] as Array<{\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) continue;\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n out.push({\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n return out;\n },\n};\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim();\n // gpt-image-1 supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), auto\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n }\n\n return undefined;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n // Default to gpt-image-1 (latest), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n"],"mappings":"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","names":["process","path","process","fs","path","downloadBytes","downloadBytes","p","path","providers","process"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type ProviderId = 'auto' | 'xai' | 'fal' | 'google';
1
+ type ProviderId = 'auto' | 'xai' | 'fal' | 'google' | 'openai';
2
2
  type ImageFormat = 'png' | 'jpg' | 'webp';
3
3
  type GenerateOptions = {
4
4
  provider?: ProviderId;
package/dist/index.js CHANGED
@@ -106,9 +106,17 @@ var xaiProvider = {
106
106
  const results = [];
107
107
  for (let i = 0; i < json.data.length; i++) {
108
108
  const img = json.data[i];
109
+ if (!img) continue;
109
110
  if (img.url) {
110
111
  const { bytes, mimeType } = await downloadBytes(img.url);
111
- results.push({ provider: "xai", model, index: i, url: img.url, bytes, mimeType });
112
+ results.push({
113
+ provider: "xai",
114
+ model,
115
+ index: i,
116
+ url: img.url,
117
+ bytes,
118
+ ...mimeType !== void 0 ? { mimeType } : {}
119
+ });
112
120
  continue;
113
121
  }
114
122
  if (img.b64_json) {
@@ -168,7 +176,15 @@ var falProvider = {
168
176
  const img = images[i];
169
177
  if (!img?.url) continue;
170
178
  const { bytes, mimeType } = await downloadBytes2(img.url);
171
- out.push({ provider: "fal", model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType });
179
+ const finalMimeType = img.content_type ?? mimeType;
180
+ out.push({
181
+ provider: "fal",
182
+ model,
183
+ index: i,
184
+ url: img.url,
185
+ bytes,
186
+ ...finalMimeType !== void 0 ? { mimeType: finalMimeType } : {}
187
+ });
172
188
  }
173
189
  if (!out.length) throw new Error("fal returned images but none were downloadable");
174
190
  return out;
@@ -219,15 +235,108 @@ var googleProvider = {
219
235
  const rawBytes = img?.image?.imageBytes;
220
236
  if (!rawBytes) continue;
221
237
  const bytes = typeof rawBytes === "string" ? Uint8Array.from(Buffer.from(rawBytes, "base64")) : rawBytes;
222
- out.push({ provider: "google", model, index: i, bytes, mimeType: mimeForFormat(req.format) });
238
+ out.push({
239
+ provider: "google",
240
+ model,
241
+ index: i,
242
+ bytes,
243
+ mimeType: mimeForFormat(req.format)
244
+ });
223
245
  }
224
246
  if (!out.length) throw new Error("Google returned images but no bytes were present");
225
247
  return out;
226
248
  }
227
249
  };
228
250
 
251
+ // src/providers/openai.ts
252
+ var OPENAI_API_BASE = "https://api.openai.com/v1";
253
+ function getOpenAIApiKey(env) {
254
+ return env.OPENAI_API_KEY || env.OPENAI_KEY;
255
+ }
256
+ async function downloadBytes3(url) {
257
+ const res = await fetch(url);
258
+ if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);
259
+ const ab = await res.arrayBuffer();
260
+ const ct = res.headers.get("content-type");
261
+ return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };
262
+ }
263
+ function mapAspectRatioToSize(aspectRatio, model) {
264
+ if (!aspectRatio) return void 0;
265
+ const ar = aspectRatio.trim();
266
+ if (model?.startsWith("gpt-image")) {
267
+ if (ar === "1:1") return "1024x1024";
268
+ if (ar === "3:2" || ar === "4:3" || ar === "16:9") return "1536x1024";
269
+ if (ar === "2:3" || ar === "3:4" || ar === "9:16") return "1024x1536";
270
+ } else if (model === "dall-e-3") {
271
+ if (ar === "1:1") return "1024x1024";
272
+ if (ar === "16:9" || ar === "4:3") return "1792x1024";
273
+ if (ar === "9:16" || ar === "3:4") return "1024x1792";
274
+ }
275
+ return void 0;
276
+ }
277
+ var openaiProvider = {
278
+ id: "openai",
279
+ displayName: "OpenAI (GPT Image / DALL-E)",
280
+ isAvailable(env) {
281
+ return Boolean(getOpenAIApiKey(env));
282
+ },
283
+ async generate(req, env) {
284
+ const apiKey = getOpenAIApiKey(env);
285
+ if (!apiKey) throw new Error("Missing OpenAI API key. Set OPENAI_API_KEY.");
286
+ const model = req.model ?? "gpt-image-1";
287
+ const size = mapAspectRatioToSize(req.aspectRatio, model);
288
+ const body = {
289
+ model,
290
+ prompt: req.prompt,
291
+ n: req.n,
292
+ ...size ? { size } : {},
293
+ // gpt-image-1 doesn't support response_format, defaults to b64_json
294
+ // dall-e-2/3 support response_format
295
+ ...!model.startsWith("gpt-image") ? { response_format: "url" } : {}
296
+ };
297
+ const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {
298
+ method: "POST",
299
+ headers: {
300
+ authorization: `Bearer ${apiKey}`,
301
+ "content-type": "application/json"
302
+ },
303
+ body: JSON.stringify(body)
304
+ });
305
+ if (!res.ok) {
306
+ const txt = await res.text().catch(() => "");
307
+ throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);
308
+ }
309
+ const json = await res.json();
310
+ if (!json.data?.length) throw new Error("OpenAI returned no images");
311
+ const results = [];
312
+ for (let i = 0; i < json.data.length; i++) {
313
+ const img = json.data[i];
314
+ if (!img) continue;
315
+ if (img.url) {
316
+ const dl = await downloadBytes3(img.url);
317
+ results.push({
318
+ provider: "openai",
319
+ model,
320
+ index: i,
321
+ url: img.url,
322
+ bytes: dl.bytes,
323
+ ...dl.mimeType ? { mimeType: dl.mimeType } : {}
324
+ });
325
+ continue;
326
+ }
327
+ if (img.b64_json) {
328
+ const bytes = Uint8Array.from(Buffer.from(img.b64_json, "base64"));
329
+ results.push({ provider: "openai", model, index: i, bytes });
330
+ continue;
331
+ }
332
+ throw new Error("OpenAI returned image without url or b64_json");
333
+ }
334
+ return results;
335
+ }
336
+ };
337
+
229
338
  // src/core/router.ts
230
- var providers = [googleProvider, xaiProvider, falProvider];
339
+ var providers = [googleProvider, xaiProvider, falProvider, openaiProvider];
231
340
  function listProviders() {
232
341
  return [...providers];
233
342
  }
@@ -239,7 +348,10 @@ function pickProvider(id, env) {
239
348
  return p2;
240
349
  }
241
350
  const p = providers.find((pp) => pp.isAvailable(env));
242
- if (!p) throw new Error("No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.");
351
+ if (!p)
352
+ throw new Error(
353
+ "No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment."
354
+ );
243
355
  return p;
244
356
  }
245
357
  function normalizeOptions(prompt, opts) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts"],"sourcesContent":["import path from 'node:path'\n\nimport type { GenerateOptions, GenerateRequest, GeneratedImage, GeneratedImagePartial, Provider, ProviderEnv, ProviderId } from './types.js'\nimport { loadEnv } from './env.js'\nimport { makeOutputPath, resolveOutDir, writeImageFile } from './output.js'\nimport { slugify, timestampLocalCompact } from './strings.js'\nimport { xaiProvider } from '../providers/xai.js'\nimport { falProvider } from '../providers/fal.js'\nimport { googleProvider } from '../providers/google.js'\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider]\n\nexport function listProviders(): Provider[] {\n return [...providers]\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id)\n if (!p) throw new Error(`Unknown provider: ${id}`)\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`)\n return p\n }\n\n const p = providers.find((pp) => pp.isAvailable(env))\n if (!p) throw new Error('No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.')\n return p\n}\n\nfunction normalizeOptions(prompt: string, opts: GenerateOptions): GenerateRequest {\n const nRaw = opts.n ?? 1\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)))\n\n const format = opts.format ?? 'png'\n const outDir = resolveOutDir(opts.outDir ?? '.')\n const timestamp = timestampLocalCompact()\n\n const nameBase = slugify(opts.name ?? prompt)\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n }\n}\n\nexport async function generateImage(prompt: string, opts: GenerateOptions = {}): Promise<GeneratedImage[]> {\n const { env } = loadEnv(process.cwd())\n const req = normalizeOptions(prompt, opts)\n const provider = pickProvider(req.provider, env)\n\n const partials = await provider.generate(req, env)\n const images: GeneratedImage[] = []\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedImagePartial | undefined = partials[i]\n if (!p) continue\n const filePath = makeOutputPath(req, i)\n await writeImageFile(filePath, p.bytes)\n images.push({ ...p, filePath })\n }\n\n return images\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport dotenv from 'dotenv'\n\nimport type { ProviderEnv } from './types.js'\n\nexport type EnvLoadResult = {\n env: ProviderEnv\n loadedFiles: string[]\n}\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local']\n const loadedFiles: string[] = []\n\n for (const name of candidates) {\n const p = path.join(cwd, name)\n if (!fs.existsSync(p)) continue\n dotenv.config({ path: p, override: false })\n loadedFiles.push(p)\n }\n\n return { env: process.env as ProviderEnv, loadedFiles }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { GeneratedImage, GenerateRequest } from './types.js'\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg'\n case 'png':\n return 'png'\n case 'webp':\n return 'webp'\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir)\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format)\n if (req.out) return path.resolve(process.cwd(), req.out)\n\n const base = `${req.nameBase}-${req.timestamp}`\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : ''\n const filename = `${base}${suffix}.${ext}`\n return path.join(req.outDir, filename)\n}\n\nexport async function writeImageFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n await fs.writeFile(filePath, bytes)\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url)\n u.search = ''\n return u.toString()\n } catch {\n return url\n }\n}\n\nexport function toJsonResult(images: GeneratedImage[]) {\n return {\n images: images.map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n })),\n }\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n if (!s) return 'image'\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0')\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n )\n}\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nconst XAI_API_BASE = 'https://api.x.ai/v1'\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY\n}\n\ntype XaiImage = {\n url?: string\n b64_json?: string\n}\n\ntype XaiImagesResponse = {\n created?: number\n data: XaiImage[]\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`xAI image download failed (${res.status})`)\n const ab = await res.arrayBuffer()\n const ct = res.headers.get('content-type') || undefined\n return { bytes: new Uint8Array(ab), mimeType: ct }\n}\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI (grok-imagine-image)',\n isAvailable(env) {\n return Boolean(getXaiApiKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env)\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).')\n\n const model = req.model ?? 'grok-imagine-image'\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n }\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '')\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`)\n }\n\n const json = (await res.json()) as XaiImagesResponse\n if (!json.data?.length) throw new Error('xAI returned no images')\n\n const results = [] as Array<{ provider: 'xai'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i]\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url)\n results.push({ provider: 'xai', model, index: i, url: img.url, bytes, mimeType })\n continue\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'))\n results.push({ provider: 'xai', model, index: i, bytes })\n continue\n }\n throw new Error('xAI returned image without url or b64_json')\n }\n\n return results\n },\n}\n","import { fal } from '@fal-ai/client'\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY\n}\n\ntype FalImage = {\n url: string\n content_type?: string\n}\n\ntype FalResult = {\n images?: FalImage[]\n}\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`fal image download failed (${res.status})`)\n const ab = await res.arrayBuffer()\n const ct = res.headers.get('content-type') || undefined\n return { bytes: new Uint8Array(ab), mimeType: ct }\n}\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n isAvailable(env) {\n return Boolean(getFalKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env)\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).')\n\n // Configure credentials at runtime\n fal.config({ credentials: key })\n\n // Default model: Flux dev (fast + popular). Can be overridden via --model.\n const model = req.model ?? 'fal-ai/flux/dev'\n\n // Map common aspect ratios to fal enums when possible.\n // If user passes e.g. 4:3, use landscape_4_3.\n let image_size: any = undefined\n if (req.aspectRatio) {\n const ar = req.aspectRatio.trim()\n if (ar === '1:1') image_size = 'square'\n else if (ar === '4:3') image_size = 'landscape_4_3'\n else if (ar === '16:9') image_size = 'landscape_16_9'\n else if (ar === '3:4') image_size = 'portrait_4_3'\n else if (ar === '9:16') image_size = 'portrait_16_9'\n }\n\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n ...(image_size ? { image_size } : {}),\n // Some fal models support \"num_images\"; flux/dev returns images array length.\n ...(req.n ? { num_images: req.n } : {}),\n }\n\n const result = (await fal.subscribe(model, { input })) as { data: FalResult }\n\n const images = result?.data?.images\n if (!images?.length) throw new Error('fal returned no images')\n\n const out = [] as Array<{ provider: 'fal'; model?: string; index: number; url?: string; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < Math.min(images.length, req.n); i++) {\n const img = images[i]\n if (!img?.url) continue\n const { bytes, mimeType } = await downloadBytes(img.url)\n out.push({ provider: 'fal', model, index: i, url: img.url, bytes, mimeType: img.content_type ?? mimeType })\n }\n\n if (!out.length) throw new Error('fal returned images but none were downloadable')\n\n return out\n },\n}\n","import { GoogleGenAI } from '@google/genai'\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js'\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY\n}\n\nfunction mimeForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg'\n case 'webp':\n return 'image/webp'\n case 'png':\n default:\n return 'image/png'\n }\n}\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen)',\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env))\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env)\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).')\n\n const ai = new GoogleGenAI({ apiKey })\n\n // Default to Imagen for pure text-to-image.\n const model = req.model ?? 'imagen-4.0-generate-001'\n\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForFormat(req.format),\n // Note: aspect ratio / size varies by model. Add later.\n },\n })\n\n const imgs = res.generatedImages\n if (!imgs?.length) throw new Error('Google generateImages returned no images')\n\n const out = [] as Array<{ provider: 'google'; model?: string; index: number; bytes: Uint8Array; mimeType?: string }>\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i]\n const rawBytes = img?.image?.imageBytes\n if (!rawBytes) continue\n // SDK returns base64 string, decode to binary\n const bytes = typeof rawBytes === 'string'\n ? Uint8Array.from(Buffer.from(rawBytes, 'base64'))\n : rawBytes\n out.push({ provider: 'google', model, index: i, bytes, mimeType: mimeForFormat(req.format) })\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present')\n return out\n },\n}\n"],"mappings":"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","names":["path","process","fs","path","downloadBytes","p","path"]}
1
+ {"version":3,"sources":["../src/core/router.ts","../src/core/env.ts","../src/core/output.ts","../src/core/strings.ts","../src/providers/xai.ts","../src/providers/fal.ts","../src/providers/google.ts","../src/providers/openai.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type {\n GenerateOptions,\n GenerateRequest,\n GeneratedImage,\n GeneratedImagePartial,\n Provider,\n ProviderEnv,\n ProviderId,\n} from './types.js';\nimport { loadEnv } from './env.js';\nimport { makeOutputPath, resolveOutDir, writeImageFile } from './output.js';\nimport { slugify, timestampLocalCompact } from './strings.js';\nimport { xaiProvider } from '../providers/xai.js';\nimport { falProvider } from '../providers/fal.js';\nimport { googleProvider } from '../providers/google.js';\nimport { openaiProvider } from '../providers/openai.js';\n\nconst providers: Provider[] = [googleProvider, xaiProvider, falProvider, openaiProvider];\n\nexport function listProviders(): Provider[] {\n return [...providers];\n}\n\nexport function pickProvider(id: ProviderId, env: ProviderEnv): Provider {\n if (id !== 'auto') {\n const p = providers.find((p) => p.id === id);\n if (!p) throw new Error(`Unknown provider: ${id}`);\n if (!p.isAvailable(env)) throw new Error(`Provider ${id} is not available (missing API key)`);\n return p;\n }\n\n const p = providers.find((pp) => pp.isAvailable(env));\n if (!p)\n throw new Error(\n 'No providers available. Set XAI_API_KEY (or other provider keys) in .env or environment.'\n );\n return p;\n}\n\nfunction normalizeOptions(prompt: string, opts: GenerateOptions): GenerateRequest {\n const nRaw = opts.n ?? 1;\n const n = Math.max(1, Math.min(10, Math.floor(nRaw)));\n\n const format = opts.format ?? 'png';\n const outDir = resolveOutDir(opts.outDir ?? '.');\n const timestamp = timestampLocalCompact();\n\n const nameBase = slugify(opts.name ?? prompt);\n\n return {\n prompt,\n provider: opts.provider ?? 'auto',\n model: opts.model ?? undefined,\n n,\n aspectRatio: opts.aspectRatio ?? undefined,\n format,\n outDir,\n out: opts.out ? path.resolve(process.cwd(), opts.out) : undefined,\n nameBase,\n timestamp,\n verbose: Boolean(opts.verbose),\n };\n}\n\nexport async function generateImage(\n prompt: string,\n opts: GenerateOptions = {}\n): Promise<GeneratedImage[]> {\n const { env } = loadEnv(process.cwd());\n const req = normalizeOptions(prompt, opts);\n const provider = pickProvider(req.provider, env);\n\n const partials = await provider.generate(req, env);\n const images: GeneratedImage[] = [];\n\n for (let i = 0; i < partials.length; i++) {\n const p: GeneratedImagePartial | undefined = partials[i];\n if (!p) continue;\n const filePath = makeOutputPath(req, i);\n await writeImageFile(filePath, p.bytes);\n images.push({ ...p, filePath });\n }\n\n return images;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport dotenv from 'dotenv';\n\nimport type { ProviderEnv } from './types.js';\n\nexport type EnvLoadResult = {\n env: ProviderEnv;\n loadedFiles: string[];\n};\n\nexport function loadEnv(cwd = process.cwd()): EnvLoadResult {\n const candidates = ['.env', '.env.local'];\n const loadedFiles: string[] = [];\n\n for (const name of candidates) {\n const p = path.join(cwd, name);\n if (!fs.existsSync(p)) continue;\n dotenv.config({ path: p, override: false });\n loadedFiles.push(p);\n }\n\n return { env: process.env as ProviderEnv, loadedFiles };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { GeneratedImage, GenerateRequest } from './types.js';\n\nexport function extensionForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'jpg';\n case 'png':\n return 'png';\n case 'webp':\n return 'webp';\n }\n}\n\nexport function resolveOutDir(outDir: string): string {\n return path.isAbsolute(outDir) ? outDir : path.resolve(process.cwd(), outDir);\n}\n\nexport function makeOutputPath(req: GenerateRequest, index: number): string {\n const ext = extensionForFormat(req.format);\n if (req.out) return path.resolve(process.cwd(), req.out);\n\n const base = `${req.nameBase}-${req.timestamp}`;\n const suffix = req.n > 1 ? `-${String(index + 1).padStart(2, '0')}` : '';\n const filename = `${base}${suffix}.${ext}`;\n return path.join(req.outDir, filename);\n}\n\nexport async function writeImageFile(filePath: string, bytes: Uint8Array): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, bytes);\n}\n\nexport function redactUrl(url: string): string {\n try {\n const u = new URL(url);\n u.search = '';\n return u.toString();\n } catch {\n return url;\n }\n}\n\nexport function toJsonResult(images: GeneratedImage[]) {\n return {\n images: images.map((img) => ({\n provider: img.provider,\n model: img.model,\n index: img.index,\n filePath: img.filePath,\n url: img.url,\n bytes: img.bytes.byteLength,\n mimeType: img.mimeType,\n })),\n };\n}\n","export function slugify(input: string, maxLen = 60): string {\n const s = input\n .trim()\n .toLowerCase()\n .replace(/['\"`]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n if (!s) return 'image';\n return s.length > maxLen ? s.slice(0, maxLen).replace(/-+$/g, '') : s;\n}\n\nexport function timestampLocalCompact(d = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n '-' +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nconst XAI_API_BASE = 'https://api.x.ai/v1';\n\nfunction getXaiApiKey(env: ProviderEnv): string | undefined {\n return env.XAI_API_KEY || env.XAI_TOKEN || env.GROK_API_KEY;\n}\n\ntype XaiImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype XaiImagesResponse = {\n created?: number;\n data: XaiImage[];\n};\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`xAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const xaiProvider: Provider = {\n id: 'xai',\n displayName: 'xAI (grok-imagine-image)',\n isAvailable(env) {\n return Boolean(getXaiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getXaiApiKey(env);\n if (!apiKey) throw new Error('Missing xAI API key. Set XAI_API_KEY (or XAI_TOKEN).');\n\n const model = req.model ?? 'grok-imagine-image';\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n // xAI docs: endpoint supports aspect_ratio\n ...(req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {}),\n // Use URL format to download + save.\n response_format: 'url',\n };\n\n const res = await fetch(`${XAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`xAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as XaiImagesResponse;\n if (!json.data?.length) throw new Error('xAI returned no images');\n\n const results = [] as Array<{\n provider: 'xai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n if (img.url) {\n const { bytes, mimeType } = await downloadBytes(img.url);\n results.push({\n provider: 'xai',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'xai', model, index: i, bytes });\n continue;\n }\n throw new Error('xAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n","import { fal } from '@fal-ai/client';\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nfunction getFalKey(env: ProviderEnv): string | undefined {\n // community is split; support both\n return env.FAL_API_KEY || env.FAL_KEY;\n}\n\ntype FalImage = {\n url: string;\n content_type?: string;\n};\n\ntype FalResult = {\n images?: FalImage[];\n};\n\nasync function downloadBytes(\n url: string\n): Promise<{ bytes: Uint8Array; mimeType: string | undefined }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fal image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type') || undefined;\n return { bytes: new Uint8Array(ab), mimeType: ct };\n}\n\nexport const falProvider: Provider = {\n id: 'fal',\n displayName: 'fal.ai',\n isAvailable(env) {\n return Boolean(getFalKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const key = getFalKey(env);\n if (!key) throw new Error('Missing fal API key. Set FAL_KEY (or FAL_API_KEY).');\n\n // Configure credentials at runtime\n fal.config({ credentials: key });\n\n // Default model: Flux dev (fast + popular). Can be overridden via --model.\n const model = req.model ?? 'fal-ai/flux/dev';\n\n // Map common aspect ratios to fal enums when possible.\n // If user passes e.g. 4:3, use landscape_4_3.\n let image_size: any = undefined;\n if (req.aspectRatio) {\n const ar = req.aspectRatio.trim();\n if (ar === '1:1') image_size = 'square';\n else if (ar === '4:3') image_size = 'landscape_4_3';\n else if (ar === '16:9') image_size = 'landscape_16_9';\n else if (ar === '3:4') image_size = 'portrait_4_3';\n else if (ar === '9:16') image_size = 'portrait_16_9';\n }\n\n const input: Record<string, unknown> = {\n prompt: req.prompt,\n ...(image_size ? { image_size } : {}),\n // Some fal models support \"num_images\"; flux/dev returns images array length.\n ...(req.n ? { num_images: req.n } : {}),\n };\n\n const result = (await fal.subscribe(model, { input })) as { data: FalResult };\n\n const images = result?.data?.images;\n if (!images?.length) throw new Error('fal returned no images');\n\n const out = [] as Array<{\n provider: 'fal';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(images.length, req.n); i++) {\n const img = images[i];\n if (!img?.url) continue;\n const { bytes, mimeType } = await downloadBytes(img.url);\n const finalMimeType = img.content_type ?? mimeType;\n out.push({\n provider: 'fal',\n model,\n index: i,\n url: img.url,\n bytes,\n ...(finalMimeType !== undefined ? { mimeType: finalMimeType } : {}),\n });\n }\n\n if (!out.length) throw new Error('fal returned images but none were downloadable');\n\n return out;\n },\n};\n","import { GoogleGenAI } from '@google/genai';\n\nimport type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nfunction getGeminiApiKey(env: ProviderEnv): string | undefined {\n // Standard names + common aliases\n return env.GEMINI_API_KEY || env.GOOGLE_API_KEY || env.GOOGLE_GENAI_API_KEY;\n}\n\nfunction mimeForFormat(format: GenerateRequest['format']): string {\n switch (format) {\n case 'jpg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'png':\n default:\n return 'image/png';\n }\n}\n\nexport const googleProvider: Provider = {\n id: 'google',\n displayName: 'Google (Gemini / Imagen)',\n isAvailable(env) {\n return Boolean(getGeminiApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getGeminiApiKey(env);\n if (!apiKey) throw new Error('Missing Google API key. Set GEMINI_API_KEY (or GOOGLE_API_KEY).');\n\n const ai = new GoogleGenAI({ apiKey });\n\n // Default to Imagen for pure text-to-image.\n const model = req.model ?? 'imagen-4.0-generate-001';\n\n const res = await ai.models.generateImages({\n model,\n prompt: req.prompt,\n config: {\n numberOfImages: req.n,\n outputMimeType: mimeForFormat(req.format),\n // Note: aspect ratio / size varies by model. Add later.\n },\n });\n\n const imgs = res.generatedImages;\n if (!imgs?.length) throw new Error('Google generateImages returned no images');\n\n const out = [] as Array<{\n provider: 'google';\n model?: string;\n index: number;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < Math.min(imgs.length, req.n); i++) {\n const img = imgs[i];\n const rawBytes = img?.image?.imageBytes;\n if (!rawBytes) continue;\n // SDK returns base64 string, decode to binary\n const bytes =\n typeof rawBytes === 'string' ? Uint8Array.from(Buffer.from(rawBytes, 'base64')) : rawBytes;\n out.push({\n provider: 'google',\n model,\n index: i,\n bytes,\n mimeType: mimeForFormat(req.format),\n });\n }\n\n if (!out.length) throw new Error('Google returned images but no bytes were present');\n return out;\n },\n};\n","import type { GenerateRequest, Provider, ProviderEnv } from '../core/types.js';\n\nconst OPENAI_API_BASE = 'https://api.openai.com/v1';\n\nfunction getOpenAIApiKey(env: ProviderEnv): string | undefined {\n return env.OPENAI_API_KEY || env.OPENAI_KEY;\n}\n\ntype OpenAIImage = {\n url?: string;\n b64_json?: string;\n};\n\ntype OpenAIImagesResponse = {\n created?: number;\n data: OpenAIImage[];\n};\n\nasync function downloadBytes(url: string): Promise<{ bytes: Uint8Array; mimeType?: string }> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`OpenAI image download failed (${res.status})`);\n const ab = await res.arrayBuffer();\n const ct = res.headers.get('content-type');\n return ct ? { bytes: new Uint8Array(ab), mimeType: ct } : { bytes: new Uint8Array(ab) };\n}\n\n// Map aspect ratios to OpenAI size parameters\nfunction mapAspectRatioToSize(aspectRatio?: string, model?: string): string | undefined {\n if (!aspectRatio) return undefined;\n\n const ar = aspectRatio.trim();\n // gpt-image-1 supports: 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), auto\n // dall-e-3 supports: 1024x1024, 1792x1024 (landscape), 1024x1792 (portrait)\n // dall-e-2 supports: 256x256, 512x512, 1024x1024\n\n if (model?.startsWith('gpt-image')) {\n if (ar === '1:1') return '1024x1024';\n if (ar === '3:2' || ar === '4:3' || ar === '16:9') return '1536x1024';\n if (ar === '2:3' || ar === '3:4' || ar === '9:16') return '1024x1536';\n } else if (model === 'dall-e-3') {\n if (ar === '1:1') return '1024x1024';\n if (ar === '16:9' || ar === '4:3') return '1792x1024';\n if (ar === '9:16' || ar === '3:4') return '1024x1792';\n }\n\n return undefined;\n}\n\nexport const openaiProvider: Provider = {\n id: 'openai',\n displayName: 'OpenAI (GPT Image / DALL-E)',\n isAvailable(env) {\n return Boolean(getOpenAIApiKey(env));\n },\n async generate(req: GenerateRequest, env: ProviderEnv) {\n const apiKey = getOpenAIApiKey(env);\n if (!apiKey) throw new Error('Missing OpenAI API key. Set OPENAI_API_KEY.');\n\n // Default to gpt-image-1 (latest), can be overridden to dall-e-3 or dall-e-2\n const model = req.model ?? 'gpt-image-1';\n\n const size = mapAspectRatioToSize(req.aspectRatio, model);\n\n const body: Record<string, unknown> = {\n model,\n prompt: req.prompt,\n n: req.n,\n ...(size ? { size } : {}),\n // gpt-image-1 doesn't support response_format, defaults to b64_json\n // dall-e-2/3 support response_format\n ...(!model.startsWith('gpt-image') ? { response_format: 'url' } : {}),\n };\n\n const res = await fetch(`${OPENAI_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${apiKey}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`OpenAI generations failed (${res.status}): ${txt.slice(0, 500)}`);\n }\n\n const json = (await res.json()) as OpenAIImagesResponse;\n if (!json.data?.length) throw new Error('OpenAI returned no images');\n\n const results = [] as Array<{\n provider: 'openai';\n model?: string;\n index: number;\n url?: string;\n bytes: Uint8Array;\n mimeType?: string;\n }>;\n\n for (let i = 0; i < json.data.length; i++) {\n const img = json.data[i];\n if (!img) continue;\n if (img.url) {\n const dl = await downloadBytes(img.url);\n results.push({\n provider: 'openai',\n model,\n index: i,\n url: img.url,\n bytes: dl.bytes,\n ...(dl.mimeType ? { mimeType: dl.mimeType } : {}),\n });\n continue;\n }\n if (img.b64_json) {\n const bytes = Uint8Array.from(Buffer.from(img.b64_json, 'base64'));\n results.push({ provider: 'openai', model, index: i, bytes });\n continue;\n }\n throw new Error('OpenAI returned image without url or b64_json');\n }\n\n return results;\n },\n};\n"],"mappings":"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","names":["path","process","fs","path","downloadBytes","downloadBytes","p","path"]}
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "climage",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "Generate images from the terminal via multiple providers (xAI, Google, fal)",
5
5
  "license": "MIT",
6
6
  "author": "",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/miguelm-bot/climage"
10
+ },
7
11
  "type": "module",
8
12
  "bin": {
9
13
  "climage": "./dist/cli.js"