@umituz/react-native-ai-fal-provider 1.0.2 → 1.0.4

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,24 +1,24 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-fal-provider",
3
- "version": "1.0.2",
4
- "description": "FAL AI provider service for React Native applications - client wrapper, error handling, and utilities",
3
+ "version": "1.0.4",
4
+ "description": "FAL AI provider for React Native - implements IAIProvider interface for unified AI generation",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
8
- "typecheck": "echo 'TypeScript validation passed'",
9
- "lint": "echo 'Lint passed'",
10
- "version:patch": "npm version patch -m 'chore: release v%s'",
11
- "version:minor": "npm version minor -m 'chore: release v%s'",
12
- "version:major": "npm version major -m 'chore: release v%s'"
8
+ "typecheck": "tsc --noEmit",
9
+ "lint": "eslint src --ext .ts,.tsx --max-warnings 0",
10
+ "lint:fix": "eslint src --ext .ts,.tsx --fix"
13
11
  },
14
12
  "keywords": [
15
13
  "react-native",
16
14
  "fal-ai",
17
15
  "ai",
16
+ "ai-provider",
18
17
  "text-to-image",
19
18
  "text-to-video",
20
19
  "image-to-video",
21
- "ai-generation"
20
+ "ai-generation",
21
+ "provider-agnostic"
22
22
  ],
23
23
  "author": "Umit UZ <umit@umituz.com>",
24
24
  "license": "MIT",
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@fal-ai/client": ">=0.6.0",
31
+ "@umituz/react-native-ai-generation-content": ">=1.16.0",
31
32
  "react": ">=18.2.0",
32
33
  "react-native": ">=0.74.0"
33
34
  },
@@ -36,9 +37,13 @@
36
37
  },
37
38
  "devDependencies": {
38
39
  "@types/react": "~19.1.10",
40
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
41
+ "@typescript-eslint/parser": "^7.0.0",
42
+ "@umituz/react-native-ai-generation-content": "^1.16.0",
43
+ "eslint": "^8.57.0",
39
44
  "react": "19.1.0",
40
45
  "react-native": "0.81.5",
41
- "typescript": "~5.9.2"
46
+ "typescript": "^5.3.0"
42
47
  },
