@umituz/react-native-ai-generation-content 1.53.0 → 1.55.0

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-generation-content",
3
- "version": "1.53.0",
3
+ "version": "1.55.0",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -3,11 +3,20 @@
3
3
  * Shared utilities for extracting and processing generation results
4
4
  */
5
5
 
6
+ export interface FalErrorDetail {
7
+ msg?: string;
8
+ type?: string;
9
+ loc?: string[];
10
+ input?: string;
11
+ }
12
+
6
13
  export interface FalResult {
7
14
  video?: { url?: string };
8
15
  output?: string;
9
16
  images?: Array<{ url?: string }>;
10
17
  image?: { url?: string };
18
+ detail?: FalErrorDetail[];
19
+ error?: string;
11
20
  }
12
21
 
13
22
  export interface GenerationUrls {
@@ -15,11 +24,43 @@ export interface GenerationUrls {
15
24
  videoUrl?: string;
16
25
  }
17
26
 
27
+ /**
28
+ * Check if result contains an error and throw with appropriate message
29
+ */
30
+ function checkForErrors(result: FalResult): void {
31
+ // Check for FAL API error format: {detail: [{msg, type}]}
32
+ if (result.detail && Array.isArray(result.detail) && result.detail.length > 0) {
33
+ const firstError = result.detail[0];
34
+ const errorType = firstError?.type || "unknown";
35
+ const errorMsg = firstError?.msg || "Generation failed";
36
+
37
+ // Map error type to translation key
38
+ if (errorType === "content_policy_violation") {
39
+ throw new Error("error.generation.content_policy");
40
+ }
41
+
42
+ if (errorType.includes("validation")) {
43
+ throw new Error("error.generation.validation");
44
+ }
45
+
46
+ throw new Error(errorMsg);
47
+ }
48
+
49
+ // Check for simple error field
50
+ if (result.error) {
51
+ throw new Error(result.error);
52
+ }
53
+ }
54
+
18
55
  /**
19
56
  * Extracts image/video URL from FAL result
20
57
  * Handles various result formats from different FAL models
58
+ * Throws error if result contains error information
21
59
  */
22
60
  export function extractResultUrl(result: FalResult): GenerationUrls {
61
+ // First check for errors in the result
62
+ checkForErrors(result);
63
+
23
64
  // Video result
24
65
  if (result.video?.url) {
25
66
  return { videoUrl: result.video.url };
@@ -109,14 +109,29 @@ export function useVideoQueueGeneration(
109
109
  if (status.status === QUEUE_STATUS.COMPLETED || status.status === QUEUE_STATUS.FAILED) {
110
110
  if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; }
111
111
  if (status.status === QUEUE_STATUS.COMPLETED) {
112
- const result = await provider.getJobResult<FalResult>(model, requestId);
113
- await handleComplete(extractResultUrl(result));
112
+ try {
113
+ const result = await provider.getJobResult<FalResult>(model, requestId);
114
+ await handleComplete(extractResultUrl(result));
115
+ } catch (resultErr) {
116
+ // Handle errors when getting/extracting result (e.g., ValidationError, content policy)
117
+ const errorMessage = resultErr instanceof Error ? resultErr.message : "Generation failed";
118
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
119
+ console.error("[VideoQueueGeneration] Result error:", errorMessage);
120
+ }
121
+ await handleError(errorMessage);
122
+ }
114
123
  } else {
115
124
  await handleError("Generation failed");
116
125
  }
117
126
  }
118
127
  } catch (err) {
119
- if (typeof __DEV__ !== "undefined" && __DEV__) console.error("[VideoQueueGeneration] Poll error:", err);
128
+ // Handle polling errors - stop polling and show error to user
129
+ if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; }
130
+ const errorMessage = err instanceof Error ? err.message : "Generation failed";
131
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
132
+ console.error("[VideoQueueGeneration] Poll error:", errorMessage);
133
+ }
134
+ await handleError(errorMessage);
120
135
  }
121
136
  }, [handleComplete, handleError]);
122
137
 
@@ -16,6 +16,42 @@ interface FalErrorDetail {
16
16
  readonly url?: string;
17
17
  }
18
18
 
