@umituz/react-native-ai-gemini-provider 1.14.24 → 1.14.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-gemini-provider",
3
- "version": "1.14.24",
3
+ "version": "1.14.25",
4
4
  "description": "Google Gemini AI provider for React Native applications",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -37,3 +37,48 @@ export interface GeminiApiError {
37
37
  }>;
38
38
  };
39
39
  }
40
+
41
+ /**
42
+ * Custom error class for Gemini API errors
43
+ */
44
+ export class GeminiError extends Error {
45
+ readonly type: GeminiErrorType;
46
+ readonly retryable: boolean;
47
+ readonly statusCode?: number;
48
+ readonly originalError?: unknown;
49
+
50
+ constructor(info: GeminiErrorInfo) {
51
+ super(info.messageKey);
52
+ this.name = "GeminiError";
53
+ this.type = info.type;
54
+ this.retryable = info.retryable;
55
+ this.statusCode = info.statusCode;
56
+ this.originalError = info.originalError;
57
+
58
+ // Maintains proper stack trace (only available on V8)
59
+ if (Error.captureStackTrace) {
60
+ Error.captureStackTrace(this, GeminiError);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Check if error is retryable
66
+ */
67
+ isRetryable(): boolean {
68
+ return this.retryable;
69
+ }
70
+
71
+ /**
72
+ * Get error type
73
+ */
74
+ getErrorType(): GeminiErrorType {
75
+ return this.type;
76
+ }
77
+
78
+ /**
79
+ * Create GeminiError from unknown error
80
+ */
81
+ static fromError(_error: unknown, info: GeminiErrorInfo): GeminiError {
82
+ return new GeminiError(info);
83
+ }
84
+ }
package/src/index.ts CHANGED
@@ -51,6 +51,8 @@ export type {
51
51
  GeminiApiError,
52
52
  } from "./domain/entities";
53
53
 
54
+ export { GeminiError } from "./domain/entities";
55
+
54
56
  // Model Constants
55
57
  export {
56
58
  GEMINI_MODELS,
@@ -90,6 +92,7 @@ export {
90
92
  geminiVideoGenerationService,
91
93
  geminiProviderService,
92
94
  createGeminiProvider,
95
+ featureModelSelector,
93
96
  } from "./infrastructure/services";
94
97
 
95
98
  export type {
@@ -100,6 +103,9 @@ export type {
100
103
  JobStatus,
101
104
  SubscribeOptions,
102
105
  AIJobStatusType,
106
+ GenerationInput,
107
+ GenerationResult,
108
+ ExecutionOptions,
103
109
  } from "./infrastructure/services";
104
110
 
105
111
  // =============================================================================
@@ -110,6 +116,7 @@ export {
110
116
  mapGeminiError,
111
117
  isGeminiErrorRetryable,
112
118
  categorizeGeminiError,
119
+ createGeminiError,
113
120
  // Input builders
114
121
  buildSingleImageInput,
115
122
  buildDualImageInput,
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Feature Model Selector
3
3
  * Returns the appropriate model ID for a given feature
4
+ * Supports runtime model overrides for flexibility
4
5
  */
5
6
 
6
7
  import type {
@@ -12,19 +13,64 @@ import {
12
13
  GEMINI_VIDEO_FEATURE_MODELS,
13
14
  } from "../../domain/constants/feature-models.constants";
14
15
 
16
+ declare const __DEV__: boolean;
17
+
18
+ type ModelOverrideMap = Partial<Record<ImageFeatureType | VideoFeatureType, string>>;
19
+
15
20
  class FeatureModelSelector {
21
+ private overrides: ModelOverrideMap = {};
22
+
23
+ /**
24
+ * Set model override for a specific feature
25
+ * This allows runtime configuration without modifying constants
26
+ */
27
+ setModelOverride(feature: ImageFeatureType | VideoFeatureType, model: string): void {
28
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
29
+ // eslint-disable-next-line no-console
30
+ console.log("[FeatureModelSelector] Model override set:", { feature, model });
31
+ }
32
+ this.overrides[feature] = model;
33
+ }
34
+
35
+ /**
36
+ * Clear all model overrides
37
+ */
38
+ clearOverrides(): void {
39
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
40
+ // eslint-disable-next-line no-console
41
+ console.log("[FeatureModelSelector] All model overrides cleared");
42
+ }
43
+ this.overrides = {};
44
+ }
45
+
16
46
  /**
17
47
  * Get model ID for an IMAGE feature
48
+ * Returns override if set, otherwise returns default model
18
49
  */
19
50
  getImageFeatureModel(feature: ImageFeatureType): string {
20
- return GEMINI_IMAGE_FEATURE_MODELS[feature];
51
+ return this.overrides[feature] ?? GEMINI_IMAGE_FEATURE_MODELS[feature];
21
52
  }
22
53
 
23
54
  /**
24
55
  * Get model ID for a VIDEO feature
56
+ * Returns override if set, otherwise returns default model
25
57
  */
26
58
  getVideoFeatureModel(feature: VideoFeatureType): string {
27
- return GEMINI_VIDEO_FEATURE_MODELS[feature];
59
+ return this.overrides[feature] ?? GEMINI_VIDEO_FEATURE_MODELS[feature];
60
+ }
61
+
62
+ /**
63
+ * Check if a feature has a custom override
64
+ */
65
+ hasOverride(feature: ImageFeatureType | VideoFeatureType): boolean {
66
+ return feature in this.overrides;
67
+ }
68
+
69
+ /**
70
+ * Get all current overrides
71
+ */
72
+ getOverrides(): ModelOverrideMap {
73
+ return { ...this.overrides };
28
74
  }
29
75
  }
30
76
 
@@ -5,7 +5,9 @@
5
5
 
6
6
  import type {
7
7
  GeminiImageInput,
8
+ GeminiImageGenerationResult,
8
9
  VideoGenerationInput,
10
+ VideoGenerationResult,
9
11
  VideoGenerationProgress,
10
12
  } from "../../domain/entities";
11
13
  import { geminiTextGenerationService } from "./gemini-text-generation.service";
@@ -20,13 +22,29 @@ export interface ExecutionOptions {
20
22
  onProgress?: (progress: number) => void;
21
23
  }
22
24
 
25
+ export type GenerationInput = {
26
+ type?: "text" | "image" | "video";
27
+ generateImage?: boolean;
28
+ prompt?: string;
29
+ images?: GeminiImageInput[];
30
+ generationConfig?: unknown;
31
+ image?: string;
32
+ negativePrompt?: string;
33
+ aspect_ratio?: string;
34
+ };
35
+
36
+ export type GenerationResult =
37
+ | string
38
+ | GeminiImageGenerationResult
39
+ | VideoGenerationResult;
40
+
23
41
  export class GenerationExecutor {
24
42
  private contentBuilder = new ContentBuilder();
25
43
  private responseFormatter = new ResponseFormatter();
26
44
 
27
- async executeGeneration<T>(
45
+ async executeGeneration<T = GenerationResult>(
28
46
  model: string,
29
- input: Record<string, unknown>,
47
+ input: GenerationInput,
30
48
  options?: ExecutionOptions,
31
49
  ): Promise<T> {
32
50
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -43,14 +61,13 @@ export class GenerationExecutor {
43
61
  }
44
62
 
45
63
  if (isVideoGeneration) {
46
- return this.executeVideoGeneration<T>(input, options);
64
+ return this.executeVideoGeneration(input, options) as T;
47
65
  }
48
66
 
49
67
  if (isImageGeneration) {
50
- const prompt = String(input.prompt || "");
51
- const images = input.images as GeminiImageInput[] | undefined;
52
- const result = await geminiImageGenerationService.generateImage(prompt, images);
53
- return result as T;
68
+ const prompt = String(input.prompt ?? "");
69
+ const images = input.images;
70
+ return geminiImageGenerationService.generateImage(prompt, images) as T;
54
71
  }
55
72
 
56
73
  const contents = this.contentBuilder.buildContents(input);
@@ -73,21 +90,21 @@ export class GenerationExecutor {
73
90
  /**
74
91
  * Execute video generation using Veo API
75
92
  */
76
- private async executeVideoGeneration<T>(
77
- input: Record<string, unknown>,
93
+ private async executeVideoGeneration(
94
+ input: GenerationInput,
78
95
  options?: ExecutionOptions,
79
- ): Promise<T> {
96
+ ): Promise<VideoGenerationResult> {
80
97
  if (typeof __DEV__ !== "undefined" && __DEV__) {
81
98
  // eslint-disable-next-line no-console
82
99
  console.log("[GenerationExecutor] executeVideoGeneration() called");
83
100
  }
84
101
 
85
102
  const videoInput: VideoGenerationInput = {
86
- prompt: String(input.prompt || ""),
87
- image: input.image as string | undefined,
88
- negativePrompt: input.negativePrompt as string | undefined,
103
+ prompt: String(input.prompt ?? ""),
104
+ image: input.image,
105
+ negativePrompt: input.negativePrompt,
89
106
  options: {
90
- aspectRatio: this.normalizeAspectRatio(input.aspect_ratio as string),
107
+ aspectRatio: this.normalizeAspectRatio(input.aspect_ratio),
91
108
  },
92
109
  };
93
110
 
@@ -109,10 +126,9 @@ export class GenerationExecutor {
109
126
  }
110
127
 
111
128
  return {
112
- video: { url: result.videoUrl },
113
129
  videoUrl: result.videoUrl,
114
130
  metadata: result.metadata,
115
- } as T;
131
+ };
116
132
  }
117
133
 
118
134
  /**
@@ -15,6 +15,7 @@ export { geminiVideoGenerationService } from "./gemini-video-generation.service"
15
15
  export { providerInitializer } from "./provider-initializer";
16
16
  export { jobProcessor } from "./job-processor";
17
17
  export { generationExecutor } from "./generation-executor";
18
+ export { featureModelSelector } from "./feature-model-selector";
18
19
 
19
20
  // Public provider API
20
21
  export {
@@ -26,6 +27,13 @@ export {
26
27
  export type { GeminiProviderConfig } from "./gemini-provider";
27
28
  export type { GeminiProviderConfig as AIProviderConfig } from "./provider-initializer";
28
29
 
30
+ // Generation executor types
31
+ export type {
32
+ GenerationInput,
33
+ GenerationResult,
34
+ ExecutionOptions,
35
+ } from "./generation-executor";
36
+
29
37
  // Re-export types from generation-content for convenience
30
38
  export type {
31
39
  IAIProvider,
@@ -7,6 +7,7 @@ import {
7
7
  GeminiErrorType,
8
8
  type GeminiErrorInfo,
9
9
  type GeminiApiError,
10
+ GeminiError,
10
11
  } from "../../domain/entities";
11
12
 
12
13
  const ERROR_PATTERNS: Array<{
@@ -112,3 +113,11 @@ export function isGeminiErrorRetryable(error: unknown): boolean {
112
113
  export function categorizeGeminiError(error: unknown): GeminiErrorType {
113
114
  return mapGeminiError(error).type;
114
115
  }
116
+
117
+ /**
118
+ * Create a GeminiError instance from an unknown error
119
+ */
120
+ export function createGeminiError(error: unknown): GeminiError {
121
+ const errorInfo = mapGeminiError(error);
122
+ return GeminiError.fromError(error, errorInfo);
123
+ }
@@ -6,6 +6,7 @@ export {
6
6
  mapGeminiError,
7
7
  isGeminiErrorRetryable,
8
8
  categorizeGeminiError,
9
+ createGeminiError,
9
10
  } from "./error-mapper.util";
10
11
 
11
12
  export {