43
48
  "publishConfig": {
44
49
  "access": "public"
package/src/index.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  /**
2
2
  * @umituz/react-native-ai-fal-provider
3
- * FAL AI provider service for React Native applications
3
+ * FAL AI provider for React Native - implements IAIProvider interface
4
4
  *
5
5
  * Usage:
6
6
  * import {
7
- * falClientService,
8
- * useFalGeneration,
9
- * mapFalError
7
+ * FalProvider,
8
+ * falProvider,
9
+ * providerRegistry,
10
10
  * } from '@umituz/react-native-ai-fal-provider';
11
+ * import { providerRegistry } from '@umituz/react-native-ai-generation-content';
12
+ *
13
+ * // Register provider at app startup
14
+ * falProvider.initialize({ apiKey: 'your-api-key' });
15
+ * providerRegistry.register(falProvider);
16
+ * providerRegistry.setActiveProvider('fal');
11
17
  */
12
18
 
13
19
  // =============================================================================
@@ -37,7 +43,13 @@ export type {
37
43
  } from "./domain/entities/error.types";
38
44
 
39
45
  // =============================================================================
40
- // INFRASTRUCTURE LAYER - Services
46
+ // INFRASTRUCTURE LAYER - Provider (IAIProvider Implementation)
47
+ // =============================================================================
48
+
49
+ export { FalProvider, falProvider } from "./infrastructure/services";
50
+
51
+ // =============================================================================
52
+ // INFRASTRUCTURE LAYER - Services (Low-level client)
41
53
  // =============================================================================
42
54
 
43
55
  export { falClientService } from "./infrastructure/services";
@@ -0,0 +1,177 @@
1
+ /**
2
+ * FAL Provider
3
+ * Implements IAIProvider interface for unified AI generation
4
+ */
5
+
6
+ import { fal } from "@fal-ai/client";
7
+ import type {
8
+ IAIProvider,
9
+ AIProviderConfig,
10
+ JobSubmission,
11
+ JobStatus,
12
+ AIJobStatusType,
13
+ SubscribeOptions,
14
+ } from "@umituz/react-native-ai-generation-content";
15
+ import type { FalQueueStatus, FalLogEntry } from "../../domain/entities/fal.types";
16
+
17
+ declare const __DEV__: boolean;
18
+
19
+ const DEFAULT_CONFIG = {
20
+ maxRetries: 3,
21
+ baseDelay: 1000,
22
+ maxDelay: 10000,
23
+ defaultTimeoutMs: 300000,
24
+ };
25
+
26
+ function mapFalStatusToJobStatus(status: FalQueueStatus): JobStatus {
27
+ const statusMap: Record<string, AIJobStatusType> = {
28
+ IN_QUEUE: "IN_QUEUE",
29
+ IN_PROGRESS: "IN_PROGRESS",
30
+ COMPLETED: "COMPLETED",
31
+ FAILED: "FAILED",
32
+ };
33
+
34
+ return {
35
+ status: statusMap[status.status] ?? "IN_PROGRESS",
36
+ logs: status.logs?.map((log: FalLogEntry) => ({
37
+ message: log.message,
38
+ level: log.level ?? "info",
39
+ timestamp: log.timestamp,
40
+ })),
41
+ queuePosition: status.queuePosition,
42
+ };
43
+ }
44
+
45
+ export class FalProvider implements IAIProvider {
46
+ readonly providerId = "fal";
47
+ readonly providerName = "FAL AI";
48
+
49
+ private apiKey: string | null = null;
50
+ private config: AIProviderConfig | null = null;
51
+ private initialized = false;
52
+
53
+ initialize(config: AIProviderConfig): void {
54
+ this.apiKey = config.apiKey;
55
+ this.config = { ...DEFAULT_CONFIG, ...config };
56
+
57
+ fal.config({
58
+ credentials: config.apiKey,
59
+ retry: {
60
+ maxRetries: config.maxRetries ?? DEFAULT_CONFIG.maxRetries,
61
+ baseDelay: config.baseDelay ?? DEFAULT_CONFIG.baseDelay,
62
+ maxDelay: config.maxDelay ?? DEFAULT_CONFIG.maxDelay,
63
+ },
64
+ });
65
+
66
+ this.initialized = true;
67
+
68
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
69
+ // eslint-disable-next-line no-console
70
+ console.log("[FalProvider] Initialized");
71
+ }
72
+ }
73
+
74
+ isInitialized(): boolean {
75
+ return this.initialized;
76
+ }
77
+
78
+ private validateInitialization(): void {
79
+ if (!this.apiKey || !this.initialized) {
80
+ throw new Error("FAL provider not initialized. Call initialize() first.");
81
+ }
82
+ }
83
+
84
+ async submitJob(
85
+ model: string,
86
+ input: Record<string, unknown>,
87
+ ): Promise<JobSubmission> {
88
+ this.validateInitialization();
89
+
90
+ const result = await fal.queue.submit(model, { input });
91
+
92
+ return {
93
+ requestId: result.request_id,
94
+ statusUrl: result.status_url,
95
+ responseUrl: result.response_url,
96
+ };
97
+ }
98
+
99
+ async getJobStatus(model: string, requestId: string): Promise<JobStatus> {
100
+ this.validateInitialization();
101
+
102
+ const status = await fal.queue.status(model, { requestId, logs: true });
103
+
104
+ return mapFalStatusToJobStatus(status as unknown as FalQueueStatus);
105
+ }
106
+
107
+ async getJobResult<T = unknown>(model: string, requestId: string): Promise<T> {
108
+ this.validateInitialization();
109
+
110
+ const result = await fal.queue.result(model, { requestId });
111
+
112
+ return result.data as T;
113
+ }
114
+
115
+ async subscribe<T = unknown>(
116
+ model: string,
117
+ input: Record<string, unknown>,
118
+ options?: SubscribeOptions<T>,
119
+ ): Promise<T> {
120
+ this.validateInitialization();
121
+
122
+ const timeoutMs = options?.timeoutMs ?? this.config?.defaultTimeoutMs ?? DEFAULT_CONFIG.defaultTimeoutMs;
123
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
124
+
125
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
126
+ // eslint-disable-next-line no-console
127
+ console.log("[FalProvider] Subscribe started:", { model, timeoutMs });
128
+ }
129
+
130
+ try {
131
+ const result = await Promise.race([
132
+ fal.subscribe(model, {
133
+ input,
134
+ onQueueUpdate: (update) => {
135
+ const jobStatus = mapFalStatusToJobStatus(update as unknown as FalQueueStatus);
136
+ options?.onQueueUpdate?.(jobStatus);
137
+ },
138
+ }),
139
+ new Promise<never>((_, reject) => {
140
+ timeoutId = setTimeout(
141
+ () => reject(new Error("FAL subscription timeout")),
142
+ timeoutMs,
143
+ );
144
+ }),
145
+ ]);
146
+
147
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
148
+ // eslint-disable-next-line no-console
149
+ console.log("[FalProvider] Subscribe completed:", { model });
150
+ }
151
+
152
+ options?.onResult?.(result as T);
153
+
154
+ return result as T;
155
+ } finally {
156
+ if (timeoutId) {
157
+ clearTimeout(timeoutId);
158
+ }
159
+ }
160
+ }
161
+
162
+ async run<T = unknown>(model: string, input: Record<string, unknown>): Promise<T> {
163
+ this.validateInitialization();
164
+
165
+ const result = await fal.run(model, { input });
166
+
167
+ return result as T;
168
+ }
169
+
170
+ reset(): void {
171
+ this.apiKey = null;
172
+ this.config = null;
173
+ this.initialized = false;
174
+ }
175
+ }
176
+
177
+ export const falProvider = new FalProvider();
@@ -4,3 +4,4 @@
4
4
  */
5
5
 
6
6
  export { falClientService } from "./fal-client.service";
7
+ export { FalProvider, falProvider } from "./fal-provider";