19
+ /**
20
+ * Error types for user-friendly messages
21
+ */
22
+ export const GenerationErrorType = {
23
+ CONTENT_POLICY: "content_policy",
24
+ VALIDATION: "validation",
25
+ NETWORK: "network",
26
+ TIMEOUT: "timeout",
27
+ RATE_LIMIT: "rate_limit",
28
+ QUOTA_EXCEEDED: "quota_exceeded",
29
+ UNKNOWN: "unknown",
30
+ } as const;
31
+
32
+ export type GenerationErrorTypeValue = typeof GenerationErrorType[keyof typeof GenerationErrorType];
33
+
34
+ /**
35
+ * Structured generation error
36
+ */
37
+ export interface GenerationError extends Error {
38
+ readonly errorType: GenerationErrorTypeValue;
39
+ readonly translationKey: string;
40
+ }
41
+
42
+ /**
43
+ * Create a structured generation error
44
+ */
45
+ function createGenerationError(
46
+ type: GenerationErrorTypeValue,
47
+ message: string,
48
+ ): GenerationError {
49
+ const error = new Error(message) as GenerationError;
50
+ (error as { errorType: GenerationErrorTypeValue }).errorType = type;
51
+ (error as { translationKey: string }).translationKey = `error.generation.${type}`;
52
+ return error;
53
+ }
54
+
19
55
  /**
20
56
  * Check if result contains a FAL API error response
21
57
  * FAL sometimes returns errors with COMPLETED status
@@ -40,22 +76,74 @@ export function checkFalApiError(result: unknown): void {
40
76
 
41
77
  // Throw specific error based on type
42
78
  if (errorType === "content_policy_violation") {
43
- throw new Error(`Content policy violation: ${errorMsg}`);
79
+ throw createGenerationError(GenerationErrorType.CONTENT_POLICY, errorMsg);
80
+ }
81
+
82
+ if (errorType === "validation_error" || errorType.includes("validation")) {
83
+ throw createGenerationError(GenerationErrorType.VALIDATION, errorMsg);
44
84
  }
45
85
 
46
- throw new Error(errorMsg);
86
+ throw createGenerationError(GenerationErrorType.UNKNOWN, errorMsg);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Check if error is a GenerationError with translation key
92
+ */
93
+ export function isGenerationError(error: unknown): error is GenerationError {
94
+ return error instanceof Error && "errorType" in error && "translationKey" in error;
95
+ }
96
+
97
+ /**
98
+ * Get translation key from error (returns key if GenerationError, null otherwise)
99
+ */
100
+ export function getErrorTranslationKey(error: unknown): string | null {
101
+ if (isGenerationError(error)) {
102
+ return error.translationKey;
103
+ }
104
+
105
+ // Check for content policy in error message
106
+ const message = error instanceof Error ? error.message : String(error);
107
+ const lowerMessage = message.toLowerCase();
108
+
109
+ if (lowerMessage.includes("content_policy") || lowerMessage.includes("policy violation")) {
110
+ return `error.generation.${GenerationErrorType.CONTENT_POLICY}`;
111
+ }
112
+
113
+ if (lowerMessage.includes("rate limit") || lowerMessage.includes("429")) {
114
+ return `error.generation.${GenerationErrorType.RATE_LIMIT}`;
115
+ }
116
+
117
+ if (lowerMessage.includes("timeout") || lowerMessage.includes("timed out")) {
118
+ return `error.generation.${GenerationErrorType.TIMEOUT}`;
119
+ }
120
+
121
+ if (lowerMessage.includes("network") || lowerMessage.includes("connection")) {
122
+ return `error.generation.${GenerationErrorType.NETWORK}`;
47
123
  }
124
+
125
+ return null;
48
126
  }
49
127
 
50
128
  /**
51
129
  * Extract error message from FAL API and other error formats
52
130
  * Supports: Error instances, FAL API errors, generic objects
131
+ * Returns translation key if available, otherwise original message
53
132
  */
54
133
  export function extractErrorMessage(
55
134
  error: unknown,
56
135
  defaultMessage = "Processing failed",
57
136
  debugPrefix?: string,
58
137
  ): string {
138
+ // First check if this is a GenerationError with translation key
139
+ const translationKey = getErrorTranslationKey(error);
140
+ if (translationKey) {
141
+ if (__DEV__ && debugPrefix) {
142
+ console.error(`[${debugPrefix}] Error (translation key):`, translationKey);
143
+ }
144
+ return translationKey;
145
+ }
146
+
59
147
  let message = defaultMessage;
60
148
 
61
149
  if (error instanceof Error) {
@@ -65,6 +153,11 @@ export function extractErrorMessage(
65
153
 
66
154
  // FAL API error format: {detail: [{msg, type, loc}]}
67
155
  if (Array.isArray(errObj.detail) && errObj.detail[0]?.msg) {
156
+ const detailType = errObj.detail[0]?.type;
157
+ // Check for content policy in FAL API response
158
+ if (detailType === "content_policy_violation") {
159
+ return `error.generation.${GenerationErrorType.CONTENT_POLICY}`;
160
+ }
68
161
  message = String(errObj.detail[0].msg);
69
162
  } else if (errObj.detail) {
70
163
  message = JSON.stringify(errObj.detail);