@hasna/connectors 1.3.0 → 1.3.1

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/bin/index.js CHANGED
@@ -11851,7 +11851,7 @@ import chalk2 from "chalk";
11851
11851
  // package.json
11852
11852
  var package_default = {
11853
11853
  name: "@hasna/connectors",
11854
- version: "1.2.1",
11854
+ version: "1.3.1",
11855
11855
  description: "Open source connector library - Install API connectors with a single command",
11856
11856
  type: "module",
11857
11857
  bin: {
package/bin/mcp.js CHANGED
@@ -27082,7 +27082,7 @@ init_strip();
27082
27082
  // package.json
27083
27083
  var package_default = {
27084
27084
  name: "@hasna/connectors",
27085
- version: "1.2.1",
27085
+ version: "1.3.1",
27086
27086
  description: "Open source connector library - Install API connectors with a single command",
27087
27087
  type: "module",
27088
27088
  bin: {
@@ -124,6 +124,11 @@ export class HuggingFaceClient {
124
124
  return this.request<T>(path, { method: 'DELETE', params });
125
125
  }
126
126
 
127
+ /** Get the raw API key (needed by InferenceApi for direct fetch) */
128
+ getApiKey(): string {
129
+ return this.apiKey;
130
+ }
131
+
127
132
  /**
128
133
  * Get a preview of the API key (for display/debugging)
129
134
  */
@@ -0,0 +1,73 @@
1
+ import type { HuggingFaceClient } from './client';
2
+
3
+ export interface DatasetSearchOptions {
4
+ search?: string;
5
+ author?: string;
6
+ filter?: string;
7
+ sort?: 'likes' | 'downloads' | 'trending' | 'lastModified';
8
+ direction?: 'asc' | 'desc';
9
+ limit?: number;
10
+ full?: boolean;
11
+ }
12
+
13
+ export interface DatasetInfo {
14
+ _id: string;
15
+ id: string;
16
+ author?: string;
17
+ sha?: string;
18
+ lastModified?: string;
19
+ private?: boolean;
20
+ gated?: boolean | string;
21
+ tags?: string[];
22
+ downloads?: number;
23
+ likes?: number;
24
+ description?: string;
25
+ citation?: string;
26
+ cardData?: Record<string, unknown>;
27
+ [key: string]: unknown;
28
+ }
29
+
30
+ export interface DatasetSplit {
31
+ dataset: string;
32
+ config: string;
33
+ split: string;
34
+ num_rows: number;
35
+ num_bytes: number;
36
+ }
37
+
38
+ export class DatasetsApi {
39
+ constructor(private readonly client: HuggingFaceClient) {}
40
+
41
+ /** Search/list datasets */
42
+ async search(options: DatasetSearchOptions = {}): Promise<DatasetInfo[]> {
43
+ const params: Record<string, string | number | boolean | undefined> = {};
44
+ if (options.search) params.search = options.search;
45
+ if (options.author) params.author = options.author;
46
+ if (options.filter) params.filter = options.filter;
47
+ if (options.sort) params.sort = options.sort;
48
+ if (options.direction) params.direction = options.direction === 'desc' ? '-1' : '1';
49
+ if (options.limit) params.limit = options.limit;
50
+ if (options.full) params.full = true;
51
+
52
+ return this.client.request<DatasetInfo[]>('/datasets', { params });
53
+ }
54
+
55
+ /** Get a single dataset by ID */
56
+ async get(datasetId: string): Promise<DatasetInfo> {
57
+ return this.client.request<DatasetInfo>(`/datasets/${datasetId}`);
58
+ }
59
+
60
+ /** Preview first N rows of a dataset split */
61
+ async preview(datasetId: string, config = 'default', split = 'train', rows = 10): Promise<unknown> {
62
+ // Uses the datasets-server API
63
+ const url = `https://datasets-server.huggingface.co/first-rows?dataset=${encodeURIComponent(datasetId)}&config=${config}&split=${split}&rows=${rows}`;
64
+ const response = await fetch(url, {
65
+ headers: { Authorization: `Bearer ${this.client.getApiKey()}` },
66
+ });
67
+ if (!response.ok) {
68
+ const text = await response.text();
69
+ throw new Error(`Dataset preview failed (${response.status}): ${text}`);
70
+ }
71
+ return response.json();
72
+ }
73
+ }
@@ -1,6 +1,9 @@
1
1
  import type { HuggingFaceConfig } from '../types';
2
2
  import { HuggingFaceClient } from './client';
3
- import { ExampleApi } from './example';
3
+ import { ModelsApi } from './models';
4
+ import { InferenceApi } from './inference';
5
+ import { DatasetsApi } from './datasets';
6
+ import { SpacesApi } from './spaces';
4
7
 
5
8
  /**
6
9
  * Main HuggingFace API class
@@ -8,42 +11,37 @@ import { ExampleApi } from './example';
8
11
  export class HuggingFace {
9
12
  private readonly client: HuggingFaceClient;
10
13
 
11
- // API modules - add more as needed
12
- public readonly example: ExampleApi;
14
+ public readonly models: ModelsApi;
15
+ public readonly inference: InferenceApi;
16
+ public readonly datasets: DatasetsApi;
17
+ public readonly spaces: SpacesApi;
13
18
 
14
19
  constructor(config: HuggingFaceConfig) {
15
20
  this.client = new HuggingFaceClient(config);
16
- this.example = new ExampleApi(this.client);
21
+ this.models = new ModelsApi(this.client);
22
+ this.inference = new InferenceApi(this.client);
23
+ this.datasets = new DatasetsApi(this.client);
24
+ this.spaces = new SpacesApi(this.client);
17
25
  }
18
26
 
19
- /**
20
- * Create a client from environment variables
21
- * Looks for HUGGINGFACE_API_KEY or HF_TOKEN
22
- */
23
27
  static fromEnv(): HuggingFace {
24
28
  const apiKey = process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
25
29
  const apiSecret = process.env.HUGGINGFACE_API_SECRET;
26
-
27
- if (!apiKey) {
28
- throw new Error('HUGGINGFACE_API_KEY or HF_TOKEN environment variable is required');
29
- }
30
+ if (!apiKey) throw new Error('HUGGINGFACE_API_KEY or HF_TOKEN environment variable is required');
30
31
  return new HuggingFace({ apiKey, apiSecret });
31
32
  }
32
33
 
33
- /**
34
- * Get a preview of the API key (for debugging)
35
- */
36
34
  getApiKeyPreview(): string {
37
35
  return this.client.getApiKeyPreview();
38
36
  }
39
37
 
40
- /**
41
- * Get the underlying client for direct API access
42
- */
43
38
  getClient(): HuggingFaceClient {
44
39
  return this.client;
45
40
  }
46
41
  }
47
42
 
48
43
  export { HuggingFaceClient } from './client';
49
- export { ExampleApi } from './example';
44
+ export { ModelsApi } from './models';
45
+ export { InferenceApi } from './inference';
46
+ export { DatasetsApi } from './datasets';
47
+ export { SpacesApi } from './spaces';
@@ -0,0 +1,100 @@
1
+ import type { HuggingFaceClient } from './client';
2
+
3
+ const INFERENCE_URL = 'https://api-inference.huggingface.co/models';
4
+
5
+ export interface TextGenerationOptions {
6
+ max_new_tokens?: number;
7
+ temperature?: number;
8
+ top_p?: number;
9
+ top_k?: number;
10
+ repetition_penalty?: number;
11
+ return_full_text?: boolean;
12
+ stop?: string[];
13
+ }
14
+
15
+ export interface TextGenerationResult {
16
+ generated_text: string;
17
+ }
18
+
19
+ export interface ChatMessage {
20
+ role: 'system' | 'user' | 'assistant';
21
+ content: string;
22
+ }
23
+
24
+ export interface ChatCompletionResult {
25
+ choices: Array<{
26
+ message: { role: string; content: string };
27
+ finish_reason: string;
28
+ index: number;
29
+ }>;
30
+ model: string;
31
+ usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
32
+ }
33
+
34
+ export class InferenceApi {
35
+ constructor(private readonly client: HuggingFaceClient) {}
36
+
37
+ /** Run text generation inference */
38
+ async textGeneration(
39
+ model: string,
40
+ prompt: string,
41
+ options: TextGenerationOptions = {}
42
+ ): Promise<TextGenerationResult[]> {
43
+ const response = await fetch(`${INFERENCE_URL}/${model}`, {
44
+ method: 'POST',
45
+ headers: {
46
+ Authorization: `Bearer ${this.client.getApiKey()}`,
47
+ 'Content-Type': 'application/json',
48
+ },
49
+ body: JSON.stringify({
50
+ inputs: prompt,
51
+ parameters: {
52
+ max_new_tokens: options.max_new_tokens ?? 256,
53
+ temperature: options.temperature,
54
+ top_p: options.top_p,
55
+ top_k: options.top_k,
56
+ repetition_penalty: options.repetition_penalty,
57
+ return_full_text: options.return_full_text ?? false,
58
+ stop: options.stop,
59
+ },
60
+ }),
61
+ });
62
+
63
+ if (!response.ok) {
64
+ const text = await response.text();
65
+ throw new Error(`Inference failed (${response.status}): ${text}`);
66
+ }
67
+
68
+ return response.json();
69
+ }
70
+
71
+ /** Chat completion via HF Inference API (for chat models) */
72
+ async chat(
73
+ model: string,
74
+ messages: ChatMessage[],
75
+ options: Omit<TextGenerationOptions, 'return_full_text'> = {}
76
+ ): Promise<ChatCompletionResult> {
77
+ const response = await fetch(`${INFERENCE_URL}/${model}/v1/chat/completions`, {
78
+ method: 'POST',
79
+ headers: {
80
+ Authorization: `Bearer ${this.client.getApiKey()}`,
81
+ 'Content-Type': 'application/json',
82
+ },
83
+ body: JSON.stringify({
84
+ model,
85
+ messages,
86
+ max_tokens: options.max_new_tokens ?? 256,
87
+ temperature: options.temperature,
88
+ top_p: options.top_p,
89
+ stop: options.stop,
90
+ }),
91
+ });
92
+
93
+ if (!response.ok) {
94
+ const text = await response.text();
95
+ throw new Error(`Chat inference failed (${response.status}): ${text}`);
96
+ }
97
+
98
+ return response.json();
99
+ }
100
+ }
@@ -0,0 +1,66 @@
1
+ import type { HuggingFaceClient } from './client';
2
+
3
+ export interface ModelSearchOptions {
4
+ search?: string;
5
+ author?: string;
6
+ filter?: string; // task filter: text-generation, text2text-generation, etc
7
+ library?: string; // transformers, gguf, pytorch, etc
8
+ sort?: 'likes' | 'downloads' | 'trending' | 'lastModified';
9
+ direction?: 'asc' | 'desc';
10
+ limit?: number;
11
+ full?: boolean; // include all fields
12
+ }
13
+
14
+ export interface ModelInfo {
15
+ _id: string;
16
+ id: string; // e.g. "meta-llama/Meta-Llama-3-8B"
17
+ modelId: string;
18
+ author?: string;
19
+ sha?: string;
20
+ lastModified?: string;
21
+ private?: boolean;
22
+ disabled?: boolean;
23
+ gated?: boolean | string;
24
+ pipeline_tag?: string;
25
+ tags?: string[];
26
+ downloads?: number;
27
+ likes?: number;
28
+ library_name?: string;
29
+ [key: string]: unknown;
30
+ }
31
+
32
+ export interface ModelFile {
33
+ rfilename: string;
34
+ size?: number;
35
+ blobId?: string;
36
+ lfs?: { size: number; sha256: string; pointerSize: number };
37
+ }
38
+
39
+ export class ModelsApi {
40
+ constructor(private readonly client: HuggingFaceClient) {}
41
+
42
+ /** Search/list models */
43
+ async search(options: ModelSearchOptions = {}): Promise<ModelInfo[]> {
44
+ const params: Record<string, string | number | boolean | undefined> = {};
45
+ if (options.search) params.search = options.search;
46
+ if (options.author) params.author = options.author;
47
+ if (options.filter) params.filter = options.filter;
48
+ if (options.library) params.library = options.library;
49
+ if (options.sort) params.sort = options.sort;
50
+ if (options.direction) params.direction = options.direction === 'desc' ? '-1' : '1';
51
+ if (options.limit) params.limit = options.limit;
52
+ if (options.full) params.full = true;
53
+
54
+ return this.client.request<ModelInfo[]>('/models', { params });
55
+ }
56
+
57
+ /** Get a single model by ID (e.g. "meta-llama/Meta-Llama-3-8B") */
58
+ async get(modelId: string): Promise<ModelInfo> {
59
+ return this.client.request<ModelInfo>(`/models/${modelId}`);
60
+ }
61
+
62
+ /** List files in a model repo */
63
+ async files(modelId: string): Promise<ModelFile[]> {
64
+ return this.client.request<ModelFile[]>(`/models/${modelId}/tree/main`);
65
+ }
66
+ }
@@ -0,0 +1,42 @@
1
+ import type { HuggingFaceClient } from './client';
2
+
3
+ export interface SpaceSearchOptions {
4
+ search?: string;
5
+ author?: string;
6
+ sort?: 'likes' | 'trending' | 'lastModified';
7
+ direction?: 'asc' | 'desc';
8
+ limit?: number;
9
+ }
10
+
11
+ export interface SpaceInfo {
12
+ _id: string;
13
+ id: string;
14
+ author?: string;
15
+ sha?: string;
16
+ lastModified?: string;
17
+ private?: boolean;
18
+ tags?: string[];
19
+ likes?: number;
20
+ sdk?: string;
21
+ runtime?: { stage: string; hardware?: { current?: string } };
22
+ [key: string]: unknown;
23
+ }
24
+
25
+ export class SpacesApi {
26
+ constructor(private readonly client: HuggingFaceClient) {}
27
+
28
+ async search(options: SpaceSearchOptions = {}): Promise<SpaceInfo[]> {
29
+ const params: Record<string, string | number | boolean | undefined> = {};
30
+ if (options.search) params.search = options.search;
31
+ if (options.author) params.author = options.author;
32
+ if (options.sort) params.sort = options.sort;
33
+ if (options.direction) params.direction = options.direction === 'desc' ? '-1' : '1';
34
+ if (options.limit) params.limit = options.limit;
35
+
36
+ return this.client.request<SpaceInfo[]>('/spaces', { params });
37
+ }
38
+
39
+ async get(spaceId: string): Promise<SpaceInfo> {
40
+ return this.client.request<SpaceInfo>(`/spaces/${spaceId}`);
41
+ }
42
+ }
@@ -188,55 +188,167 @@ configCmd
188
188
  });
189
189
 
190
190
  // ============================================
191
- // Example API Commands - Replace with HuggingFace API commands
191
+ // Models Commands
192
192
  // ============================================
193
- const exampleCmd = program
194
- .command('example')
195
- .description('Example API commands (replace with HuggingFace commands)');
193
+ const modelsCmd = program.command('models').description('Search and browse HuggingFace models');
196
194
 
197
- exampleCmd
198
- .command('list')
199
- .description('List resources')
200
- .option('-n, --max <number>', 'Maximum results', '10')
201
- .action(async (opts) => {
195
+ modelsCmd
196
+ .command('search')
197
+ .description('Search models')
198
+ .argument('[query]', 'Search query')
199
+ .option('--task <task>', 'Filter by task (text-generation, text2text-generation, etc)')
200
+ .option('--library <lib>', 'Filter by library (transformers, gguf, pytorch)')
201
+ .option('--author <author>', 'Filter by author')
202
+ .option('--sort <field>', 'Sort by: likes, downloads, trending, lastModified', 'trending')
203
+ .option('--limit <n>', 'Max results', '20')
204
+ .action(async (query, opts) => {
202
205
  try {
203
206
  const client = getClient();
204
- const result = await client.example.list({ maxResults: parseInt(opts.max) });
205
- print(result, getFormat(exampleCmd));
206
- } catch (err) {
207
- error(String(err));
208
- process.exit(1);
209
- }
207
+ const results = await client.models.search({
208
+ search: query, filter: opts.task, library: opts.library,
209
+ author: opts.author, sort: opts.sort, limit: parseInt(opts.limit),
210
+ });
211
+ print(results.map(m => ({ id: m.id, task: m.pipeline_tag, library: m.library_name, downloads: m.downloads, likes: m.likes })), getFormat(modelsCmd));
212
+ } catch (err) { error(String(err)); process.exit(1); }
210
213
  });
211
214
 
212
- exampleCmd
215
+ modelsCmd
213
216
  .command('get <id>')
214
- .description('Get a resource by ID')
215
- .action(async (id: string) => {
217
+ .description('Get model details (e.g. meta-llama/Meta-Llama-3-8B)')
218
+ .action(async (id) => {
216
219
  try {
217
220
  const client = getClient();
218
- const result = await client.example.get(id);
219
- print(result, getFormat(exampleCmd));
220
- } catch (err) {
221
- error(String(err));
222
- process.exit(1);
223
- }
221
+ const result = await client.models.get(id);
222
+ print(result, getFormat(modelsCmd));
223
+ } catch (err) { error(String(err)); process.exit(1); }
224
224
  });
225
225
 
226
- exampleCmd
227
- .command('create')
228
- .description('Create a new resource')
229
- .requiredOption('-n, --name <name>', 'Resource name')
230
- .action(async (opts) => {
226
+ modelsCmd
227
+ .command('files <id>')
228
+ .description('List files in a model repo')
229
+ .action(async (id) => {
231
230
  try {
232
231
  const client = getClient();
233
- const result = await client.example.create({ name: opts.name });
234
- success('Resource created!');
235
- print(result, getFormat(exampleCmd));
236
- } catch (err) {
237
- error(String(err));
238
- process.exit(1);
239
- }
232
+ const files = await client.models.files(id);
233
+ print(files.map(f => ({ name: f.rfilename, size: f.lfs?.size ?? f.size ?? null })), getFormat(modelsCmd));
234
+ } catch (err) { error(String(err)); process.exit(1); }
235
+ });
236
+
237
+ // ============================================
238
+ // Inference Commands
239
+ // ============================================
240
+ const inferCmd = program.command('inference').description('Run model inference via HF Inference API');
241
+
242
+ inferCmd
243
+ .command('text-generation <model>')
244
+ .description('Generate text from a prompt')
245
+ .requiredOption('--prompt <text>', 'Input prompt')
246
+ .option('--max-tokens <n>', 'Max new tokens', '256')
247
+ .option('--temperature <t>', 'Temperature', '0.7')
248
+ .action(async (model, opts) => {
249
+ try {
250
+ const client = getClient();
251
+ const results = await client.inference.textGeneration(model, opts.prompt, {
252
+ max_new_tokens: parseInt(opts.maxTokens), temperature: parseFloat(opts.temperature),
253
+ });
254
+ print(results, getFormat(inferCmd));
255
+ } catch (err) { error(String(err)); process.exit(1); }
256
+ });
257
+
258
+ inferCmd
259
+ .command('chat <model>')
260
+ .description('Chat completion (for chat models)')
261
+ .requiredOption('--messages <json>', 'Messages JSON array')
262
+ .option('--max-tokens <n>', 'Max new tokens', '256')
263
+ .option('--temperature <t>', 'Temperature', '0.7')
264
+ .action(async (model, opts) => {
265
+ try {
266
+ const messages = JSON.parse(opts.messages);
267
+ const client = getClient();
268
+ const result = await client.inference.chat(model, messages, {
269
+ max_new_tokens: parseInt(opts.maxTokens), temperature: parseFloat(opts.temperature),
270
+ });
271
+ print(result, getFormat(inferCmd));
272
+ } catch (err) { error(String(err)); process.exit(1); }
273
+ });
274
+
275
+ // ============================================
276
+ // Datasets Commands
277
+ // ============================================
278
+ const datasetsCmd = program.command('datasets').description('Search and browse HuggingFace datasets');
279
+
280
+ datasetsCmd
281
+ .command('search')
282
+ .description('Search datasets')
283
+ .argument('[query]', 'Search query')
284
+ .option('--author <author>', 'Filter by author')
285
+ .option('--sort <field>', 'Sort by: likes, downloads, trending', 'trending')
286
+ .option('--limit <n>', 'Max results', '20')
287
+ .action(async (query, opts) => {
288
+ try {
289
+ const client = getClient();
290
+ const results = await client.datasets.search({
291
+ search: query, author: opts.author, sort: opts.sort, limit: parseInt(opts.limit),
292
+ });
293
+ print(results.map(d => ({ id: d.id, downloads: d.downloads, likes: d.likes, tags: d.tags?.slice(0, 5) })), getFormat(datasetsCmd));
294
+ } catch (err) { error(String(err)); process.exit(1); }
295
+ });
296
+
297
+ datasetsCmd
298
+ .command('get <id>')
299
+ .description('Get dataset details')
300
+ .action(async (id) => {
301
+ try {
302
+ const client = getClient();
303
+ const result = await client.datasets.get(id);
304
+ print(result, getFormat(datasetsCmd));
305
+ } catch (err) { error(String(err)); process.exit(1); }
306
+ });
307
+
308
+ datasetsCmd
309
+ .command('preview <id>')
310
+ .description('Preview first N rows of a dataset')
311
+ .option('--split <split>', 'Dataset split', 'train')
312
+ .option('--rows <n>', 'Number of rows', '10')
313
+ .action(async (id, opts) => {
314
+ try {
315
+ const client = getClient();
316
+ const result = await client.datasets.preview(id, 'default', opts.split, parseInt(opts.rows));
317
+ print(result, getFormat(datasetsCmd));
318
+ } catch (err) { error(String(err)); process.exit(1); }
319
+ });
320
+
321
+ // ============================================
322
+ // Spaces Commands
323
+ // ============================================
324
+ const spacesCmd = program.command('spaces').description('Search and browse HuggingFace Spaces');
325
+
326
+ spacesCmd
327
+ .command('search')
328
+ .description('Search spaces')
329
+ .argument('[query]', 'Search query')
330
+ .option('--author <author>', 'Filter by author')
331
+ .option('--sort <field>', 'Sort by: likes, trending', 'trending')
332
+ .option('--limit <n>', 'Max results', '20')
333
+ .action(async (query, opts) => {
334
+ try {
335
+ const client = getClient();
336
+ const results = await client.spaces.search({
337
+ search: query, author: opts.author, sort: opts.sort, limit: parseInt(opts.limit),
338
+ });
339
+ print(results.map(s => ({ id: s.id, sdk: s.sdk, likes: s.likes })), getFormat(spacesCmd));
340
+ } catch (err) { error(String(err)); process.exit(1); }
341
+ });
342
+
343
+ spacesCmd
344
+ .command('get <id>')
345
+ .description('Get space details')
346
+ .action(async (id) => {
347
+ try {
348
+ const client = getClient();
349
+ const result = await client.spaces.get(id);
350
+ print(result, getFormat(spacesCmd));
351
+ } catch (err) { error(String(err)); process.exit(1); }
240
352
  });
241
353
 
242
354
  // Parse and execute
@@ -5,8 +5,20 @@ import type {
5
5
  ImageOptions,
6
6
  } from '../types';
7
7
 
8
+ /** Models that use the new gpt-image API (different params than DALL-E) */
9
+ const GPT_IMAGE_MODELS = ['gpt-image-1'];
10
+
11
+ function isGptImage(model: string): boolean {
12
+ return GPT_IMAGE_MODELS.some((m) => model.startsWith(m));
13
+ }
14
+
8
15
  /**
9
- * Images API (DALL-E)
16
+ * Images API — supports both DALL-E 3 and gpt-image-1
17
+ *
18
+ * gpt-image-1 differences:
19
+ * - Uses `output_format` instead of `response_format`
20
+ * - Does NOT support `style` parameter
21
+ * - Does NOT support `response_format` parameter
10
22
  */
11
23
  export class ImagesApi {
12
24
  constructor(private readonly client: OpenAIClient) {}
@@ -18,13 +30,29 @@ export class ImagesApi {
18
30
  prompt: string,
19
31
  options: ImageOptions = {}
20
32
  ): Promise<ImageResponse> {
33
+ const model = options.model || 'dall-e-3';
34
+
35
+ if (isGptImage(model)) {
36
+ // gpt-image-1: different parameter set
37
+ const request: Record<string, unknown> = {
38
+ model,
39
+ prompt,
40
+ n: options.n || 1,
41
+ };
42
+ if (options.size !== undefined) request.size = options.size;
43
+ if (options.quality !== undefined) request.quality = options.quality;
44
+ // gpt-image-1 uses output_format, not response_format. No style param.
45
+ request.output_format = 'url';
46
+ return this.client.post<ImageResponse>('/images/generations', request);
47
+ }
48
+
49
+ // DALL-E 3: original parameter set
21
50
  const request: ImageGenerateRequest = {
22
- model: options.model || 'dall-e-3',
51
+ model,
23
52
  prompt,
24
53
  n: options.n || 1,
25
54
  response_format: 'url',
26
55
  };
27
-
28
56
  if (options.size !== undefined) request.size = options.size;
29
57
  if (options.quality !== undefined) request.quality = options.quality;
30
58
  if (options.style !== undefined) request.style = options.style;
@@ -54,22 +82,38 @@ export class ImagesApi {
54
82
  prompt: string,
55
83
  options: Omit<ImageOptions, 'n'> = {}
56
84
  ): Promise<string> {
85
+ const model = options.model || 'dall-e-3';
86
+
87
+ if (isGptImage(model)) {
88
+ const request: Record<string, unknown> = {
89
+ model,
90
+ prompt,
91
+ n: 1,
92
+ output_format: 'b64_json',
93
+ };
94
+ if (options.size !== undefined) request.size = options.size;
95
+ if (options.quality !== undefined) request.quality = options.quality;
96
+
97
+ const response = await this.client.post<ImageResponse>('/images/generations', request);
98
+ const b64 = response.data[0]?.b64_json;
99
+ if (!b64) throw new Error('No image data in response');
100
+ return b64;
101
+ }
102
+
103
+ // DALL-E 3
57
104
  const request: ImageGenerateRequest = {
58
- model: options.model || 'dall-e-3',
105
+ model,
59
106
  prompt,
60
107
  n: 1,
61
108
  response_format: 'b64_json',
62
109
  };
63
-
64
110
  if (options.size !== undefined) request.size = options.size;
65
111
  if (options.quality !== undefined) request.quality = options.quality;
66
112
  if (options.style !== undefined) request.style = options.style;
67
113
 
68
114
  const response = await this.client.post<ImageResponse>('/images/generations', request);
69
115
  const b64 = response.data[0]?.b64_json;
70
- if (!b64) {
71
- throw new Error('No image data in response');
72
- }
116
+ if (!b64) throw new Error('No image data in response');
73
117
  return b64;
74
118
  }
75
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/connectors",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Open source connector library - Install API connectors with a single command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,48 +0,0 @@
1
- import type { HuggingFaceClient } from './client';
2
- import type { ExampleResource, ExampleListResponse, ExampleCreateParams } from '../types';
3
-
4
- /**
5
- * Example API module - demonstrates the pattern for API modules
6
- * Replace with actual HuggingFace API endpoints (models, datasets, spaces, etc.)
7
- */
8
- export class ExampleApi {
9
- constructor(private readonly client: HuggingFaceClient) {}
10
-
11
- /**
12
- * List resources with optional pagination
13
- */
14
- async list(options?: { maxResults?: number; pageToken?: string }): Promise<ExampleListResponse> {
15
- return this.client.get<ExampleListResponse>('/resources', {
16
- max_results: options?.maxResults,
17
- page_token: options?.pageToken,
18
- });
19
- }
20
-
21
- /**
22
- * Get a single resource by ID
23
- */
24
- async get(id: string): Promise<ExampleResource> {
25
- return this.client.get<ExampleResource>(`/resources/${id}`);
26
- }
27
-
28
- /**
29
- * Create a new resource
30
- */
31
- async create(params: ExampleCreateParams): Promise<ExampleResource> {
32
- return this.client.post<ExampleResource>('/resources', params);
33
- }
34
-
35
- /**
36
- * Update an existing resource
37
- */
38
- async update(id: string, params: Partial<ExampleCreateParams>): Promise<ExampleResource> {
39
- return this.client.patch<ExampleResource>(`/resources/${id}`, params);
40
- }
41
-
42
- /**
43
- * Delete a resource
44
- */
45
- async delete(id: string): Promise<void> {
46
- await this.client.delete(`/resources/${id}`);
47
- }
48
- }