@umituz/react-native-ai-generation-content 1.68.0 → 1.70.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 +1 -1
- package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +8 -5
- package/src/domains/generation/wizard/infrastructure/builders/dynamic-step-builder.ts +1 -1
- package/src/domains/generation/wizard/presentation/hooks/generation-result.utils.ts +8 -16
- package/src/domains/generation/wizard/presentation/hooks/useGenerationPhase.ts +4 -1
- package/src/domains/generation/wizard/presentation/hooks/videoQueuePoller.ts +2 -2
- package/src/domains/image-to-video/infrastructure/services/image-to-video-executor.ts +0 -2
- package/src/domains/prompts/infrastructure/repositories/PromptHistoryRepository.ts +13 -53
- package/src/infrastructure/http/http-fetch-handler.ts +5 -1
- package/src/infrastructure/http/timeout.util.ts +6 -1
- package/src/infrastructure/services/video-feature-executor.service.ts +1 -3
- package/src/infrastructure/utils/error-factory.ts +15 -1
- package/src/infrastructure/utils/error-handlers.ts +0 -2
- package/src/infrastructure/utils/error-retry.ts +3 -3
- package/src/infrastructure/utils/index.ts +1 -1
- package/src/infrastructure/utils/message-extractor.ts +1 -2
- package/src/infrastructure/utils/extraction-types.ts +0 -37
- package/src/infrastructure/utils/fal-error-checker.ts +0 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.70.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",
|
|
@@ -11,7 +11,7 @@ import { QUEUE_STATUS, CREATION_STATUS } from "../../../../domain/constants/queu
|
|
|
11
11
|
import { DEFAULT_POLL_INTERVAL_MS } from "../../../../infrastructure/constants/polling.constants";
|
|
12
12
|
import {
|
|
13
13
|
extractResultUrl,
|
|
14
|
-
type
|
|
14
|
+
type GenerationResult,
|
|
15
15
|
} from "../../../generation/wizard/presentation/hooks/generation-result.utils";
|
|
16
16
|
import type { Creation } from "../../domain/entities/Creation";
|
|
17
17
|
import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
|
|
@@ -54,12 +54,15 @@ export function useProcessingJobsPoller(
|
|
|
54
54
|
|
|
55
55
|
pollJobRef.current = async (creation: Creation) => {
|
|
56
56
|
if (!userId || !creation.requestId || !creation.model) return;
|
|
57
|
+
|
|
57
58
|
if (pollingRef.current.has(creation.id)) return;
|
|
59
|
+
pollingRef.current.add(creation.id);
|
|
58
60
|
|
|
59
61
|
const provider = providerRegistry.getActiveProvider();
|
|
60
|
-
if (!provider || !provider.isInitialized())
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
if (!provider || !provider.isInitialized()) {
|
|
63
|
+
pollingRef.current.delete(creation.id);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
63
66
|
|
|
64
67
|
try {
|
|
65
68
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
@@ -73,7 +76,7 @@ export function useProcessingJobsPoller(
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
if (status.status === QUEUE_STATUS.COMPLETED) {
|
|
76
|
-
const result = await provider.getJobResult<
|
|
79
|
+
const result = await provider.getJobResult<GenerationResult>(creation.model, creation.requestId);
|
|
77
80
|
const urls = extractResultUrl(result);
|
|
78
81
|
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[ProcessingJobsPoller] Completed:", creation.id, urls);
|
|
79
82
|
|
|
@@ -8,6 +8,7 @@ import { StepType } from "../../../../../domain/entities/flow-config.types";
|
|
|
8
8
|
import type { StepDefinition } from "../../../../../domain/entities/flow-config.types";
|
|
9
9
|
import type { WizardStepConfig } from "../../domain/entities/wizard-step.types";
|
|
10
10
|
import type { WizardFeatureConfig, ScenarioBasedConfig } from "../../domain/entities/wizard-feature.types";
|
|
11
|
+
import { buildWizardConfigFromScenario } from "../../domain/entities/wizard-feature.types";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Convert wizard step config to flow step definition
|
|
@@ -104,7 +105,6 @@ export const quickBuildWizard = (
|
|
|
104
105
|
featureId: string,
|
|
105
106
|
scenarioConfig: ScenarioBasedConfig,
|
|
106
107
|
): StepDefinition[] => {
|
|
107
|
-
const { buildWizardConfigFromScenario } = require("../../domain/entities/wizard-feature.types");
|
|
108
108
|
const wizardConfig = buildWizardConfigFromScenario(featureId, scenarioConfig);
|
|
109
109
|
return buildFlowStepsFromWizard(wizardConfig, {
|
|
110
110
|
includePreview: true,
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generation Result Utilities
|
|
3
|
-
*
|
|
3
|
+
* Provider-agnostic utilities for extracting generation results
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export interface
|
|
6
|
+
export interface GenerationErrorDetail {
|
|
7
7
|
msg?: string;
|
|
8
8
|
type?: string;
|
|
9
9
|
loc?: string[];
|
|
10
10
|
input?: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export interface
|
|
13
|
+
export interface GenerationResult {
|
|
14
14
|
video?: { url?: string };
|
|
15
15
|
output?: string;
|
|
16
16
|
images?: Array<{ url?: string }>;
|
|
17
17
|
image?: { url?: string };
|
|
18
|
-
detail?:
|
|
18
|
+
detail?: GenerationErrorDetail[];
|
|
19
19
|
error?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -27,8 +27,7 @@ export interface GenerationUrls {
|
|
|
27
27
|
/**
|
|
28
28
|
* Check if result contains an error and throw with appropriate message
|
|
29
29
|
*/
|
|
30
|
-
function checkForErrors(result:
|
|
31
|
-
// Check for FAL API error format: {detail: [{msg, type}]}
|
|
30
|
+
function checkForErrors(result: GenerationResult): void {
|
|
32
31
|
if (result.detail && Array.isArray(result.detail) && result.detail.length > 0) {
|
|
33
32
|
const firstError = result.detail[0];
|
|
34
33
|
if (!firstError) return;
|
|
@@ -36,7 +35,6 @@ function checkForErrors(result: FalResult): void {
|
|
|
36
35
|
const errorType = firstError.type || "unknown";
|
|
37
36
|
const errorMsg = firstError.msg || "Generation failed";
|
|
38
37
|
|
|
39
|
-
// Map error type to translation key
|
|
40
38
|
if (errorType === "content_policy_violation") {
|
|
41
39
|
throw new Error("error.generation.content_policy");
|
|
42
40
|
}
|
|
@@ -48,27 +46,23 @@ function checkForErrors(result: FalResult): void {
|
|
|
48
46
|
throw new Error(errorMsg);
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
// Check for simple error field
|
|
52
49
|
if (result.error && typeof result.error === "string" && result.error.length > 0) {
|
|
53
50
|
throw new Error(result.error);
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
/**
|
|
58
|
-
* Extracts image/video URL from
|
|
59
|
-
* Handles various result formats from different
|
|
55
|
+
* Extracts image/video URL from generation result
|
|
56
|
+
* Handles various result formats from different providers
|
|
60
57
|
* Throws error if result contains error information
|
|
61
58
|
*/
|
|
62
|
-
export function extractResultUrl(result:
|
|
63
|
-
// First check for errors in the result
|
|
59
|
+
export function extractResultUrl(result: GenerationResult): GenerationUrls {
|
|
64
60
|
checkForErrors(result);
|
|
65
61
|
|
|
66
|
-
// Video result
|
|
67
62
|
if (result.video?.url && typeof result.video.url === "string") {
|
|
68
63
|
return { videoUrl: result.video.url };
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
// Output URL (some models return direct URL)
|
|
72
66
|
if (typeof result.output === "string" && result.output.length > 0 && result.output.startsWith("http")) {
|
|
73
67
|
if (result.output.includes(".mp4") || result.output.includes("video")) {
|
|
74
68
|
return { videoUrl: result.output };
|
|
@@ -76,7 +70,6 @@ export function extractResultUrl(result: FalResult): GenerationUrls {
|
|
|
76
70
|
return { imageUrl: result.output };
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
// Images array (most image models) with bounds checking
|
|
80
73
|
if (result.images && Array.isArray(result.images) && result.images.length > 0) {
|
|
81
74
|
const firstImage = result.images[0];
|
|
82
75
|
if (firstImage?.url && typeof firstImage.url === "string") {
|
|
@@ -84,7 +77,6 @@ export function extractResultUrl(result: FalResult): GenerationUrls {
|
|
|
84
77
|
}
|
|
85
78
|
}
|
|
86
79
|
|
|
87
|
-
// Single image
|
|
88
80
|
if (result.image?.url && typeof result.image.url === "string") {
|
|
89
81
|
return { imageUrl: result.image.url };
|
|
90
82
|
}
|
|
@@ -27,9 +27,12 @@ export function useGenerationPhase(options?: UseGenerationPhaseOptions): Generat
|
|
|
27
27
|
const { queuedDuration = 5000 } = options ?? {};
|
|
28
28
|
|
|
29
29
|
const [phase, setPhase] = useState<GenerationPhase>("queued");
|
|
30
|
-
const startTimeRef = useRef(Date.now());
|
|
30
|
+
const startTimeRef = useRef<number>(Date.now());
|
|
31
31
|
|
|
32
32
|
useEffect(() => {
|
|
33
|
+
startTimeRef.current = Date.now();
|
|
34
|
+
setPhase("queued");
|
|
35
|
+
|
|
33
36
|
const interval = setInterval(() => {
|
|
34
37
|
const elapsed = Date.now() - startTimeRef.current;
|
|
35
38
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { providerRegistry } from "../../../../../infrastructure/services/provider-registry.service";
|
|
2
|
-
import { extractResultUrl, type
|
|
2
|
+
import { extractResultUrl, type GenerationUrls } from "./generation-result.utils";
|
|
3
3
|
import { QUEUE_STATUS } from "../../../../../domain/constants/queue-status.constants";
|
|
4
4
|
|
|
5
5
|
declare const __DEV__: boolean;
|
|
@@ -34,7 +34,7 @@ export const pollQueueStatus = async (params: PollParams): Promise<void> => {
|
|
|
34
34
|
|
|
35
35
|
if (status.status === QUEUE_STATUS.COMPLETED) {
|
|
36
36
|
try {
|
|
37
|
-
const result = await provider.getJobResult
|
|
37
|
+
const result = await provider.getJobResult(model, requestId);
|
|
38
38
|
await onComplete(extractResultUrl(result));
|
|
39
39
|
} catch (resultErr) {
|
|
40
40
|
const errorMessage = resultErr instanceof Error ? resultErr.message : "Generation failed";
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { BaseExecutor } from "../../../../infrastructure/executors/base-executor";
|
|
6
6
|
import { isSuccess, type Result } from "../../../../domain/types/result.types";
|
|
7
|
-
import { checkFalApiError } from "../../../../infrastructure/utils";
|
|
8
7
|
import {
|
|
9
8
|
defaultExtractVideoResult,
|
|
10
9
|
type ExtractedVideoResult,
|
|
@@ -55,7 +54,6 @@ class ImageToVideoExecutor extends BaseExecutor<
|
|
|
55
54
|
});
|
|
56
55
|
|
|
57
56
|
this.log("info", `Complete, keys: ${result ? Object.keys(result as object) : "null"}`);
|
|
58
|
-
checkFalApiError(result);
|
|
59
57
|
return result;
|
|
60
58
|
}
|
|
61
59
|
|
|
@@ -7,74 +7,34 @@ export class PromptHistoryRepository implements IPromptHistoryRepository {
|
|
|
7
7
|
private readonly maxStorageSize = 100;
|
|
8
8
|
|
|
9
9
|
save(prompt: GeneratedPrompt): Promise<AIPromptResult<void>> {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
14
|
-
} catch {
|
|
15
|
-
return Promise.resolve({
|
|
16
|
-
success: false,
|
|
17
|
-
error: 'STORAGE_ERROR',
|
|
18
|
-
message: 'Failed to save prompt to history'
|
|
19
|
-
});
|
|
20
|
-
}
|
|
10
|
+
this.storage.push(prompt);
|
|
11
|
+
this.trimStorage();
|
|
12
|
+
return Promise.resolve({ success: true, data: undefined });
|
|
21
13
|
}
|
|
22
14
|
|
|
23
15
|
findRecent(limit: number = 50): Promise<AIPromptResult<GeneratedPrompt[]>> {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return Promise.resolve({ success: true, data: prompts });
|
|
27
|
-
} catch {
|
|
28
|
-
return Promise.resolve({
|
|
29
|
-
success: false,
|
|
30
|
-
error: 'STORAGE_ERROR',
|
|
31
|
-
message: 'Failed to retrieve recent prompts'
|
|
32
|
-
});
|
|
33
|
-
}
|
|
16
|
+
const prompts = this.storage.slice(-limit);
|
|
17
|
+
return Promise.resolve({ success: true, data: prompts });
|
|
34
18
|
}
|
|
35
19
|
|
|
36
20
|
findByTemplateId(
|
|
37
21
|
templateId: string,
|
|
38
22
|
limit: number = 20
|
|
39
23
|
): Promise<AIPromptResult<GeneratedPrompt[]>> {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return Promise.resolve({ success: true, data: prompts });
|
|
45
|
-
} catch {
|
|
46
|
-
return Promise.resolve({
|
|
47
|
-
success: false,
|
|
48
|
-
error: 'STORAGE_ERROR',
|
|
49
|
-
message: 'Failed to retrieve prompts by template ID'
|
|
50
|
-
});
|
|
51
|
-
}
|
|
24
|
+
const prompts = this.storage
|
|
25
|
+
.filter(prompt => prompt.templateId === templateId)
|
|
26
|
+
.slice(-limit);
|
|
27
|
+
return Promise.resolve({ success: true, data: prompts });
|
|
52
28
|
}
|
|
53
29
|
|
|
54
30
|
delete(id: string): Promise<AIPromptResult<void>> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
58
|
-
} catch {
|
|
59
|
-
return Promise.resolve({
|
|
60
|
-
success: false,
|
|
61
|
-
error: 'STORAGE_ERROR',
|
|
62
|
-
message: 'Failed to delete prompt'
|
|
63
|
-
});
|
|
64
|
-
}
|
|
31
|
+
this.storage = this.storage.filter(prompt => prompt.id !== id);
|
|
32
|
+
return Promise.resolve({ success: true, data: undefined });
|
|
65
33
|
}
|
|
66
34
|
|
|
67
35
|
clear(): Promise<AIPromptResult<void>> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
71
|
-
} catch {
|
|
72
|
-
return Promise.resolve({
|
|
73
|
-
success: false,
|
|
74
|
-
error: 'STORAGE_ERROR',
|
|
75
|
-
message: 'Failed to clear prompt history'
|
|
76
|
-
});
|
|
77
|
-
}
|
|
36
|
+
this.storage = [];
|
|
37
|
+
return Promise.resolve({ success: true, data: undefined });
|
|
78
38
|
}
|
|
79
39
|
|
|
80
40
|
private trimStorage(): void {
|
|
@@ -56,5 +56,9 @@ export async function fetchWithTimeout<T>(
|
|
|
56
56
|
return createErrorResponse(getErrorMessage(result.error));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
if (result.data === undefined) {
|
|
60
|
+
return createErrorResponse("No data received from server");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return createSuccessResponse(result.data);
|
|
60
64
|
}
|
|
@@ -16,6 +16,11 @@ export function createTimeoutController(
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const controller = new AbortController();
|
|
19
|
-
setTimeout(() => controller.abort(), timeout);
|
|
19
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
20
|
+
|
|
21
|
+
controller.signal.addEventListener('abort', () => {
|
|
22
|
+
clearTimeout(timeoutId);
|
|
23
|
+
}, { once: true });
|
|
24
|
+
|
|
20
25
|
return controller;
|
|
21
26
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Output: video URL
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { extractErrorMessage,
|
|
7
|
+
import { extractErrorMessage, validateProvider, prepareVideoInputData } from "../utils";
|
|
8
8
|
import { extractVideoResult } from "../utils/url-extractor";
|
|
9
9
|
import { DEFAULT_MAX_POLL_TIME_MS } from "../constants";
|
|
10
10
|
import type { VideoFeatureType } from "../../domain/interfaces";
|
|
@@ -42,8 +42,6 @@ export async function executeVideoFeature(
|
|
|
42
42
|
onQueueUpdate: (status) => onStatusChange?.(status.status),
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
checkFalApiError(result);
|
|
46
|
-
|
|
47
45
|
const videoUrl = (extractResult ?? extractVideoResult)(result);
|
|
48
46
|
|
|
49
47
|
if (!videoUrl) {
|
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
* Error Factory Functions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
export const GenerationErrorType = {
|
|
6
|
+
CONTENT_POLICY: "content_policy",
|
|
7
|
+
RATE_LIMIT: "rate_limit",
|
|
8
|
+
TIMEOUT: "timeout",
|
|
9
|
+
VALIDATION: "validation",
|
|
10
|
+
NETWORK: "network",
|
|
11
|
+
UNKNOWN: "unknown",
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
export type GenerationErrorTypeValue = typeof GenerationErrorType[keyof typeof GenerationErrorType];
|
|
15
|
+
|
|
16
|
+
export interface GenerationError extends Error {
|
|
17
|
+
errorType: GenerationErrorTypeValue;
|
|
18
|
+
translationKey: string;
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
/**
|
|
8
22
|
* Create a structured generation error
|
|
@@ -25,13 +25,13 @@ export async function retryWithBackoff<T>(
|
|
|
25
25
|
|
|
26
26
|
let lastError: Error | undefined;
|
|
27
27
|
|
|
28
|
-
for (let attempt = 0; attempt
|
|
28
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
29
29
|
try {
|
|
30
30
|
return await operation();
|
|
31
31
|
} catch (error) {
|
|
32
32
|
lastError = error instanceof Error ? error : new Error(getErrorMessage(error));
|
|
33
33
|
|
|
34
|
-
if (
|
|
34
|
+
if (!shouldRetry(lastError)) {
|
|
35
35
|
throw lastError;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -40,5 +40,5 @@ export async function retryWithBackoff<T>(
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
throw lastError
|
|
43
|
+
throw lastError ?? new Error("Operation failed after retries");
|
|
44
44
|
}
|
|
@@ -9,8 +9,8 @@ export * from "./error-handlers";
|
|
|
9
9
|
export * from "./error-factory";
|
|
10
10
|
export * from "./error-types";
|
|
11
11
|
export * from "./message-extractor";
|
|
12
|
-
export * from "./fal-error-checker";
|
|
13
12
|
export * from "./classifier-helpers";
|
|
13
|
+
export * from "./result-polling";
|
|
14
14
|
export * from "./validation.util";
|
|
15
15
|
export * from "../../domains/background/infrastructure/utils/polling-interval.util";
|
|
16
16
|
export * from "./progress-calculator.util";
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Error Message Extraction Functions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { GenerationErrorType } from "./
|
|
6
|
-
import { isGenerationError } from "./error-factory";
|
|
5
|
+
import { GenerationErrorType, isGenerationError } from "./error-factory";
|
|
7
6
|
|
|
8
7
|
declare const __DEV__: boolean;
|
|
9
8
|
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Extraction Type Definitions
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* FAL API error detail item
|
|
7
|
-
*/
|
|
8
|
-
export interface FalErrorDetail {
|
|
9
|
-
readonly msg?: string;
|
|
10
|
-
readonly type?: string;
|
|
11
|
-
readonly loc?: string[];
|
|
12
|
-
readonly input?: string;
|
|
13
|
-
readonly url?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Error types for user-friendly messages
|
|
18
|
-
*/
|
|
19
|
-
export const GenerationErrorType = {
|
|
20
|
-
CONTENT_POLICY: "content_policy",
|
|
21
|
-
VALIDATION: "validation",
|
|
22
|
-
NETWORK: "network",
|
|
23
|
-
TIMEOUT: "timeout",
|
|
24
|
-
RATE_LIMIT: "rate_limit",
|
|
25
|
-
QUOTA_EXCEEDED: "quota_exceeded",
|
|
26
|
-
UNKNOWN: "unknown",
|
|
27
|
-
} as const;
|
|
28
|
-
|
|
29
|
-
export type GenerationErrorTypeValue = typeof GenerationErrorType[keyof typeof GenerationErrorType];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Structured generation error
|
|
33
|
-
*/
|
|
34
|
-
export interface GenerationError extends Error {
|
|
35
|
-
readonly errorType: GenerationErrorTypeValue;
|
|
36
|
-
readonly translationKey: string;
|
|
37
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FAL API Error Checker
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { FalErrorDetail } from "./extraction-types";
|
|
6
|
-
import { GenerationErrorType } from "./extraction-types";
|
|
7
|
-
import { createGenerationError } from "./error-factory";
|
|
8
|
-
|
|
9
|
-
declare const __DEV__: boolean;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Check if result contains a FAL API error response
|
|
13
|
-
* FAL sometimes returns errors with COMPLETED status
|
|
14
|
-
*/
|
|
15
|
-
export function checkFalApiError(result: unknown): void {
|
|
16
|
-
if (!result || typeof result !== "object") return;
|
|
17
|
-
|
|
18
|
-
const resultObj = result as { detail?: FalErrorDetail[] };
|
|
19
|
-
|
|
20
|
-
// FAL API error format: {detail: [{msg, type, loc}]}
|
|
21
|
-
if (Array.isArray(resultObj.detail) && resultObj.detail.length > 0) {
|
|
22
|
-
const firstError = resultObj.detail[0];
|
|
23
|
-
const errorType = firstError?.type || "unknown";
|
|
24
|
-
const errorMsg = firstError?.msg || "Unknown API error";
|
|
25
|
-
|
|
26
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
27
|
-
console.error("[FalApiError] Detected error in result:", {
|
|
28
|
-
type: errorType,
|
|
29
|
-
message: errorMsg,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Throw specific error based on type
|
|
34
|
-
if (errorType === "content_policy_violation") {
|
|
35
|
-
throw createGenerationError(GenerationErrorType.CONTENT_POLICY, errorMsg);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (errorType === "validation_error" || errorType.includes("validation")) {
|
|
39
|
-
throw createGenerationError(GenerationErrorType.VALIDATION, errorMsg);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
throw createGenerationError(GenerationErrorType.UNKNOWN, errorMsg);
|
|
43
|
-
}
|
|
44
|
-
}
|