@umituz/react-native-ai-generation-content 1.90.2 → 1.90.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 +3 -3
- package/src/domain/interfaces/app-services-auth.interface.ts +27 -0
- package/src/domain/interfaces/app-services-composite.interface.ts +29 -0
- package/src/domain/interfaces/app-services-optional.interface.ts +42 -0
- package/src/domain/interfaces/app-services.interface.ts +0 -79
- package/src/domain/interfaces/index.ts +3 -0
- package/src/domains/background/infrastructure/services/job-poller-index.ts +7 -0
- package/src/domains/background/infrastructure/services/job-poller-utils.ts +127 -0
- package/src/domains/background/infrastructure/services/job-poller.service.ts +85 -140
- package/src/domains/background/infrastructure/utils/polling-interval.util.ts +1 -1
- package/src/domains/background/presentation/hooks/use-background-generation.ts +1 -1
- package/src/domains/content-moderation/index.ts +7 -13
- package/src/domains/content-moderation/infrastructure/services/content-moderation.service.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +15 -4
- package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +19 -8
- package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
- package/src/domains/creations/domain/types/creation-categories.constants.ts +57 -0
- package/src/domains/creations/domain/types/creation-categories.helpers.ts +67 -0
- package/src/domains/creations/domain/types/creation-categories.ts +7 -114
- package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
- package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
- package/src/domains/creations/presentation/hooks/creation-validators.ts +31 -29
- package/src/domains/creations/presentation/hooks/job-poller-index.ts +10 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.filters.ts +34 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.logger.ts +76 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.stale-handlers.ts +52 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.ts +8 -0
- package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
- package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +18 -235
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +1 -2
- package/src/domains/creations/presentation-exports.ts +2 -2
- package/src/domains/face-detection/domain/entities/FaceDetection.ts +4 -3
- package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +24 -21
- package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +58 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +69 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +77 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +54 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +112 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder.ts +7 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/index.ts +20 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +44 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-end-logger.ts +18 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-start-logger.ts +57 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-step-logger.ts +106 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/types.ts +49 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +8 -0
- package/src/domains/generation/infrastructure/flow/flow-store-actions.ts +105 -0
- package/src/domains/generation/infrastructure/flow/flow-store-initial-state.ts +26 -0
- package/src/domains/generation/infrastructure/flow/useFlowStore.ts +4 -116
- package/src/domains/generation/presentation/useAIGeneration.hook.ts +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation-strategy-index.ts +7 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +2 -12
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.types.ts +11 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.utils.ts +12 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +1 -220
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-builder.ts +66 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +88 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +74 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-style-enhancements.ts +35 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +41 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +10 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor.ts +76 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-input-builder.ts +46 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-result-types.ts +17 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +61 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.audio-extractor.ts +27 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +2 -176
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.input-builder.ts +90 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts +3 -108
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -130
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.validation.ts +136 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +40 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +37 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/usePhotoUploadStateLogic.ts +142 -0
- package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +102 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.handlers.ts +97 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.saver.ts +54 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.ts +22 -87
- package/src/domains/generation/wizard/presentation/hooks/usePhotoUploadState.ts +8 -177
- package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +1 -295
- package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +1 -1
- package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +77 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/use-video-queue-utils.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationCallbacks.ts +119 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +75 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationRefs.ts +65 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue-index.ts +9 -0
- package/src/domains/image-to-video/domain/types/image-to-video-state.types.ts +11 -4
- package/src/domains/text-to-image/domain/constants/index.ts +5 -6
- package/src/domains/text-to-image/domain/types/text-to-image.types.ts +43 -22
- package/src/domains/text-to-video/domain/types/request.types.ts +32 -9
- package/src/domains/text-to-video/domain/types/state.types.ts +22 -22
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.handlers.ts +44 -0
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.ts +5 -51
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.types.ts +33 -0
- package/src/exports/features.ts +1 -1
- package/src/infrastructure/services/generation-orchestrator.service.ts +2 -2
- package/src/infrastructure/utils/couple-input-context.ts +13 -0
- package/src/infrastructure/utils/couple-input-index.ts +9 -0
- package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
- package/src/infrastructure/utils/couple-input-refiner.ts +101 -0
- package/src/infrastructure/utils/couple-input-resolver.ts +71 -0
- package/src/infrastructure/utils/couple-input-types.ts +11 -0
- package/src/infrastructure/utils/couple-input.util.ts +3 -176
- package/src/infrastructure/utils/photo-generation/photo-preparation.util.ts +1 -1
- package/src/infrastructure/validation/base-validator.ts +3 -26
- package/src/infrastructure/validation/base-validator.types.ts +32 -0
- package/src/presentation/hooks/generation/index.ts +1 -1
- package/src/presentation/hooks/generation/orchestrator-abort-logs.ts +48 -0
- package/src/presentation/hooks/generation/orchestrator-execution-logs.ts +67 -0
- package/src/presentation/hooks/generation/orchestrator-index.ts +14 -0
- package/src/presentation/hooks/generation/orchestrator-start-logs.ts +65 -0
- package/src/presentation/hooks/generation/orchestrator-state-utils.ts +17 -0
- package/src/presentation/hooks/generation/orchestrator-types.ts +55 -0
- package/src/presentation/hooks/generation/orchestrator-utils-index.ts +29 -0
- package/src/presentation/hooks/generation/orchestrator-utils.ts +25 -0
- package/src/presentation/hooks/generation/useDualImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useVideoGeneration.ts +1 -1
- package/src/shared/hooks/factories/generation-hook-index.ts +12 -0
- package/src/shared/hooks/factories/generation-hook-types.ts +47 -0
- package/src/shared/hooks/factories/generation-hook-utils.ts +94 -0
- package/src/shared/hooks/factories/index.ts +1 -1
- package/src/shared/index.ts +1 -1
- package/src/shared/utils/calculations/aspect-ratio-calculations.ts +30 -0
- package/src/shared/utils/calculations/base64-calculations.ts +26 -0
- package/src/shared/utils/calculations/confidence-calculations.ts +21 -0
- package/src/shared/utils/calculations/cost-calculations-index.ts +43 -0
- package/src/shared/utils/calculations/cost-calculations.ts +25 -0
- package/src/shared/utils/calculations/credit-calculations.ts +37 -0
- package/src/shared/utils/calculations/index.ts +46 -0
- package/src/shared/utils/calculations/math-utilities.ts +32 -0
- package/src/shared/utils/calculations/memory-calculations.ts +33 -0
- package/src/shared/utils/calculations/pagination-calculations.ts +38 -0
- package/src/shared/utils/calculations/percentage-calculations.ts +33 -0
- package/src/shared/utils/calculations/time-calculations.ts +99 -0
- package/src/shared/utils/credit.ts +1 -1
- package/src/shared-kernel/application/hooks/index.ts +8 -0
- package/src/shared-kernel/application/hooks/use-feature-state.ts +106 -0
- package/src/shared-kernel/application/hooks/use-generation-handler.ts +110 -0
- package/src/shared-kernel/base-types/base-callbacks.types.ts +73 -0
- package/src/shared-kernel/base-types/base-feature-state.types.ts +77 -0
- package/src/shared-kernel/base-types/base-generation.types.ts +69 -0
- package/src/shared-kernel/base-types/index.ts +30 -0
- package/src/shared-kernel/domain/base-generation-strategy.ts +146 -0
- package/src/shared-kernel/domain/index.ts +7 -0
- package/src/shared-kernel/index.ts +17 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.ts +126 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.types.ts +33 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.ts +52 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.types.ts +38 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +79 -0
- package/src/shared-kernel/infrastructure/validation/index.ts +70 -0
- package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
- package/src/domains/creations/domain/constants/index.ts +0 -12
- package/src/domains/creations/domain/utils/index.ts +0 -12
- package/src/domains/generation/infrastructure/couple-generation-builder.ts +0 -374
- package/src/domains/image-to-video/domain/index.ts +0 -2
- package/src/domains/image-to-video/infrastructure/index.ts +0 -1
- package/src/domains/image-to-video/presentation/index.ts +0 -5
- package/src/domains/text-to-video/domain/index.ts +0 -1
- package/src/domains/text-to-video/presentation/index.ts +0 -7
- package/src/presentation/hooks/generation/orchestrator.ts +0 -276
- package/src/shared/hooks/factories/createGenerationHook.ts +0 -253
- package/src/shared/utils/calculations.util.ts +0 -366
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.90.
|
|
3
|
+
"version": "1.90.4",
|
|
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",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"@tanstack/react-query": "^5.66.7",
|
|
74
74
|
"@tanstack/react-query-persist-client": "^5.66.7",
|
|
75
75
|
"@types/react": "~19.1.10",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
77
|
-
"@typescript-eslint/parser": "^8.
|
|
76
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
77
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
78
78
|
"@umituz/react-native-ai-fal-provider": "*",
|
|
79
79
|
"@umituz/react-native-design-system": "*",
|
|
80
80
|
"@umituz/react-native-firebase": "*",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Services - Auth Interface
|
|
3
|
+
* Authentication service interface
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Auth service interface
|
|
8
|
+
* Handles user authentication
|
|
9
|
+
*/
|
|
10
|
+
export interface IAuthService {
|
|
11
|
+
/**
|
|
12
|
+
* Get current user ID
|
|
13
|
+
* @returns User ID or null if not authenticated
|
|
14
|
+
*/
|
|
15
|
+
getUserId: () => string | null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if user is authenticated
|
|
19
|
+
*/
|
|
20
|
+
isAuthenticated: () => boolean;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Require authenticated user - throws if not authenticated
|
|
24
|
+
* @returns User ID
|
|
25
|
+
*/
|
|
26
|
+
requireAuth: () => string;
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Services - Composite Interface
|
|
3
|
+
* Combined app services interface
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { INetworkService } from "./app-services.interface";
|
|
7
|
+
import type { ICreditService } from "./app-services.interface";
|
|
8
|
+
import type { IPaywallService } from "./app-services.interface";
|
|
9
|
+
import type { IAuthService } from "./app-services-auth.interface";
|
|
10
|
+
import type { IAnalyticsService } from "./app-services-optional.interface";
|
|
11
|
+
import type { IFeatureUtils } from "./app-services-optional.interface";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Combined app services interface
|
|
15
|
+
* Apps implement this to provide all required services
|
|
16
|
+
*/
|
|
17
|
+
export interface IAppServices {
|
|
18
|
+
readonly network: INetworkService;
|
|
19
|
+
readonly credits: ICreditService;
|
|
20
|
+
readonly paywall: IPaywallService;
|
|
21
|
+
readonly auth: IAuthService;
|
|
22
|
+
readonly analytics?: IAnalyticsService;
|
|
23
|
+
readonly featureUtils?: IFeatureUtils;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Partial app services for optional configuration
|
|
28
|
+
*/
|
|
29
|
+
export type PartialAppServices = Partial<IAppServices>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Services - Optional Interfaces
|
|
3
|
+
* Optional service interfaces (analytics, feature utils)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Analytics event data
|
|
8
|
+
*/
|
|
9
|
+
interface AnalyticsEventData {
|
|
10
|
+
readonly [key: string]: string | number | boolean | null | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Analytics service interface (optional)
|
|
15
|
+
* Tracks events for analytics
|
|
16
|
+
*/
|
|
17
|
+
export interface IAnalyticsService {
|
|
18
|
+
/**
|
|
19
|
+
* Track an event
|
|
20
|
+
* @param event - Event name
|
|
21
|
+
* @param data - Event data
|
|
22
|
+
*/
|
|
23
|
+
track: (event: string, data: AnalyticsEventData) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Feature utils interface (optional)
|
|
28
|
+
* Provides utility functions for AI features
|
|
29
|
+
*/
|
|
30
|
+
export interface IFeatureUtils {
|
|
31
|
+
/**
|
|
32
|
+
* Select image from gallery
|
|
33
|
+
* @returns Image URI or null if cancelled
|
|
34
|
+
*/
|
|
35
|
+
selectImage: () => Promise<string | null>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Save video to device library
|
|
39
|
+
* @param uri - Video URI to save
|
|
40
|
+
*/
|
|
41
|
+
saveVideo: (uri: string) => Promise<void>;
|
|
42
|
+
}
|
|
@@ -78,82 +78,3 @@ export interface IPaywallService {
|
|
|
78
78
|
*/
|
|
79
79
|
showPaywall: (requiredCredits: number) => void;
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Auth service interface
|
|
84
|
-
* Handles user authentication
|
|
85
|
-
*/
|
|
86
|
-
export interface IAuthService {
|
|
87
|
-
/**
|
|
88
|
-
* Get current user ID
|
|
89
|
-
* @returns User ID or null if not authenticated
|
|
90
|
-
*/
|
|
91
|
-
getUserId: () => string | null;
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Check if user is authenticated
|
|
95
|
-
*/
|
|
96
|
-
isAuthenticated: () => boolean;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Require authenticated user - throws if not authenticated
|
|
100
|
-
* @returns User ID
|
|
101
|
-
*/
|
|
102
|
-
requireAuth: () => string;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Analytics event data
|
|
107
|
-
*/
|
|
108
|
-
interface AnalyticsEventData {
|
|
109
|
-
readonly [key: string]: string | number | boolean | null | undefined;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Analytics service interface (optional)
|
|
114
|
-
* Tracks events for analytics
|
|
115
|
-
*/
|
|
116
|
-
export interface IAnalyticsService {
|
|
117
|
-
/**
|
|
118
|
-
* Track an event
|
|
119
|
-
* @param event - Event name
|
|
120
|
-
* @param data - Event data
|
|
121
|
-
*/
|
|
122
|
-
track: (event: string, data: AnalyticsEventData) => void;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Feature utils interface (optional)
|
|
127
|
-
* Provides utility functions for AI features
|
|
128
|
-
*/
|
|
129
|
-
export interface IFeatureUtils {
|
|
130
|
-
/**
|
|
131
|
-
* Select image from gallery
|
|
132
|
-
* @returns Image URI or null if cancelled
|
|
133
|
-
*/
|
|
134
|
-
selectImage: () => Promise<string | null>;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Save video to device library
|
|
138
|
-
* @param uri - Video URI to save
|
|
139
|
-
*/
|
|
140
|
-
saveVideo: (uri: string) => Promise<void>;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Combined app services interface
|
|
145
|
-
* Apps implement this to provide all required services
|
|
146
|
-
*/
|
|
147
|
-
export interface IAppServices {
|
|
148
|
-
readonly network: INetworkService;
|
|
149
|
-
readonly credits: ICreditService;
|
|
150
|
-
readonly paywall: IPaywallService;
|
|
151
|
-
readonly auth: IAuthService;
|
|
152
|
-
readonly analytics?: IAnalyticsService;
|
|
153
|
-
readonly featureUtils?: IFeatureUtils;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Partial app services for optional configuration
|
|
158
|
-
*/
|
|
159
|
-
export type PartialAppServices = Partial<IAppServices>;
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
export * from "./ai-provider.interface";
|
|
7
7
|
export * from "./app-services.interface";
|
|
8
|
+
export * from "./app-services-auth.interface";
|
|
9
|
+
export * from "./app-services-composite.interface";
|
|
10
|
+
export * from "./app-services-optional.interface";
|
|
8
11
|
|
|
9
12
|
// Video Model Configuration
|
|
10
13
|
export type { VideoModelConfig, ModelCapabilityOption } from "./video-model-config.types";
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Poller Service - Utility Functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wrap a promise with abort signal support
|
|
7
|
+
* Rejects if signal is aborted before promise resolves
|
|
8
|
+
*/
|
|
9
|
+
export function withAbortSignal<T>(
|
|
10
|
+
promise: Promise<T>,
|
|
11
|
+
signal: AbortSignal | undefined,
|
|
12
|
+
timeoutMs?: number,
|
|
13
|
+
): Promise<T> {
|
|
14
|
+
if (!signal && !timeoutMs) {
|
|
15
|
+
return promise;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return new Promise<T>((resolve, reject) => {
|
|
19
|
+
// Handle abort signal
|
|
20
|
+
if (signal?.aborted) {
|
|
21
|
+
reject(new Error("Operation aborted"));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let isResolved = false;
|
|
26
|
+
const abortHandler = () => {
|
|
27
|
+
if (isResolved) return;
|
|
28
|
+
isResolved = true;
|
|
29
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
30
|
+
reject(new Error("Operation aborted"));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
34
|
+
|
|
35
|
+
// Handle timeout
|
|
36
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
37
|
+
if (timeoutMs) {
|
|
38
|
+
timeoutId = setTimeout(() => {
|
|
39
|
+
if (isResolved) return;
|
|
40
|
+
isResolved = true;
|
|
41
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
42
|
+
reject(new Error(`Operation timeout after ${timeoutMs}ms`));
|
|
43
|
+
}, timeoutMs);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
promise
|
|
47
|
+
.then((result) => {
|
|
48
|
+
if (isResolved) return;
|
|
49
|
+
isResolved = true;
|
|
50
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
51
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
52
|
+
resolve(result);
|
|
53
|
+
})
|
|
54
|
+
.catch((error) => {
|
|
55
|
+
if (isResolved) return;
|
|
56
|
+
isResolved = true;
|
|
57
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
58
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
59
|
+
reject(error);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validate request ID
|
|
66
|
+
*/
|
|
67
|
+
export function validateRequestId(requestId: string | undefined): { valid: boolean; error?: string } {
|
|
68
|
+
if (!requestId || typeof requestId !== "string" || requestId.trim() === "") {
|
|
69
|
+
return {
|
|
70
|
+
valid: false,
|
|
71
|
+
error: "Invalid requestId provided",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { valid: true };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validate model
|
|
79
|
+
*/
|
|
80
|
+
export function validateModel(model: string | undefined): { valid: boolean; error?: string } {
|
|
81
|
+
if (!model || typeof model !== "string" || model.trim() === "") {
|
|
82
|
+
return {
|
|
83
|
+
valid: false,
|
|
84
|
+
error: "Invalid model provided",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return { valid: true };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Log transient error during polling
|
|
92
|
+
*/
|
|
93
|
+
export function logTransientError(
|
|
94
|
+
attempt: number,
|
|
95
|
+
requestId: string,
|
|
96
|
+
model: string,
|
|
97
|
+
consecutiveErrors: number,
|
|
98
|
+
error: unknown
|
|
99
|
+
): void {
|
|
100
|
+
if (__DEV__) {
|
|
101
|
+
console.warn("[JobPoller] Transient error during polling", {
|
|
102
|
+
attempt: attempt + 1,
|
|
103
|
+
requestId,
|
|
104
|
+
model,
|
|
105
|
+
consecutiveErrors,
|
|
106
|
+
error: error instanceof Error ? error.message : String(error),
|
|
107
|
+
code: (error as { code?: string })?.code,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Log max consecutive errors reached
|
|
114
|
+
*/
|
|
115
|
+
export function logMaxConsecutiveErrors(
|
|
116
|
+
maxConsecutiveErrors: number,
|
|
117
|
+
requestId: string,
|
|
118
|
+
model: string
|
|
119
|
+
): void {
|
|
120
|
+
if (__DEV__) {
|
|
121
|
+
console.error("[JobPoller] Max consecutive errors reached", {
|
|
122
|
+
maxConsecutiveErrors,
|
|
123
|
+
requestId,
|
|
124
|
+
model,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,234 +1,179 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Job Poller Service
|
|
3
3
|
* Provider-agnostic job polling with exponential backoff
|
|
4
|
-
* Reports only real status - no fake progress
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import type { JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
|
|
7
|
+
import type { PollingConfig } from "../../../../domain/entities/polling.types";
|
|
8
|
+
import type { PollJobOptions, PollJobResult } from "./job-poller.types";
|
|
9
|
+
import { withAbortSignal, validateRequestId, validateModel, logTransientError, logMaxConsecutiveErrors } from "./job-poller-utils";
|
|
9
10
|
import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
|
|
10
11
|
import { validateResult } from "../utils/result-validator.util";
|
|
11
|
-
import type { PollJobOptions, PollJobResult } from "./job-poller.types";
|
|
12
|
-
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
* Rejects if signal is aborted before promise resolves
|
|
14
|
+
* Default polling configuration
|
|
17
15
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return new Promise<T>((resolve, reject) => {
|
|
28
|
-
// Handle abort signal
|
|
29
|
-
if (signal?.aborted) {
|
|
30
|
-
reject(new Error("Operation aborted"));
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let isResolved = false;
|
|
35
|
-
const abortHandler = () => {
|
|
36
|
-
if (isResolved) return;
|
|
37
|
-
isResolved = true;
|
|
38
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
39
|
-
reject(new Error("Operation aborted"));
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
43
|
-
|
|
44
|
-
// Handle timeout
|
|
45
|
-
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
46
|
-
if (timeoutMs) {
|
|
47
|
-
timeoutId = setTimeout(() => {
|
|
48
|
-
if (isResolved) return;
|
|
49
|
-
isResolved = true;
|
|
50
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
51
|
-
reject(new Error(`Operation timeout after ${timeoutMs}ms`));
|
|
52
|
-
}, timeoutMs);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
promise
|
|
56
|
-
.then((result) => {
|
|
57
|
-
if (isResolved) return;
|
|
58
|
-
isResolved = true;
|
|
59
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
60
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
61
|
-
resolve(result);
|
|
62
|
-
})
|
|
63
|
-
.catch((error) => {
|
|
64
|
-
if (isResolved) return;
|
|
65
|
-
isResolved = true;
|
|
66
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
67
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
68
|
-
reject(error);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
}
|
|
16
|
+
const DEFAULT_CONFIG: Partial<PollingConfig> = {
|
|
17
|
+
maxAttempts: 40,
|
|
18
|
+
initialIntervalMs: 1500,
|
|
19
|
+
maxIntervalMs: 5000,
|
|
20
|
+
backoffMultiplier: 1.3,
|
|
21
|
+
maxConsecutiveErrors: 5,
|
|
22
|
+
};
|
|
72
23
|
|
|
73
24
|
/**
|
|
74
|
-
* Poll job until completion
|
|
75
|
-
* Only reports 100% on actual completion
|
|
25
|
+
* Poll a job until completion or timeout
|
|
76
26
|
*/
|
|
77
27
|
export async function pollJob<T = unknown>(
|
|
78
|
-
options: PollJobOptions
|
|
28
|
+
options: PollJobOptions
|
|
79
29
|
): Promise<PollJobResult<T>> {
|
|
80
30
|
const {
|
|
81
31
|
provider,
|
|
82
32
|
model,
|
|
83
33
|
requestId,
|
|
84
|
-
config,
|
|
34
|
+
config = DEFAULT_CONFIG,
|
|
85
35
|
onProgress,
|
|
86
36
|
onStatusChange,
|
|
87
37
|
signal,
|
|
88
38
|
} = options;
|
|
89
39
|
|
|
90
|
-
// Validate
|
|
91
|
-
|
|
40
|
+
// Validate inputs
|
|
41
|
+
const requestIdValidation = validateRequestId(requestId);
|
|
42
|
+
if (!requestIdValidation.valid) {
|
|
92
43
|
return {
|
|
93
44
|
success: false,
|
|
94
|
-
error: new Error(
|
|
45
|
+
error: new Error(requestIdValidation.error!),
|
|
95
46
|
attempts: 0,
|
|
96
47
|
elapsedMs: 0,
|
|
97
48
|
};
|
|
98
49
|
}
|
|
99
50
|
|
|
100
|
-
|
|
101
|
-
if (!
|
|
51
|
+
const modelValidation = validateModel(model);
|
|
52
|
+
if (!modelValidation.valid) {
|
|
102
53
|
return {
|
|
103
54
|
success: false,
|
|
104
|
-
error: new Error(
|
|
55
|
+
error: new Error(modelValidation.error!),
|
|
105
56
|
attempts: 0,
|
|
106
57
|
elapsedMs: 0,
|
|
107
58
|
};
|
|
108
59
|
}
|
|
109
60
|
|
|
110
|
-
const pollingConfig = { ...DEFAULT_POLLING_CONFIG, ...config };
|
|
111
|
-
const { maxAttempts, maxTotalTimeMs, maxConsecutiveErrors } = pollingConfig;
|
|
112
|
-
|
|
113
61
|
const startTime = Date.now();
|
|
114
|
-
let
|
|
62
|
+
let currentInterval = config.initialIntervalMs || DEFAULT_CONFIG.initialIntervalMs!;
|
|
63
|
+
const maxInterval = config.maxIntervalMs || DEFAULT_CONFIG.maxIntervalMs!;
|
|
64
|
+
const maxAttempts = config.maxAttempts || DEFAULT_CONFIG.maxAttempts!;
|
|
65
|
+
const backoffMultiplier = config.backoffMultiplier || DEFAULT_CONFIG.backoffMultiplier!;
|
|
66
|
+
const maxConsecutiveErrors = config.maxConsecutiveErrors || DEFAULT_CONFIG.maxConsecutiveErrors!;
|
|
115
67
|
|
|
116
|
-
|
|
117
|
-
// Check total time limit
|
|
118
|
-
const elapsedMs = Date.now() - startTime;
|
|
119
|
-
if (maxTotalTimeMs && elapsedMs >= maxTotalTimeMs) {
|
|
120
|
-
return {
|
|
121
|
-
success: false,
|
|
122
|
-
error: new Error(`Polling timeout after ${elapsedMs}ms`),
|
|
123
|
-
attempts: attempt + 1,
|
|
124
|
-
elapsedMs,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
68
|
+
let consecutiveErrors = 0;
|
|
127
69
|
|
|
70
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
71
|
+
// Check for abort signal
|
|
128
72
|
if (signal?.aborted) {
|
|
129
73
|
return {
|
|
130
74
|
success: false,
|
|
131
|
-
error: new Error("
|
|
75
|
+
error: new Error("Operation aborted"),
|
|
132
76
|
attempts: attempt + 1,
|
|
133
|
-
elapsedMs,
|
|
77
|
+
elapsedMs: Date.now() - startTime,
|
|
134
78
|
};
|
|
135
79
|
}
|
|
136
80
|
|
|
137
|
-
if (attempt > 0) {
|
|
138
|
-
const interval = calculatePollingInterval({ attempt, config: pollingConfig });
|
|
139
|
-
await new Promise<void>((resolve) => setTimeout(() => resolve(), interval));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
81
|
try {
|
|
143
|
-
//
|
|
144
|
-
const
|
|
145
|
-
provider.
|
|
82
|
+
// Check job status
|
|
83
|
+
const statusResult = await withAbortSignal(
|
|
84
|
+
provider.checkStatus(requestId, model),
|
|
146
85
|
signal,
|
|
147
|
-
|
|
86
|
+
config.maxTotalTimeMs ? config.maxTotalTimeMs - (Date.now() - startTime) : undefined
|
|
148
87
|
);
|
|
149
|
-
onStatusChange?.(status);
|
|
150
88
|
|
|
151
|
-
|
|
89
|
+
// Notify status change
|
|
90
|
+
if (onStatusChange && typeof statusResult === 'object' && 'status' in statusResult) {
|
|
91
|
+
onStatusChange(statusResult as JobStatus);
|
|
92
|
+
}
|
|
152
93
|
|
|
153
|
-
|
|
94
|
+
// Check for errors in status
|
|
95
|
+
const statusError = checkStatusForErrors(statusResult as JobStatus | Record<string, unknown>);
|
|
96
|
+
if (statusError) {
|
|
154
97
|
return {
|
|
155
98
|
success: false,
|
|
156
|
-
error:
|
|
99
|
+
error: statusError,
|
|
157
100
|
attempts: attempt + 1,
|
|
158
101
|
elapsedMs: Date.now() - startTime,
|
|
159
102
|
};
|
|
160
103
|
}
|
|
161
104
|
|
|
162
|
-
|
|
105
|
+
// Reset consecutive errors on success
|
|
106
|
+
consecutiveErrors = 0;
|
|
163
107
|
|
|
164
|
-
if
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
60000,
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
const validation = validateResult(result);
|
|
173
|
-
if (!validation.isValid) {
|
|
108
|
+
// Check if job is complete
|
|
109
|
+
if (isJobComplete(statusResult as JobStatus | Record<string, unknown>)) {
|
|
110
|
+
// Validate result
|
|
111
|
+
const validationResult = validateResult(statusResult);
|
|
112
|
+
if (!validationResult.isValid) {
|
|
174
113
|
return {
|
|
175
114
|
success: false,
|
|
176
|
-
error: new Error(
|
|
115
|
+
error: new Error(validationResult.errorMessage || "Result validation failed"),
|
|
177
116
|
attempts: attempt + 1,
|
|
178
117
|
elapsedMs: Date.now() - startTime,
|
|
179
118
|
};
|
|
180
119
|
}
|
|
181
120
|
|
|
121
|
+
// Report progress
|
|
182
122
|
onProgress?.(100);
|
|
183
123
|
|
|
124
|
+
// Extract result data if available
|
|
125
|
+
let data: T | undefined = undefined;
|
|
126
|
+
if (typeof statusResult === 'object' && statusResult !== null && 'result' in statusResult) {
|
|
127
|
+
data = statusResult.result as T;
|
|
128
|
+
} else {
|
|
129
|
+
data = statusResult as T;
|
|
130
|
+
}
|
|
131
|
+
|
|
184
132
|
return {
|
|
185
133
|
success: true,
|
|
186
|
-
data
|
|
134
|
+
data,
|
|
187
135
|
attempts: attempt + 1,
|
|
188
136
|
elapsedMs: Date.now() - startTime,
|
|
189
137
|
};
|
|
190
138
|
}
|
|
139
|
+
|
|
140
|
+
// Report progress based on attempt number
|
|
141
|
+
const progress = Math.min((attempt / maxAttempts) * 100, 90);
|
|
142
|
+
onProgress?.(progress);
|
|
143
|
+
|
|
191
144
|
} catch (error) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (__DEV__) {
|
|
195
|
-
console.warn("[JobPoller] Transient error during polling", {
|
|
196
|
-
attempt: attempt + 1,
|
|
197
|
-
requestId,
|
|
198
|
-
model,
|
|
199
|
-
consecutiveErrors: consecutiveTransientErrors,
|
|
200
|
-
error: error instanceof Error ? error.message : String(error),
|
|
201
|
-
code: (error as { code?: string })?.code,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
145
|
+
consecutiveErrors++;
|
|
146
|
+
logTransientError(attempt, requestId, model, consecutiveErrors, error);
|
|
204
147
|
|
|
205
|
-
// Check if we've hit max consecutive
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
console.error("[JobPoller] Max consecutive errors reached", {
|
|
209
|
-
maxConsecutiveErrors,
|
|
210
|
-
requestId,
|
|
211
|
-
model,
|
|
212
|
-
});
|
|
213
|
-
}
|
|
148
|
+
// Check if we've hit max consecutive errors
|
|
149
|
+
if (consecutiveErrors >= maxConsecutiveErrors) {
|
|
150
|
+
logMaxConsecutiveErrors(maxConsecutiveErrors, requestId, model);
|
|
214
151
|
return {
|
|
215
152
|
success: false,
|
|
216
|
-
error:
|
|
153
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
217
154
|
attempts: attempt + 1,
|
|
218
155
|
elapsedMs: Date.now() - startTime,
|
|
219
156
|
};
|
|
220
157
|
}
|
|
221
|
-
|
|
222
|
-
// Continue polling on transient errors
|
|
223
|
-
continue;
|
|
224
158
|
}
|
|
159
|
+
|
|
160
|
+
// Wait before next attempt with exponential backoff
|
|
161
|
+
await withAbortSignal(
|
|
162
|
+
new Promise(resolve => setTimeout(resolve, currentInterval)),
|
|
163
|
+
signal
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Increase interval for next attempt (exponential backoff)
|
|
167
|
+
currentInterval = Math.min(currentInterval * backoffMultiplier, maxInterval);
|
|
225
168
|
}
|
|
226
169
|
|
|
170
|
+
// Max attempts reached
|
|
227
171
|
return {
|
|
228
172
|
success: false,
|
|
229
|
-
error: new Error(`
|
|
173
|
+
error: new Error(`Job did not complete after ${maxAttempts} attempts`),
|
|
230
174
|
attempts: maxAttempts,
|
|
231
175
|
elapsedMs: Date.now() - startTime,
|
|
232
176
|
};
|
|
233
177
|
}
|
|
234
178
|
|
|
179
|
+
export type { PollJobOptions, PollJobResult } from './job-poller.types';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { PollingConfig } from "../../../../domain/entities/polling.types";
|
|
7
|
-
import { calculatePollingInterval as calculateInterval } from "../../../../shared/utils/calculations
|
|
7
|
+
import { calculatePollingInterval as calculateInterval } from "../../../../shared/utils/calculations";
|
|
8
8
|
|
|
9
9
|
export interface IntervalOptions {
|
|
10
10
|
attempt: number;
|
|
@@ -2,7 +2,7 @@ import { useCallback, useRef, useState, useMemo } from "react";
|
|
|
2
2
|
import { usePendingJobs } from "./use-pending-jobs";
|
|
3
3
|
import { executeDirectGeneration, executeQueuedJob } from "../../infrastructure/executors/backgroundJobExecutor";
|
|
4
4
|
import { DEFAULT_QUEUE_CONFIG } from "../../domain/entities/job.types";
|
|
5
|
-
import { calculateFilteredCount } from "../../../../shared/utils/calculations
|
|
5
|
+
import { calculateFilteredCount } from "../../../../shared/utils/calculations";
|
|
6
6
|
import type {
|
|
7
7
|
UseBackgroundGenerationOptions,
|
|
8
8
|
UseBackgroundGenerationReturn,
|