@umituz/react-native-ai-gemini-provider 3.0.41 → 3.0.43

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.
Files changed (89) hide show
  1. package/package.json +1 -1
  2. package/src/application/builders/config-builder.ts +102 -0
  3. package/src/application/builders/index.ts +8 -0
  4. package/src/application/dtos/generation-request.dto.ts +89 -0
  5. package/src/application/dtos/index.ts +8 -0
  6. package/src/application/index.ts +16 -0
  7. package/src/application/providers/gemini-provider.ts +135 -0
  8. package/src/application/providers/index.ts +6 -0
  9. package/src/application/use-cases/generate-json.use-case.ts +73 -0
  10. package/src/application/use-cases/generate-text.use-case.ts +81 -0
  11. package/src/application/use-cases/index.ts +20 -0
  12. package/src/application/use-cases/stream-content.use-case.ts +46 -0
  13. package/src/domain/entities/error.types.ts +0 -5
  14. package/src/domain/entities/gemini.types.ts +3 -1
  15. package/src/domain/index.ts +16 -0
  16. package/src/domain/repositories/index.ts +19 -0
  17. package/src/domain/repositories/streaming.repository.ts +41 -0
  18. package/src/domain/repositories/structured-text.repository.ts +41 -0
  19. package/src/domain/repositories/text-generation.repository.ts +38 -0
  20. package/src/domain/services/validation.service.ts +157 -0
  21. package/src/domain/value-objects/api-key.vo.ts +55 -0
  22. package/src/domain/value-objects/index.ts +8 -0
  23. package/src/domain/value-objects/model-name.vo.ts +66 -0
  24. package/src/domain/value-objects/timeout.vo.ts +69 -0
  25. package/src/index.ts +110 -25
  26. package/src/infrastructure/external/gemini-client.singleton.ts +49 -0
  27. package/src/infrastructure/external/gemini-sdk.adapter.ts +143 -0
  28. package/src/infrastructure/external/index.ts +7 -0
  29. package/src/infrastructure/index.ts +16 -0
  30. package/src/infrastructure/mappers/content.mapper.ts +80 -0
  31. package/src/infrastructure/mappers/error.mapper.ts +152 -0
  32. package/src/infrastructure/mappers/index.ts +7 -0
  33. package/src/infrastructure/mappers/response.mapper.ts +165 -0
  34. package/src/infrastructure/repositories/base-gemini.repository.ts +94 -0
  35. package/src/infrastructure/repositories/gemini-streaming.repository.impl.ts +119 -0
  36. package/src/infrastructure/repositories/gemini-structured-text.repository.impl.ts +108 -0
  37. package/src/infrastructure/repositories/gemini-text.repository.impl.ts +76 -0
  38. package/src/infrastructure/repositories/index.ts +10 -0
  39. package/src/infrastructure/utils/index.ts +6 -0
  40. package/src/presentation/hooks/index.ts +8 -0
  41. package/src/presentation/hooks/use-gemini.hook.ts +181 -0
  42. package/src/presentation/hooks/use-operation-manager.hook.ts +67 -0
  43. package/src/presentation/index.ts +10 -0
  44. package/src/presentation/providers/gemini-provider.tsx +93 -0
  45. package/src/presentation/providers/index.ts +10 -0
  46. package/dist/domain/entities/error.types.d.ts +0 -96
  47. package/dist/domain/entities/gemini.types.d.ts +0 -128
  48. package/dist/domain/entities/index.d.ts +0 -6
  49. package/dist/domain/entities/models.d.ts +0 -23
  50. package/dist/index.d.ts +0 -15
  51. package/dist/infrastructure/services/BaseService.d.ts +0 -29
  52. package/dist/infrastructure/services/ChatSession.d.ts +0 -63
  53. package/dist/infrastructure/services/GeminiClient.d.ts +0 -16
  54. package/dist/infrastructure/services/GeminiProvider.d.ts +0 -10
  55. package/dist/infrastructure/services/Streaming.d.ts +0 -7
  56. package/dist/infrastructure/services/StructuredText.d.ts +0 -6
  57. package/dist/infrastructure/services/TextGeneration.d.ts +0 -8
  58. package/dist/infrastructure/services/index.d.ts +0 -6
  59. package/dist/infrastructure/telemetry/TelemetryHooks.d.ts +0 -41
  60. package/dist/infrastructure/telemetry/index.d.ts +0 -4
  61. package/dist/infrastructure/utils/async/execute-state.util.d.ts +0 -49
  62. package/dist/infrastructure/utils/async/index.d.ts +0 -4
  63. package/dist/infrastructure/utils/content-mapper.util.d.ts +0 -45
  64. package/dist/infrastructure/utils/error-mapper.util.d.ts +0 -2
  65. package/dist/infrastructure/utils/gemini-data-transformer.util.d.ts +0 -2
  66. package/dist/infrastructure/utils/json-parser.util.d.ts +0 -9
  67. package/dist/infrastructure/utils/stream-processor.util.d.ts +0 -14
  68. package/dist/presentation/hooks/index.d.ts +0 -1
  69. package/dist/presentation/hooks/useGemini.d.ts +0 -17
  70. package/dist/presentation/hooks/useOperationManager.d.ts +0 -23
  71. package/dist/providers/ConfigBuilder.d.ts +0 -46
  72. package/dist/providers/ProviderFactory.d.ts +0 -25
  73. package/dist/providers/index.d.ts +0 -7
  74. package/src/infrastructure/services/BaseService.ts +0 -53
  75. package/src/infrastructure/services/ChatSession.ts +0 -199
  76. package/src/infrastructure/services/GeminiClient.ts +0 -112
  77. package/src/infrastructure/services/Streaming.ts +0 -56
  78. package/src/infrastructure/services/StructuredText.ts +0 -57
  79. package/src/infrastructure/services/TextGeneration.ts +0 -57
  80. package/src/infrastructure/telemetry/TelemetryHooks.ts +0 -110
  81. package/src/infrastructure/utils/async/execute-state.util.ts +0 -93
  82. package/src/infrastructure/utils/content-mapper.util.ts +0 -175
  83. package/src/infrastructure/utils/error-mapper.util.ts +0 -145
  84. package/src/infrastructure/utils/gemini-data-transformer.util.ts +0 -40
  85. package/src/infrastructure/utils/text-calculations.util.ts +0 -51
  86. package/src/presentation/hooks/useGemini.ts +0 -125
  87. package/src/presentation/hooks/useOperationManager.ts +0 -88
  88. package/src/providers/ConfigBuilder.ts +0 -112
  89. package/src/providers/ProviderFactory.ts +0 -65
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Streaming Repository Interface
3
+ * Domain layer contract for streaming operations
4
+ */
5
+
6
+ import type { GeminiContent, GeminiGenerationConfig } from "../entities";
7
+
8
+ export interface StreamingRequest {
9
+ model: string;
10
+ contents: GeminiContent[];
11
+ onChunk: (text: string) => void;
12
+ generationConfig?: GeminiGenerationConfig;
13
+ signal?: AbortSignal;
14
+ }
15
+
16
+ export interface IStreamingRepository {
17
+ /**
18
+ * Stream text content from Gemini API
19
+ * @param request - Streaming request parameters
20
+ * @returns Complete generated text
21
+ * @throws GeminiError on API errors
22
+ */
23
+ stream(request: StreamingRequest): Promise<string>;
24
+
25
+ /**
26
+ * Stream text from a simple prompt
27
+ * @param model - Model name
28
+ * @param prompt - Text prompt
29
+ * @param onChunk - Callback for each chunk
30
+ * @param config - Optional generation config
31
+ * @param signal - Optional abort signal
32
+ * @returns Complete generated text
33
+ */
34
+ streamText(
35
+ model: string,
36
+ prompt: string,
37
+ onChunk: (text: string) => void,
38
+ config?: GeminiGenerationConfig,
39
+ signal?: AbortSignal
40
+ ): Promise<string>;
41
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Structured Text Repository Interface
3
+ * Domain layer contract for structured JSON generation
4
+ */
5
+
6
+ import type { GeminiContent, GeminiGenerationConfig } from "../entities";
7
+
8
+ export interface StructuredGenerationRequest {
9
+ model: string;
10
+ prompt: string;
11
+ schema: Record<string, unknown>;
12
+ config?: Omit<GeminiGenerationConfig, "responseMimeType" | "responseSchema">;
13
+ signal?: AbortSignal;
14
+ }
15
+
16
+ export interface IStructuredTextRepository {
17
+ /**
18
+ * Generate structured JSON response from Gemini API
19
+ * @param request - Structured generation request
20
+ * @returns Parsed JSON response
21
+ * @throws GeminiError on API errors
22
+ */
23
+ generateStructured<T>(request: StructuredGenerationRequest): Promise<T>;
24
+
25
+ /**
26
+ * Generate structured JSON from contents
27
+ * @param model - Model name
28
+ * @param contents - Content array
29
+ * @param schema - JSON schema
30
+ * @param config - Optional generation config
31
+ * @param signal - Optional abort signal
32
+ * @returns Parsed JSON response
33
+ */
34
+ generateStructuredFromContents<T>(
35
+ model: string,
36
+ contents: GeminiContent[],
37
+ schema: Record<string, unknown>,
38
+ config?: GeminiGenerationConfig,
39
+ signal?: AbortSignal
40
+ ): Promise<T>;
41
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Text Generation Repository Interface
3
+ * Domain layer contract for text generation operations
4
+ */
5
+
6
+ import type { GeminiContent, GeminiGenerationConfig, GeminiResponse } from "../entities";
7
+
8
+ export interface TextGenerationRequest {
9
+ model: string;
10
+ contents: GeminiContent[];
11
+ generationConfig?: GeminiGenerationConfig;
12
+ signal?: AbortSignal;
13
+ }
14
+
15
+ export interface ITextGenerationRepository {
16
+ /**
17
+ * Generate text content from Gemini API
18
+ * @param request - Generation request parameters
19
+ * @returns Generated response
20
+ * @throws GeminiError on API errors
21
+ */
22
+ generate(request: TextGenerationRequest): Promise<GeminiResponse>;
23
+
24
+ /**
25
+ * Generate simple text from a prompt
26
+ * @param model - Model name
27
+ * @param prompt - Text prompt
28
+ * @param config - Optional generation config
29
+ * @param signal - Optional abort signal
30
+ * @returns Generated text
31
+ */
32
+ generateText(
33
+ model: string,
34
+ prompt: string,
35
+ config?: GeminiGenerationConfig,
36
+ signal?: AbortSignal
37
+ ): Promise<string>;
38
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Domain Validation Service
3
+ * Pure validation functions for domain entities
4
+ */
5
+
6
+ import type { GeminiContent } from "../entities";
7
+
8
+ export class ValidationError extends Error {
9
+ constructor(message: string) {
10
+ super(message);
11
+ this.name = "ValidationError";
12
+ }
13
+ }
14
+
15
+ export class ValidationService {
16
+ /**
17
+ * Validate prompt text
18
+ */
19
+ validatePrompt(prompt: string): void {
20
+ if (!prompt || typeof prompt !== "string") {
21
+ throw new ValidationError("Prompt must be a string");
22
+ }
23
+
24
+ const trimmed = prompt.trim();
25
+ if (trimmed.length < 3) {
26
+ throw new ValidationError("Prompt must be at least 3 characters");
27
+ }
28
+
29
+ if (trimmed.length > 100000) {
30
+ throw new ValidationError("Prompt too long (max 100k characters)");
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Validate JSON schema object
36
+ */
37
+ validateSchema(schema: unknown): void {
38
+ if (!schema || typeof schema !== "object") {
39
+ throw new ValidationError("Schema must be an object");
40
+ }
41
+
42
+ if (Array.isArray(schema)) {
43
+ throw new ValidationError("Schema cannot be an array");
44
+ }
45
+
46
+ const keys = Object.keys(schema);
47
+ if (keys.length === 0) {
48
+ throw new ValidationError("Schema cannot be empty");
49
+ }
50
+
51
+ // Recursively validate nested schema properties
52
+ for (const value of Object.values(schema)) {
53
+ if (typeof value === "object" && value !== null) {
54
+ this.validateSchema(value);
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Validate contents array
61
+ */
62
+ validateContents(contents: GeminiContent[]): void {
63
+ if (!Array.isArray(contents)) {
64
+ throw new ValidationError("Contents must be an array");
65
+ }
66
+
67
+ if (contents.length === 0) {
68
+ throw new ValidationError("Contents cannot be empty");
69
+ }
70
+
71
+ if (contents.length > 1000) {
72
+ throw new ValidationError("Too many content items (max 1000)");
73
+ }
74
+
75
+ // Validate each content item
76
+ for (const content of contents) {
77
+ this.validateContent(content);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Validate single content item
83
+ */
84
+ private validateContent(content: GeminiContent): void {
85
+ if (!content.role || typeof content.role !== "string") {
86
+ throw new ValidationError("Content role is required");
87
+ }
88
+
89
+ if (!content.parts || !Array.isArray(content.parts)) {
90
+ throw new ValidationError("Content parts must be an array");
91
+ }
92
+
93
+ if (content.parts.length === 0) {
94
+ throw new ValidationError("Content parts cannot be empty");
95
+ }
96
+
97
+ // Validate each part
98
+ for (const part of content.parts) {
99
+ const hasText = "text" in part && typeof part.text === "string" && part.text.length > 0;
100
+ const hasInlineData = "inlineData" in part && part.inlineData !== null;
101
+
102
+ if (!hasText && !hasInlineData) {
103
+ throw new ValidationError("Each part must have text or inlineData");
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Validate model name
110
+ */
111
+ validateModelName(model: string): void {
112
+ if (!model || typeof model !== "string") {
113
+ throw new ValidationError("Model name is required");
114
+ }
115
+
116
+ if (!model.startsWith("gemini-")) {
117
+ throw new ValidationError("Model name must start with 'gemini-'");
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Validate callback function
123
+ */
124
+ validateCallback(callback: unknown, name: string): void {
125
+ if (typeof callback !== "function") {
126
+ throw new ValidationError(`${name} must be a function`);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Validate generation config
132
+ */
133
+ validateConfig(config: unknown): void {
134
+ if (!config) return; // Config is optional
135
+
136
+ if (typeof config !== "object" || Array.isArray(config)) {
137
+ throw new ValidationError("Config must be an object");
138
+ }
139
+
140
+ // Validate temperature if present
141
+ const cfg = config as Record<string, unknown>;
142
+ if (cfg.temperature !== undefined) {
143
+ const temp = cfg.temperature as number;
144
+ if (typeof temp !== "number" || temp < 0 || temp > 2) {
145
+ throw new ValidationError("Temperature must be between 0 and 2");
146
+ }
147
+ }
148
+
149
+ // Validate max output tokens if present
150
+ if (cfg.maxOutputTokens !== undefined) {
151
+ const tokens = cfg.maxOutputTokens as number;
152
+ if (typeof tokens !== "number" || tokens < 1 || tokens > 8192) {
153
+ throw new ValidationError("maxOutputTokens must be between 1 and 8192");
154
+ }
155
+ }
156
+ }
157
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * API Key Value Object
3
+ * Encapsulates API key validation and formatting
4
+ */
5
+
6
+ export class ApiKey {
7
+ private static readonly MIN_LENGTH = 10;
8
+ private static readonly PREFIX = "AIza";
9
+
10
+ private constructor(private readonly value: string) {}
11
+
12
+ /**
13
+ * Create a validated API key
14
+ * @throws Error if validation fails
15
+ */
16
+ static create(value: string): ApiKey {
17
+ const trimmed = value?.trim() || "";
18
+
19
+ if (trimmed.length < ApiKey.MIN_LENGTH) {
20
+ throw new Error(
21
+ `API key must be at least ${ApiKey.MIN_LENGTH} characters`
22
+ );
23
+ }
24
+
25
+ if (!trimmed.startsWith(ApiKey.PREFIX)) {
26
+ throw new Error(
27
+ `API key must start with "${ApiKey.PREFIX}"`
28
+ );
29
+ }
30
+
31
+ return new ApiKey(trimmed);
32
+ }
33
+
34
+ /**
35
+ * Get the API key value
36
+ */
37
+ getValue(): string {
38
+ return this.value;
39
+ }
40
+
41
+ /**
42
+ * Check if API key equals another
43
+ */
44
+ equals(other: ApiKey): boolean {
45
+ return this.value === other.value;
46
+ }
47
+
48
+ /**
49
+ * Get masked version for logging (e.g., "AIza...xyz")
50
+ */
51
+ toMasked(): string {
52
+ if (this.value.length <= 10) return "***";
53
+ return `${this.value.substring(0, 6)}...${this.value.substring(this.value.length - 3)}`;
54
+ }
55
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Domain Value Objects
3
+ * Immutable, self-validating value objects
4
+ */
5
+
6
+ export { ApiKey } from "./api-key.vo";
7
+ export { ModelName } from "./model-name.vo";
8
+ export { Timeout } from "./timeout.vo";
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Model Name Value Object
3
+ * Encapsulates Gemini model name validation
4
+ */
5
+
6
+ export class ModelName {
7
+ private static readonly PREFIX = "gemini-";
8
+
9
+ private constructor(private readonly value: string) {}
10
+
11
+ /**
12
+ * Create a validated model name
13
+ * @throws Error if validation fails
14
+ */
15
+ static create(value: string): ModelName {
16
+ const trimmed = value?.trim() || "";
17
+
18
+ if (!trimmed) {
19
+ throw new Error("Model name cannot be empty");
20
+ }
21
+
22
+ if (!trimmed.startsWith(ModelName.PREFIX)) {
23
+ throw new Error(
24
+ `Model name must start with "${ModelName.PREFIX}"`
25
+ );
26
+ }
27
+
28
+ return new ModelName(trimmed);
29
+ }
30
+
31
+ /**
32
+ * Get the model name value
33
+ */
34
+ getValue(): string {
35
+ return this.value;
36
+ }
37
+
38
+ /**
39
+ * Check if this is a Flash model (faster, cheaper)
40
+ */
41
+ isFlash(): boolean {
42
+ return this.value.includes("flash");
43
+ }
44
+
45
+ /**
46
+ * Check if this is a Pro model (higher quality)
47
+ */
48
+ isPro(): boolean {
49
+ return this.value.includes("pro");
50
+ }
51
+
52
+ /**
53
+ * Get model family (e.g., "gemini-2.5-flash" -> "2.5")
54
+ */
55
+ getVersion(): string {
56
+ const match = this.value.match(/gemini-([\d.]+)/);
57
+ return match ? match[1] : "unknown";
58
+ }
59
+
60
+ /**
61
+ * Check if model name equals another
62
+ */
63
+ equals(other: ModelName): boolean {
64
+ return this.value === other.value;
65
+ }
66
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Timeout Value Object
3
+ * Encapsulates timeout duration validation
4
+ */
5
+
6
+ export class Timeout {
7
+ private static readonly MIN_MS = 1;
8
+ private static readonly MAX_MS = 300000; // 5 minutes
9
+
10
+ private constructor(private readonly valueMs: number) {}
11
+
12
+ /**
13
+ * Create a validated timeout in milliseconds
14
+ * @throws Error if validation fails
15
+ */
16
+ static create(milliseconds: number): Timeout {
17
+ const value = milliseconds ?? 30000; // Default 30s
18
+
19
+ if (value < Timeout.MIN_MS || value > Timeout.MAX_MS) {
20
+ throw new Error(
21
+ `Timeout must be between ${Timeout.MIN_MS}ms and ${Timeout.MAX_MS}ms`
22
+ );
23
+ }
24
+
25
+ return new Timeout(value);
26
+ }
27
+
28
+ /**
29
+ * Create timeout in seconds
30
+ */
31
+ static fromSeconds(seconds: number): Timeout {
32
+ return Timeout.create(seconds * 1000);
33
+ }
34
+
35
+ /**
36
+ * Get timeout in milliseconds
37
+ */
38
+ toMilliseconds(): number {
39
+ return this.valueMs;
40
+ }
41
+
42
+ /**
43
+ * Get timeout in seconds
44
+ */
45
+ toSeconds(): number {
46
+ return Math.round(this.valueMs / 1000);
47
+ }
48
+
49
+ /**
50
+ * Check if this is a short timeout (< 10s)
51
+ */
52
+ isShort(): boolean {
53
+ return this.valueMs < 10000;
54
+ }
55
+
56
+ /**
57
+ * Check if this is a long timeout (> 60s)
58
+ */
59
+ isLong(): boolean {
60
+ return this.valueMs > 60000;
61
+ }
62
+
63
+ /**
64
+ * Check if timeout equals another
65
+ */
66
+ equals(other: Timeout): boolean {
67
+ return this.valueMs === other.valueMs;
68
+ }
69
+ }
package/src/index.ts CHANGED
@@ -1,9 +1,17 @@
1
1
  /**
2
2
  * @umituz/react-native-ai-gemini-provider
3
3
  * Google Gemini AI provider for React Native applications
4
+ *
5
+ * Clean DDD Architecture - Production Ready
6
+ *
7
+ * @version 4.0.0
4
8
  */
5
9
 
6
- // Domain Types
10
+ // ============================================================================
11
+ // DOMAIN LAYER - Core business logic and types
12
+ // ============================================================================
13
+
14
+ // Domain Entities
7
15
  export type {
8
16
  GeminiConfig,
9
17
  GeminiGenerationConfig,
@@ -29,31 +37,108 @@ export {
29
37
  GeminiErrorType,
30
38
  GeminiError,
31
39
  GEMINI_MODELS,
32
- DEFAULT_MODELS
40
+ DEFAULT_MODELS,
33
41
  } from "./domain/entities";
34
42
 
35
- // Services
36
- export { geminiClient } from "./infrastructure/services/GeminiClient";
43
+ // Value Objects
44
+ export { ApiKey, ModelName, Timeout } from "./domain/value-objects";
45
+
46
+ // Domain Services
47
+ export { ValidationService, ValidationError } from "./domain/services/validation.service";
48
+
49
+ // Repository Interfaces
50
+ export type {
51
+ ITextGenerationRepository,
52
+ TextGenerationRequest,
53
+ } from "./domain/repositories/text-generation.repository";
54
+
55
+ export type {
56
+ IStreamingRepository,
57
+ StreamingRequest,
58
+ } from "./domain/repositories/streaming.repository";
59
+
60
+ export type {
61
+ IStructuredTextRepository,
62
+ StructuredGenerationRequest,
63
+ } from "./domain/repositories/structured-text.repository";
64
+
65
+ // ============================================================================
66
+ // APPLICATION LAYER - Use cases and orchestration
67
+ // ============================================================================
68
+
69
+ // Use Cases
37
70
  export {
38
- createChatSession,
39
- sendChatMessage,
40
- buildChatHistory,
41
- trimChatHistory,
42
- type ChatSendResult,
43
- type ChatHistoryMessage,
44
- type SendChatMessageOptions,
45
- } from "./infrastructure/services/ChatSession";
46
- export { textGeneration } from "./infrastructure/services/TextGeneration";
47
- export { structuredText } from "./infrastructure/services/StructuredText";
48
- export { streaming } from "./infrastructure/services/Streaming";
49
-
50
- // React Hook
51
- export { useGemini } from "./presentation/hooks/useGemini";
52
- export type { UseGeminiOptions, UseGeminiReturn } from "./presentation/hooks/useGemini";
53
-
54
- // Provider Configuration & Factory
55
- export { ConfigBuilder, providerFactory } from "./providers/ProviderFactory";
71
+ GenerateTextUseCase,
72
+ StreamContentUseCase,
73
+ GenerateJSONUseCase,
74
+ } from "./application/use-cases";
75
+
56
76
  export type {
57
- ProviderConfig,
58
- ProviderFactoryOptions,
59
- } from "./providers/ProviderFactory";
77
+ GenerateTextOptions,
78
+ GenerateTextResult,
79
+ StreamContentOptions,
80
+ GenerateJSONOptions,
81
+ GenerateJSONResult,
82
+ } from "./application/use-cases";
83
+
84
+ // Builders
85
+ export { GeminiConfigBuilder } from "./application/builders";
86
+
87
+ export type { GeminiConfigOptions } from "./application/builders";
88
+
89
+ // Providers
90
+ export { geminiProvider, GeminiProviderClass } from "./application/providers";
91
+
92
+ export type { GeminiProvider } from "./application/providers";
93
+
94
+ // ============================================================================
95
+ // INFRASTRUCTURE LAYER - External integrations
96
+ // ============================================================================
97
+
98
+ // Mappers
99
+ export {
100
+ ContentMapper,
101
+ ResponseMapper,
102
+ ErrorMapper,
103
+ } from "./infrastructure/mappers";
104
+
105
+ // SDK Adapter
106
+ export {
107
+ GeminiSDKAdapter,
108
+ GeminiClient,
109
+ geminiClient,
110
+ } from "./infrastructure/external";
111
+
112
+ // Repository Implementations
113
+ export {
114
+ BaseGeminiRepository,
115
+ GeminiTextRepository,
116
+ GeminiStreamingRepository,
117
+ GeminiStructuredTextRepository,
118
+ } from "./infrastructure/repositories";
119
+
120
+ // Utilities
121
+ export { parseJsonResponse } from "./infrastructure/utils/json-parser.util";
122
+
123
+ // ============================================================================
124
+ // PRESENTATION LAYER - React hooks and providers
125
+ // ============================================================================
126
+
127
+ // React Hooks
128
+ export { useGemini, useOperationManager } from "./presentation/hooks";
129
+
130
+ export type {
131
+ UseGeminiOptions,
132
+ UseGeminiReturn,
133
+ } from "./presentation/hooks";
134
+
135
+ export type { OperationManager } from "./presentation/hooks/use-operation-manager.hook";
136
+
137
+ // React Provider Component
138
+ export {
139
+ GeminiProviderComponent,
140
+ useGeminiContext,
141
+ useGeminiInitializer,
142
+ } from "./presentation/providers";
143
+
144
+ export type { GeminiProviderProps } from "./presentation/providers";
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Gemini Client Singleton
3
+ * Global access point for Gemini SDK adapter
4
+ */
5
+
6
+ import { GeminiSDKAdapter } from "./gemini-sdk.adapter";
7
+
8
+ let instance: GeminiSDKAdapter | null = null;
9
+
10
+ export class GeminiClient {
11
+ private constructor() {}
12
+
13
+ /**
14
+ * Get the singleton instance
15
+ */
16
+ static getInstance(): GeminiSDKAdapter {
17
+ if (!instance) {
18
+ instance = new GeminiSDKAdapter();
19
+ }
20
+ return instance;
21
+ }
22
+
23
+ /**
24
+ * Export adapter class for type safety
25
+ */
26
+ static Adapter = GeminiSDKAdapter;
27
+
28
+ /**
29
+ * Initialize the client (convenience method)
30
+ */
31
+ static initialize(apiKey: string): void {
32
+ GeminiClient.getInstance().initialize(apiKey);
33
+ }
34
+
35
+ /**
36
+ * Reset the client (for testing)
37
+ */
38
+ static reset(): void {
39
+ if (instance) {
40
+ instance.reset();
41
+ instance = null;
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Export a simpler interface for backward compatibility
48
+ */
49
+ export const geminiClient = GeminiClient.getInstance();