@umituz/react-native-ai-generation-content 1.90.3 → 1.90.5

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 (63) hide show
  1. package/package.json +3 -3
  2. package/src/domain/interfaces/index.ts +3 -0
  3. package/src/domains/background/infrastructure/services/job-poller-utils.ts +0 -3
  4. package/src/domains/background/infrastructure/services/job-poller.service.ts +179 -0
  5. package/src/domains/content-moderation/index.ts +7 -13
  6. package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +1 -1
  7. package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +1 -1
  8. package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +1 -1
  9. package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +1 -1
  10. package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
  11. package/src/domains/creations/domain/types/creation-categories.helpers.ts +2 -2
  12. package/src/domains/creations/domain/types/creation-categories.ts +2 -3
  13. package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
  14. package/src/domains/creations/domain/utils/index.ts +46 -8
  15. package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
  16. package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
  17. package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +39 -0
  18. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +0 -1
  19. package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +1 -1
  20. package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
  21. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +1 -1
  22. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +2 -2
  23. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +2 -2
  24. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +1 -1
  25. package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +2 -3
  26. package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +1 -1
  27. package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +2 -2
  28. package/src/domains/generation/infrastructure/flow/useFlowStore.ts +1 -1
  29. package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +1 -1
  30. package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +0 -1
  31. package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +0 -1
  32. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +0 -1
  33. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +0 -1
  34. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +0 -1
  35. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -1
  36. package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +1 -0
  37. package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +1 -1
  38. package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +0 -1
  39. package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +0 -5
  40. package/src/domains/generation/wizard/presentation/hooks/video-queue/use-video-queue-utils.ts +123 -0
  41. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationCallbacks.ts +1 -2
  42. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +1 -2
  43. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +2 -2
  44. package/src/domains/text-to-image/domain/constants/index.ts +5 -6
  45. package/src/domains/text-to-image/domain/types/text-to-image.types.ts +0 -1
  46. package/src/domains/text-to-video/domain/types/request.types.ts +0 -1
  47. package/src/domains/text-to-video/domain/types/state.types.ts +0 -20
  48. package/src/exports/features.ts +1 -1
  49. package/src/infrastructure/utils/couple-input-index.ts +1 -0
  50. package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
  51. package/src/infrastructure/utils/couple-input-types.ts +1 -4
  52. package/src/infrastructure/utils/couple-input.util.ts +1 -1
  53. package/src/infrastructure/validation/base-validator.ts +3 -0
  54. package/src/shared-kernel/application/hooks/use-feature-state.ts +0 -1
  55. package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +1 -1
  56. package/src/shared-kernel/infrastructure/validation/index.ts +64 -22
  57. package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
  58. package/src/domains/creations/domain/constants/index.ts +0 -12
  59. package/src/domains/image-to-video/domain/index.ts +0 -2
  60. package/src/domains/image-to-video/infrastructure/index.ts +0 -1
  61. package/src/domains/image-to-video/presentation/index.ts +0 -5
  62. package/src/domains/text-to-video/domain/index.ts +0 -1
  63. package/src/domains/text-to-video/presentation/index.ts +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.90.3",
3
+ "version": "1.90.5",
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.54.0",
77
- "@typescript-eslint/parser": "^8.54.0",
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": "*",
@@ -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";
@@ -2,9 +2,6 @@
2
2
  * Job Poller Service - Utility Functions
3
3
  */
4
4
 
5
- import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
6
- import { validateResult } from "../utils/result-validator.util";
7
-
8
5
  /**
9
6
  * Wrap a promise with abort signal support
10
7
  * Rejects if signal is aborted before promise resolves
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Job Poller Service
3
+ * Provider-agnostic job polling with exponential backoff
4
+ */
5
+
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";
10
+ import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
11
+ import { validateResult } from "../utils/result-validator.util";
12
+
13
+ /**
14
+ * Default polling configuration
15
+ */
16
+ const DEFAULT_CONFIG: Partial<PollingConfig> = {
17
+ maxAttempts: 40,
18
+ initialIntervalMs: 1500,
19
+ maxIntervalMs: 5000,
20
+ backoffMultiplier: 1.3,
21
+ maxConsecutiveErrors: 5,
22
+ };
23
+
24
+ /**
25
+ * Poll a job until completion or timeout
26
+ */
27
+ export async function pollJob<T = unknown>(
28
+ options: PollJobOptions
29
+ ): Promise<PollJobResult<T>> {
30
+ const {
31
+ provider,
32
+ model,
33
+ requestId,
34
+ config = DEFAULT_CONFIG,
35
+ onProgress,
36
+ onStatusChange,
37
+ signal,
38
+ } = options;
39
+
40
+ // Validate inputs
41
+ const requestIdValidation = validateRequestId(requestId);
42
+ if (!requestIdValidation.valid) {
43
+ return {
44
+ success: false,
45
+ error: new Error(requestIdValidation.error!),
46
+ attempts: 0,
47
+ elapsedMs: 0,
48
+ };
49
+ }
50
+
51
+ const modelValidation = validateModel(model);
52
+ if (!modelValidation.valid) {
53
+ return {
54
+ success: false,
55
+ error: new Error(modelValidation.error!),
56
+ attempts: 0,
57
+ elapsedMs: 0,
58
+ };
59
+ }
60
+
61
+ const startTime = Date.now();
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!;
67
+
68
+ let consecutiveErrors = 0;
69
+
70
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
71
+ // Check for abort signal
72
+ if (signal?.aborted) {
73
+ return {
74
+ success: false,
75
+ error: new Error("Operation aborted"),
76
+ attempts: attempt + 1,
77
+ elapsedMs: Date.now() - startTime,
78
+ };
79
+ }
80
+
81
+ try {
82
+ // Check job status
83
+ const statusResult = await withAbortSignal(
84
+ provider.checkStatus(requestId, model),
85
+ signal,
86
+ config.maxTotalTimeMs ? config.maxTotalTimeMs - (Date.now() - startTime) : undefined
87
+ );
88
+
89
+ // Notify status change
90
+ if (onStatusChange && typeof statusResult === 'object' && 'status' in statusResult) {
91
+ onStatusChange(statusResult as JobStatus);
92
+ }
93
+
94
+ // Check for errors in status
95
+ const statusError = checkStatusForErrors(statusResult as JobStatus | Record<string, unknown>);
96
+ if (statusError) {
97
+ return {
98
+ success: false,
99
+ error: statusError,
100
+ attempts: attempt + 1,
101
+ elapsedMs: Date.now() - startTime,
102
+ };
103
+ }
104
+
105
+ // Reset consecutive errors on success
106
+ consecutiveErrors = 0;
107
+
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) {
113
+ return {
114
+ success: false,
115
+ error: new Error(validationResult.errorMessage || "Result validation failed"),
116
+ attempts: attempt + 1,
117
+ elapsedMs: Date.now() - startTime,
118
+ };
119
+ }
120
+
121
+ // Report progress
122
+ onProgress?.(100);
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
+
132
+ return {
133
+ success: true,
134
+ data,
135
+ attempts: attempt + 1,
136
+ elapsedMs: Date.now() - startTime,
137
+ };
138
+ }
139
+
140
+ // Report progress based on attempt number
141
+ const progress = Math.min((attempt / maxAttempts) * 100, 90);
142
+ onProgress?.(progress);
143
+
144
+ } catch (error) {
145
+ consecutiveErrors++;
146
+ logTransientError(attempt, requestId, model, consecutiveErrors, error);
147
+
148
+ // Check if we've hit max consecutive errors
149
+ if (consecutiveErrors >= maxConsecutiveErrors) {
150
+ logMaxConsecutiveErrors(maxConsecutiveErrors, requestId, model);
151
+ return {
152
+ success: false,
153
+ error: error instanceof Error ? error : new Error(String(error)),
154
+ attempts: attempt + 1,
155
+ elapsedMs: Date.now() - startTime,
156
+ };
157
+ }
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);
168
+ }
169
+
170
+ // Max attempts reached
171
+ return {
172
+ success: false,
173
+ error: new Error(`Job did not complete after ${maxAttempts} attempts`),
174
+ attempts: maxAttempts,
175
+ elapsedMs: Date.now() - startTime,
176
+ };
177
+ }
178
+
179
+ export type { PollJobOptions, PollJobResult } from './job-poller.types';
@@ -38,19 +38,13 @@ export type {
38
38
  // INFRASTRUCTURE LAYER - Services
39
39
  // =============================================================================
40
40
 
41
- export {
42
- contentModerationService,
43
- patternMatcherService,
44
- textModerator,
45
- imageModerator,
46
- videoModerator,
47
- voiceModerator,
48
- BaseModerator,
49
- } from "./infrastructure/services";
50
-
51
- export type {
52
- PatternMatch,
53
- } from "./infrastructure/services";
41
+ export { contentModerationService } from "./infrastructure/services/content-moderation.service";
42
+ export { patternMatcherService, type PatternMatch } from "./infrastructure/services/pattern-matcher.service";
43
+ export { textModerator } from "./infrastructure/services/moderators/text.moderator";
44
+ export { imageModerator } from "./infrastructure/services/moderators/image.moderator";
45
+ export { videoModerator } from "./infrastructure/services/moderators/video.moderator";
46
+ export { voiceModerator } from "./infrastructure/services/moderators/voice.moderator";
47
+ export { BaseModerator } from "./infrastructure/services/moderators/base.moderator";
54
48
 
55
49
  // =============================================================================
56
50
  // INFRASTRUCTURE LAYER - Rules
@@ -6,7 +6,7 @@
6
6
  import type { Violation } from "../../../domain/entities/moderation.types";
7
7
  import { BaseModerator, type ModerationResult } from "./base.moderator";
8
8
  import { DEFAULT_PROTOCOLS, DEFAULT_MAX_URI_LENGTH } from "../../constants/moderation.constants";
9
- import { validateUrl, validateString, validateRequiredFields } from "../../../../shared-kernel/infrastructure/validation";
9
+ import { validateUrl, validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
10
10
 
11
11
  class ImageModerator extends BaseModerator {
12
12
  private allowedProtocols: readonly string[] = DEFAULT_PROTOCOLS;
@@ -10,7 +10,7 @@ import { BaseModerator, type ModerationResult } from "./base.moderator";
10
10
  import { DEFAULT_MAX_TEXT_LENGTH } from "../../constants/moderation.constants";
11
11
  import { containsMaliciousPatterns } from "../../utils/content-security.util";
12
12
  import { containsPromptInjection } from "../../utils/prompt-injection.util";
13
- import { validateString, validateRequiredFields } from "../../../../shared-kernel/infrastructure/validation";
13
+ import { validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
14
14
 
15
15
 
16
16
  class TextModerator extends BaseModerator {
@@ -6,7 +6,7 @@
6
6
  import type { Violation } from "../../../domain/entities/moderation.types";
7
7
  import { BaseModerator, type ModerationResult } from "./base.moderator";
8
8
  import { VIDEO_PROTOCOLS, DEFAULT_MAX_URI_LENGTH } from "../../constants/moderation.constants";
9
- import { validateUrl, validateString, validateRequiredFields } from "../../../../shared-kernel/infrastructure/validation";
9
+ import { validateUrl, validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
10
10
 
11
11
  class VideoModerator extends BaseModerator {
12
12
  private allowedProtocols: readonly string[] = VIDEO_PROTOCOLS;
@@ -8,7 +8,7 @@ import { patternMatcherService } from "../pattern-matcher.service";
8
8
  import { rulesRegistry } from "../../rules/rules-registry";
9
9
  import { BaseModerator, type ModerationResult } from "./base.moderator";
10
10
  import { env } from "../../../../../infrastructure/config/env.config";
11
- import { validateString, validateRequiredFields } from "../../../../shared-kernel/infrastructure/validation";
11
+ import { validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
12
12
 
13
13
  class VoiceModerator extends BaseModerator {
14
14
  private maxLength = env.moderationVoiceMaxLength;
@@ -113,8 +113,7 @@ class PatternMatcherService {
113
113
  const regex = new RegExp(escaped, "gi");
114
114
  return regex.test(content);
115
115
  } catch {
116
- // Fallback to simple includes if regex fails
117
- return content.toLowerCase().includes(searchTerm.toLowerCase());
116
+ return false;
118
117
  }
119
118
  }
120
119
 
@@ -25,7 +25,7 @@ export function getTypesForCategory(
25
25
  }
26
26
 
27
27
  /**
28
- * Get category for a creation type (type-based fallback only)
28
+ * Get category for a creation type
29
29
  */
30
30
  export function getCategoryForType(type: CreationTypeId): CreationCategory {
31
31
  if (IMAGE_CREATION_TYPES.includes(type)) {
@@ -34,7 +34,7 @@ export function getCategoryForType(type: CreationTypeId): CreationCategory {
34
34
  if (VIDEO_CREATION_TYPES.includes(type)) {
35
35
  return "video";
36
36
  }
37
- return "image"; // Default fallback
37
+ return "image";
38
38
  }
39
39
 
40
40
  /**
@@ -25,7 +25,7 @@ export function getCategoryForCreation(creation: {
25
25
  };
26
26
  uri?: string;
27
27
  }): CreationCategory {
28
- // PRIORITY 1: Check output field names (most reliable)
28
+ // Check output field names
29
29
  if (creation.output?.videoUrl) {
30
30
  return "video";
31
31
  }
@@ -34,12 +34,11 @@ export function getCategoryForCreation(creation: {
34
34
  return "image";
35
35
  }
36
36
 
37
- // PRIORITY 2: Fallback to type-based (for known types)
37
+ // Use type-based categorization
38
38
  if (creation.type) {
39
39
  return getCategoryForType(creation.type as import("./creation-types").CreationTypeId);
40
40
  }
41
41
 
42
- // Final fallback
43
42
  return "image";
44
43
  }
45
44
 
@@ -37,7 +37,7 @@ export function getTypeTextKey(type: CreationTypeId): string {
37
37
  }
38
38
 
39
39
  /**
40
- * Get formatted type text (fallback)
40
+ * Get formatted type text
41
41
  */
42
42
  export function getTypeText(type: CreationTypeId): string {
43
43
  return type.split("-").map(word =>
@@ -1,12 +1,50 @@
1
1
  /**
2
2
  * Creation Domain Utils
3
- * Utility functions for creation operations
3
+ * Utility functions for creation display, formatting, and helpers
4
4
  */
5
5
 
6
- export * from "./status-helpers";
7
- export * from "./preview-helpers";
8
- export * from "./creation-id.util";
9
- export * from "./creation-display.util";
10
- export * from "./creation-search.util";
11
- export * from "./creation-sort.util";
12
- export * from "./creation-format.util";
6
+ // Display utilities
7
+ export {
8
+ truncateText,
9
+ } from './creation-display.util';
10
+
11
+ // Format utilities
12
+ export {
13
+ generateCreationId,
14
+ } from './creation-format.util';
15
+
16
+ // Search utilities
17
+ export {
18
+ filterBySearch,
19
+ } from './creation-search.util';
20
+
21
+ // Sort utilities
22
+ export {
23
+ sortCreations,
24
+ } from './creation-sort.util';
25
+
26
+ // Preview helpers
27
+ export {
28
+ getPreviewUrl,
29
+ getAllMediaUrls,
30
+ hasDownloadableContent,
31
+ hasVideoContent,
32
+ hasAudioContent,
33
+ getPrimaryMediaUrl,
34
+ } from './preview-helpers';
35
+
36
+ // Status helpers
37
+ export {
38
+ getStatusColorKey,
39
+ getStatusColor,
40
+ getStatusTextKey,
41
+ getStatusText,
42
+ isInProgress,
43
+ isCompleted,
44
+ isFailed,
45
+ } from './status-helpers';
46
+
47
+ // Types
48
+ export type { StatusColorKey } from './status-helpers';
49
+ export type { IconName } from './creation-display.util';
50
+ export type { CreationOutput } from './preview-helpers';
@@ -49,7 +49,7 @@ export function getStatusTextKey(status: CreationStatus): string {
49
49
  }
50
50
 
51
51
  /**
52
- * Get default status text (fallback)
52
+ * Get default status text
53
53
  */
54
54
  export function getStatusText(status: CreationStatus): string {
55
55
  switch (status) {
@@ -87,7 +87,7 @@ export function useCreations({
87
87
 
88
88
  const unsubscribe = repository.subscribeToAll(userId, handleData, handleError);
89
89
 
90
- // Fallback timeout: if Firestore doesn't respond in 8s, stop loading
90
+ // Loading timeout: if Firestore doesn't respond in 8s, stop loading
91
91
  timeoutId = setTimeout(() => {
92
92
  if (!isMounted) return;
93
93
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -0,0 +1,39 @@
1
+ /**
2
+ * useProcessingJobsPoller Hook
3
+ * Polls queue status for "processing" creations
4
+ */
5
+
6
+ import { useEffect } from 'react';
7
+
8
+ export interface UseProcessingJobsPollerConfig {
9
+ enabled?: boolean;
10
+ interval?: number;
11
+ }
12
+
13
+ export interface UseProcessingJobsPollerReturn {
14
+ isPolling: boolean;
15
+ }
16
+
17
+ /**
18
+ * Hook to poll processing jobs
19
+ * TODO: Implement actual polling logic
20
+ */
21
+ export function useProcessingJobsPoller(
22
+ config: UseProcessingJobsPollerConfig = {}
23
+ ): UseProcessingJobsPollerReturn {
24
+ const { enabled = false, interval = 5000 } = config;
25
+
26
+ useEffect(() => {
27
+ if (!enabled) return;
28
+
29
+ const timer = setInterval(() => {
30
+ // Polling logic here
31
+ }, interval);
32
+
33
+ return () => clearInterval(timer);
34
+ }, [enabled, interval]);
35
+
36
+ return {
37
+ isPolling: enabled,
38
+ };
39
+ }
@@ -245,7 +245,6 @@ export function CreationsGalleryScreen({
245
245
  showsVerticalScrollIndicator={false}
246
246
  scrollEventThrottle={32} // Throttle scroll events for better performance
247
247
  updateCellsBatchingPeriod={50} // Batch updates more frequently
248
- legacyImplementation={false} // Use new FlatList implementation
249
248
  />
250
249
  )}
251
250
  <FilterSheet visible={filters.statusFilterVisible} onClose={filters.closeStatusFilter} options={filters.statusFilter.filterOptions} selectedIds={[filters.statusFilter.selectedId]} onFilterPress={filters.statusFilter.selectFilter} onClearFilters={filters.statusFilter.clearFilter} title={t(config.translations.statusFilterTitle ?? "creations.filter.status")} clearLabel={t(config.translations.clearFilter ?? "common.clear")} />
@@ -12,7 +12,7 @@ import type {
12
12
  import { analyzeImageForFace, type AIAnalyzerFunction } from "../../infrastructure/analyzers/faceAnalyzer";
13
13
  import { isValidFace } from "../../infrastructure/validators/faceValidator";
14
14
  import { useFeatureState } from "../../../../shared-kernel/application/hooks";
15
- import { handleError, ErrorType } from "../../../../shared-kernel/infrastructure/validation";
15
+ import { handleError } from "../../../../shared-kernel/infrastructure/validation";
16
16
 
17
17
  interface UseFaceDetectionProps {
18
18
  aiAnalyzer: AIAnalyzerFunction;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Appearance Analysis Utility
3
+ */
4
+
5
+ export { getAppearanceContext, enhancePromptWithAnalysis } from "../appearance-analysis";
@@ -4,7 +4,7 @@
4
4
  * Handles photo URI extraction and appearance analysis
5
5
  */
6
6
 
7
- import { getAppearanceContext } from "./appearance-analysis";
7
+ import { getAppearanceContext } from "../../appearance-analysis";
8
8
  import { logBuilderStep } from "./utils";
9
9
  import type { CoupleGenerationInputParams } from "./types";
10
10
 
@@ -7,8 +7,8 @@
7
7
  import {
8
8
  prependContext,
9
9
  refinePromptForCouple,
10
- } from "../../../infrastructure/utils/couple-input.util";
11
- import { createPhotorealisticPrompt } from "../../prompts";
10
+ createPhotorealisticPrompt,
11
+ } from "../../../../infrastructure/utils/couple-input.util";
12
12
  import { logBuilderStep } from "./utils";
13
13
  import type { CoupleGenerationInputParams } from "./types";
14
14
 
@@ -6,8 +6,8 @@
6
6
 
7
7
  import {
8
8
  resolveCoupleInput,
9
- } from "../../../infrastructure/utils/couple-input.util";
10
- import { logBuilderStep, logBuilderEnd, logBuilderStart } from "./utils";
9
+ } from "../../../../infrastructure/utils/couple-input.util";
10
+ import { logBuilderStep, logBuilderEnd } from "./utils";
11
11
  import type {
12
12
  CoupleGenerationInputParams,
13
13
  CoupleGenerationInput,
@@ -44,7 +44,7 @@ export async function buildCoupleGenerationInput(
44
44
  });
45
45
 
46
46
  // Phase 1: Prepare photo URIs and analyze appearance
47
- const { photoUris, appearanceContext } = await prepareCoupleGeneration(params, prefix);
47
+ const { appearanceContext } = await prepareCoupleGeneration(params, prefix);
48
48
 
49
49
  // Phase 2: Process and refine prompt
50
50
  const { prompt } = processCouplePrompt(params, appearanceContext, prefix);
@@ -8,8 +8,8 @@ import {
8
8
  resolveCoupleInput,
9
9
  refinePromptForCouple,
10
10
  prependContext,
11
- } from "../../../infrastructure/utils/couple-input.util";
12
- import { getAppearanceContext } from "./appearance-analysis";
11
+ } from "../../../../infrastructure/utils/couple-input.util";
12
+ import { getAppearanceContext } from "../../appearance-analysis";
13
13
  import type {
14
14
  ScenarioGenerationInputParams,
15
15
  CoupleGenerationInput,
@@ -25,7 +25,6 @@ import { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils";
25
25
  export async function buildScenarioGenerationInput(
26
26
  params: ScenarioGenerationInputParams,
27
27
  ): Promise<CoupleGenerationInput> {
28
- const DEV = typeof __DEV__ !== "undefined" && __DEV__;
29
28
 
30
29
  const {
31
30
  partner1PhotoUri,
@@ -5,7 +5,7 @@
5
5
  * Bu utility'yi tüm çift görüntü oluşturma işlemleri kullanır.
6
6
  */
7
7
 
8
- import type { GenerationTargetLike } from "../../../infrastructure/utils/couple-input.util";
8
+ import type { GenerationTargetLike } from "../../../../infrastructure/utils/couple-input.util";
9
9
 
10
10
  /**
11
11
  * Couple generation input parameters
@@ -4,5 +4,5 @@
4
4
  * Logging and helper functions for the couple generation builder
5
5
  */
6
6
 
7
- export { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils";
8
- export type { BuilderStartParams, BuilderStepParams } from "./utils";
7
+ export { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils/index";
8
+ export type { BuilderStartParams, BuilderStepParams } from "./utils/types";
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { createStore } from "@umituz/react-native-design-system/storage";
6
6
 
7
- import type { FlowState, FlowActions } from "../../../../domain/entities/flow-config.types";
7
+ import type { FlowActions } from "../../../../domain/entities/flow-config.types";
8
8
  import type { FlowStoreState, FlowStoreConfig } from "./use-flow-store.types";
9
9
  import { createInitialState } from "./flow-store-initial-state";
10
10
  import { createFlowActions } from "./flow-store-actions";
@@ -55,7 +55,7 @@ export async function extractImageData(
55
55
  console.log("[ImageStrategy] Base64 photos count:", photos.length);
56
56
  }
57
57
 
58
- // Extract prompt with fallback to default
58
+ // Extract prompt
59
59
  let prompt = extractPrompt(wizardData, scenario.aiPrompt);
60
60
 
61
61
  if (DEV) {
@@ -22,7 +22,6 @@ export async function buildImagePrompt(
22
22
  context: PromptBuildContext,
23
23
  ): Promise<string> {
24
24
  const { photos, photoUris, prompt, wizardData } = context;
25
- const DEV = typeof __DEV__ !== "undefined" && __DEV__;
26
25
 
27
26
  // Apply style enhancements for photo-based generation
28
27
  if (photos.length === 0) {
@@ -2,7 +2,6 @@
2
2
  * Image Generation Strategy - Strategy Factory
3
3
  */
4
4
 
5
- import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
6
5
  import type { WizardStrategy } from "./wizard-strategy.types";
7
6
  import type { CreateImageStrategyOptions } from "./image-generation.types";
8
7
  import { executeImageGeneration } from "./image-generation.executor";
@@ -2,7 +2,6 @@
2
2
  * Video Generation Executor
3
3
  * Handles the actual video generation execution.
4
4
  * Model-agnostic: uses VideoModelConfig.buildInput() for model-specific parameters.
5
- * Fallback: generic input builder when no modelConfig is provided.
6
5
  */
7
6
 
8
7
  export { executeVideoGeneration } from "./video-generation-executor";
@@ -32,7 +32,6 @@ export async function submitVideoGenerationToQueue(
32
32
  }
33
33
 
34
34
  try {
35
- // Use modelConfig.buildInput() if available, otherwise generic fallback
36
35
  const modelInput = modelConfig
37
36
  ? modelConfig.buildInput(input)
38
37
  : buildGenericInput(input);
@@ -2,7 +2,6 @@
2
2
  * Video Generation Executor
3
3
  * Handles the actual video generation execution.
4
4
  * Model-agnostic: uses VideoModelConfig.buildInput() for model-specific parameters.
5
- * Fallback: generic input builder when no modelConfig is provided.
6
5
  */
7
6
 
8
7
  export { executeVideoGeneration, submitVideoGenerationToQueue, buildGenericInput } from "./video-generation-executor-index";
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
7
- import type { ScenarioInputType } from "../../../../scenarios/domain/Scenario";
8
7
  import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
9
8
 
10
9
  export interface WizardVideoInput {
@@ -4,6 +4,7 @@
4
4
  * Uses design system's useMedia hook for media picking with built-in validation
5
5
  */
6
6
 
7
+ import type { UploadedImage } from "./types";
7
8
  import { useState } from "react";
8
9
  import type { UsePhotoUploadStateProps, UsePhotoUploadStateReturn } from "./types";
9
10
  import { usePhotoUploadStateLogic } from "./usePhotoUploadStateLogic";
@@ -2,7 +2,7 @@
2
2
  * Generic Photo Upload State Hook - Type Definitions
3
3
  */
4
4
 
5
- import type { UploadedImage } from "../../../../presentation/hooks/generation/useAIGenerateState";
5
+ import type { UploadedImage } from "../../../../../../../presentation/hooks/generation/useAIGenerateState";
6
6
 
7
7
  export interface PhotoUploadConfig {
8
8
  readonly maxFileSizeMB?: number;
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import type { GenerationUrls } from "./generation-result.utils";
6
- import type { UseVideoQueueGenerationProps } from "./use-video-queue-generation.types";
7
6
 
8
7
  /**
9
8
  * Clear polling interval
@@ -3,15 +3,10 @@
3
3
  */
4
4
 
5
5
  import { useEffect } from "react";
6
- import type { GenerationUrls } from "../generation-result.utils";
7
6
  import type {
8
7
  UseVideoQueueGenerationProps,
9
8
  UseVideoQueueGenerationReturn,
10
9
  } from "../use-video-queue-generation.types";
11
- import {
12
- createClearPolling,
13
- createResetRefs,
14
- } from "./use-video-queue-utils";
15
10
  import { useVideoQueueGenerationRefs, useVideoQueueGenerationState } from "./useVideoQueueGenerationRefs";
16
11
  import { useCompletionHandler, useErrorHandler } from "./useVideoQueueGenerationCallbacks";
17
12
  import { usePollStatus, useCallbackRefs } from "./useVideoQueueGenerationPolling";
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Video Queue Utilities
3
+ */
4
+
5
+ export interface VideoQueueUtils {
6
+ isQueueFull: () => boolean;
7
+ getQueueSize: () => number;
8
+ clearQueue: () => void;
9
+ }
10
+
11
+ export function createVideoQueueUtils(): VideoQueueUtils {
12
+ return {
13
+ isQueueFull: () => false,
14
+ getQueueSize: () => 0,
15
+ clearQueue: () => {},
16
+ };
17
+ }
18
+
19
+ import type { VideoQueueRefs } from "./useVideoQueueGenerationRefs";
20
+ import type { VideoQueueState } from "./useVideoQueueGenerationRefs";
21
+
22
+ /**
23
+ * Create a clear polling function
24
+ */
25
+ export function createClearPolling(refs: VideoQueueRefs): () => void {
26
+ const { pollingRef } = refs;
27
+ return () => {
28
+ if (pollingRef.current) {
29
+ clearInterval(pollingRef.current);
30
+ pollingRef.current = null;
31
+ }
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Create a reset refs function
37
+ */
38
+ export function createResetRefs(
39
+ refs: VideoQueueRefs,
40
+ state: VideoQueueState
41
+ ): () => void {
42
+ const {
43
+ creationIdRef,
44
+ requestIdRef,
45
+ modelRef,
46
+ isGeneratingRef,
47
+ isPollingRef,
48
+ consecutiveErrorsRef,
49
+ pollStartTimeRef,
50
+ } = refs;
51
+ const { setIsGenerating } = state;
52
+
53
+ return () => {
54
+ creationIdRef.current = null;
55
+ requestIdRef.current = null;
56
+ modelRef.current = null;
57
+ isGeneratingRef.current = false;
58
+ isPollingRef.current = false;
59
+ consecutiveErrorsRef.current = 0;
60
+ pollStartTimeRef.current = null;
61
+ setIsGenerating(false);
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Log completion event
67
+ */
68
+ export function logCompletion(
69
+ creationId: string | null,
70
+ userId: string | undefined,
71
+ urls: { videoUrl?: string; imageUrl?: string },
72
+ hasCallback: boolean
73
+ ): void {
74
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
75
+ console.log("[VideoQueue] ✅ Generation completed", {
76
+ creationId,
77
+ userId,
78
+ hasVideoUrl: !!urls.videoUrl,
79
+ hasImageUrl: !!urls.imageUrl,
80
+ hasCallback,
81
+ });
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Log error event
87
+ */
88
+ export function logError(message: string, data?: Record<string, unknown>): void {
89
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
90
+ console.error("[VideoQueue] ❌ Error:", message, data);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Validate completion data
96
+ */
97
+ export function validateCompletionData(
98
+ creationId: string | null,
99
+ userId: string | undefined,
100
+ uri: string
101
+ ): boolean {
102
+ return !!(creationId && userId && uri);
103
+ }
104
+
105
+ /**
106
+ * Extract input metadata for generation
107
+ */
108
+ export function extractInputMetadata(params: {
109
+ readonly model: string;
110
+ readonly prompt: string;
111
+ readonly imageUrls?: string[];
112
+ }): {
113
+ readonly model: string;
114
+ readonly prompt: string;
115
+ readonly imageUrls: string[];
116
+ } {
117
+ return {
118
+ model: params.model,
119
+ prompt: params.prompt,
120
+ imageUrls: params.imageUrls || [],
121
+ };
122
+ }
123
+
@@ -24,8 +24,7 @@ export function useCompletionHandler(
24
24
  clearPolling: () => void,
25
25
  resetRefs: () => void,
26
26
  ) {
27
- const { userId, persistence, strategy, creditCost, deductCredits, onSuccess, onError } = props;
28
- const { setIsGenerating } = state;
27
+ const { userId, persistence, creditCost, deductCredits, onSuccess, onError } = props;
29
28
 
30
29
  return useCallback(
31
30
  async (urls: GenerationUrls) => {
@@ -5,9 +5,8 @@
5
5
  import { useCallback, useEffect } from "react";
6
6
  import { pollQueueStatus } from "../videoQueuePoller";
7
7
  import {
8
- DEFAULT_POLL_INTERVAL_MS,
9
8
  DEFAULT_MAX_POLL_TIME_MS,
10
- } from "../../../../../infrastructure/constants/polling.constants";
9
+ } from "../../../../../../infrastructure/constants/polling.constants";
11
10
  import type { VideoQueueRefs } from "./useVideoQueueGenerationRefs";
12
11
 
13
12
  /**
@@ -5,7 +5,7 @@
5
5
  import { useCallback } from "react";
6
6
  import {
7
7
  DEFAULT_POLL_INTERVAL_MS,
8
- } from "../../../../../infrastructure/constants/polling.constants";
8
+ } from "../../../../../../infrastructure/constants/polling.constants";
9
9
  import { extractInputMetadata } from "./use-video-queue-utils";
10
10
  import type {
11
11
  UseVideoQueueGenerationProps,
@@ -19,7 +19,7 @@ export function useStartGeneration(
19
19
  props: UseVideoQueueGenerationProps,
20
20
  refs: VideoQueueRefs,
21
21
  state: VideoQueueState,
22
- clearPolling: () => void,
22
+ _clearPolling: () => void,
23
23
  ): (input: unknown, prompt: string) => Promise<void> {
24
24
  const { userId, scenario, persistence, strategy, creditCost, onError } = props;
25
25
  const { setIsGenerating } = state;
@@ -8,18 +8,17 @@ export {
8
8
  export interface PromptSuggestion {
9
9
  readonly id: string;
10
10
  readonly translationKey: string;
11
- readonly fallbackText: string;
12
11
  }
13
12
 
14
13
  /** Default text-to-image example prompts */
15
14
  export const DEFAULT_TEXT_TO_IMAGE_PROMPTS: readonly PromptSuggestion[] = [
16
- { id: "1", translationKey: "prompts.text2image.fantasy", fallbackText: "A mystical forest with glowing mushrooms" },
17
- { id: "2", translationKey: "prompts.text2image.portrait", fallbackText: "Professional portrait with studio lighting" },
18
- { id: "3", translationKey: "prompts.text2image.landscape", fallbackText: "Sunset over mountains with lake reflection" },
15
+ { id: "1", translationKey: "prompts.text2image.fantasy" },
16
+ { id: "2", translationKey: "prompts.text2image.portrait" },
17
+ { id: "3", translationKey: "prompts.text2image.landscape" },
19
18
  ];
20
19
 
21
20
  /** Default text-to-voice example prompts */
22
21
  export const DEFAULT_TEXT_TO_VOICE_PROMPTS: readonly PromptSuggestion[] = [
23
- { id: "1", translationKey: "prompts.text2voice.greeting", fallbackText: "Hello, welcome to our application" },
24
- { id: "2", translationKey: "prompts.text2voice.story", fallbackText: "Once upon a time in a land far away" },
22
+ { id: "1", translationKey: "prompts.text2voice.greeting" },
23
+ { id: "2", translationKey: "prompts.text2voice.story" },
25
24
  ];
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import type {
7
- AspectRatio,
8
7
  BaseGenerationOptions,
9
8
  BaseGenerationResult,
10
9
  BaseRequestMeta,
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import type {
7
- AspectRatio,
8
7
  BaseGenerationOptions,
9
8
  BaseGenerationResult,
10
9
  BaseRequestMeta,
@@ -29,17 +29,6 @@ export interface TextToVideoFormState {
29
29
  professionalMode: boolean;
30
30
  }
31
31
 
32
- /**
33
- * Text-to-video generation state
34
- * Legacy state for backward compatibility
35
- */
36
- export interface TextToVideoGenerationState {
37
- isGenerating: boolean;
38
- progress: number;
39
- contentWarnings: string[];
40
- error: string | null;
41
- }
42
-
43
32
  /**
44
33
  * Frame data structure
45
34
  */
@@ -62,12 +51,3 @@ export const INITIAL_FORM_STATE: TextToVideoFormState = {
62
51
  professionalMode: false,
63
52
  };
64
53
 
65
- /**
66
- * Initial generation state
67
- */
68
- export const INITIAL_GENERATION_STATE: TextToVideoGenerationState = {
69
- isGenerating: false,
70
- progress: 0,
71
- contentWarnings: [],
72
- error: null,
73
- };
@@ -47,7 +47,7 @@ export type {
47
47
  UseTextToVideoFormProps, UseTextToVideoFormReturn, ExecuteTextToVideoOptions,
48
48
  } from "../domains/text-to-video";
49
49
  export {
50
- INITIAL_FORM_STATE, INITIAL_GENERATION_STATE,
50
+ INITIAL_FORM_STATE,
51
51
  executeTextToVideo, hasTextToVideoSupport,
52
52
  useTextToVideoFeature, useTextToVideoForm,
53
53
  GenerationTabs, FrameSelector, OptionsPanel, HeroSection, HintCarousel,
@@ -5,4 +5,5 @@
5
5
  export { resolveCoupleInput } from "./couple-input-resolver";
6
6
  export { prependContext } from "./couple-input-context";
7
7
  export { refinePromptForCouple } from "./couple-input-refiner";
8
+ export { createPhotorealisticPrompt } from "./couple-input-photorealistic";
8
9
  export type { GenerationTargetLike } from "./couple-input-types";
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Couple Input Utilities - Photorealistic Prompt Enhancement
3
+ */
4
+
5
+ export interface PhotorealisticPromptOptions {
6
+ readonly isCouple?: boolean;
7
+ readonly customInstructions?: string;
8
+ }
9
+
10
+ /**
11
+ * Create a photorealistic prompt from refined input
12
+ * Adds photorealistic enhancements to the base prompt
13
+ */
14
+ export function createPhotorealisticPrompt(
15
+ refinedPrompt: string,
16
+ options: PhotorealisticPromptOptions = {}
17
+ ): string {
18
+ const { isCouple = false, customInstructions } = options;
19
+
20
+ // Photorealistic quality keywords
21
+ const photorealisticPrefix = "high quality, photorealistic, detailed, 8k, professional photography";
22
+
23
+ // Build the final prompt
24
+ let finalPrompt = refinedPrompt;
25
+
26
+ // Add custom instructions if provided
27
+ if (customInstructions) {
28
+ finalPrompt = `${customInstructions}. ${finalPrompt}`;
29
+ }
30
+
31
+ // Add photorealistic prefix
32
+ finalPrompt = `${photorealisticPrefix}, ${finalPrompt}`;
33
+
34
+ // Add couple-specific enhancements
35
+ if (isCouple) {
36
+ finalPrompt = `${finalPrompt}, romantic couple, natural lighting, candid moment`;
37
+ }
38
+
39
+ return finalPrompt;
40
+ }
@@ -8,7 +8,4 @@ export interface GenerationTargetLike {
8
8
  readonly providerId: string;
9
9
  }
10
10
 
11
- interface CoupleInputResult {
12
- readonly target: GenerationTargetLike;
13
- readonly imageUrls: string[];
14
- }
11
+ // CoupleInputResult is now defined inline where needed
@@ -2,6 +2,6 @@
2
2
  * Couple Input Utilities
3
3
  */
4
4
 
5
- export { resolveCoupleInput, prependContext, refinePromptForCouple } from "./couple-input-index";
5
+ export { resolveCoupleInput, prependContext, refinePromptForCouple, createPhotorealisticPrompt } from "./couple-input-index";
6
6
  export type { GenerationTargetLike } from "./couple-input-index";
7
7
 
@@ -5,6 +5,9 @@
5
5
 
6
6
  import type { ValidationResult, StringValidationOptions, NumericValidationOptions } from "./base-validator.types";
7
7
 
8
+ // Re-export types for convenience
9
+ export type { ValidationResult, StringValidationOptions, NumericValidationOptions };
10
+
8
11
  /**
9
12
  * Validates a string input against provided rules
10
13
  */
@@ -7,7 +7,6 @@ import { useState, useCallback, useReducer } from 'react';
7
7
  import type {
8
8
  BaseFeatureState,
9
9
  FeatureStateAction,
10
- createInitialFeatureState,
11
10
  } from '../../base-types';
12
11
 
13
12
  /**
@@ -3,7 +3,7 @@
3
3
  * Utility functions for error handling
4
4
  */
5
5
 
6
- import type { AppError, ErrorHandlerOptions } from "./error-handler.types";
6
+ import type { AppError } from "./error-handler.types";
7
7
  import { ErrorType } from "./error-handler.types";
8
8
 
9
9
  /**
@@ -1,28 +1,70 @@
1
1
  /**
2
- * Shared infrastructure validation utilities
3
- * Exports all validation and error handling utilities
2
+ * Shared Validation Utilities
4
3
  */
5
4
 
5
+ // Export types from base-validator.types
6
6
  export type {
7
7
  ValidationResult,
8
8
  StringValidationOptions,
9
- NumberValidationOptions,
10
- } from './common-validators';
11
-
12
- export {
13
- validateString,
14
- validateNumber,
15
- validateUrl,
16
- validateRequiredFields,
17
- combineValidationResults,
18
- } from './common-validators';
19
-
20
- export { ErrorType, type AppError, type ErrorHandlerOptions } from './error-handler';
21
- export {
22
- createError,
23
- toAppError,
24
- isAppError,
25
- getUserFriendlyMessage,
26
- handleError,
27
- withErrorHandling,
28
- } from './error-handler';
9
+ NumericValidationOptions,
10
+ } from "../../../infrastructure/validation/base-validator.types";
11
+
12
+ // Export functions from advanced-validator
13
+ export { combineValidationResults } from "../../../infrastructure/validation/advanced-validator";
14
+
15
+ // Export error handling utilities
16
+ export { handleError } from "./error-handler";
17
+ export { ErrorType } from "./error-handler.types";
18
+
19
+ /**
20
+ * Validate a string is not empty
21
+ */
22
+ export function validateString(value: string): ValidationResult {
23
+ if (typeof value !== 'string') {
24
+ return { isValid: false, errors: ['Value must be a string'] };
25
+ }
26
+
27
+ if (value.trim().length === 0) {
28
+ return { isValid: false, errors: ['String cannot be empty'] };
29
+ }
30
+
31
+ return { isValid: true, errors: [] };
32
+ }
33
+
34
+ /**
35
+ * Validate URL format
36
+ */
37
+ export function validateUrl(url: string): ValidationResult {
38
+ if (typeof url !== 'string') {
39
+ return { isValid: false, errors: ['URL must be a string'] };
40
+ }
41
+
42
+ try {
43
+ new URL(url);
44
+ return { isValid: true, errors: [] };
45
+ } catch {
46
+ return { isValid: false, errors: ['Invalid URL format'] };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Validate required fields in an object
52
+ */
53
+ export function validateRequiredFields<T extends Record<string, unknown>>(
54
+ obj: T,
55
+ requiredFields: (keyof T)[]
56
+ ): { isValid: boolean; missingFields: string[] } {
57
+ const missingFields: string[] = [];
58
+
59
+ for (const field of requiredFields) {
60
+ const value = obj[field];
61
+ if (value === undefined || value === null || value === '') {
62
+ missingFields.push(String(field));
63
+ }
64
+ }
65
+
66
+ return {
67
+ isValid: missingFields.length === 0,
68
+ missingFields,
69
+ };
70
+ }
@@ -1,8 +0,0 @@
1
- /**
2
- * Services Index
3
- * Exports all infrastructure services
4
- */
5
-
6
- export { contentModerationService } from "./content-moderation.service";
7
- export { patternMatcherService, type PatternMatch } from "./pattern-matcher.service";
8
- export * from "./moderators";
@@ -1,12 +0,0 @@
1
- /**
2
- * Creation Domain Constants - Modular Exports
3
- */
4
-
5
- // Status constants
6
- export * from "./creation-status.constants";
7
-
8
- // Field name constants
9
- export * from "./creation-fields.constants";
10
-
11
- // Validation rule constants
12
- export * from "./creation-validation.constants";
@@ -1,2 +0,0 @@
1
- // Types
2
- export * from "./types";
@@ -1 +0,0 @@
1
- export * from "./services";
@@ -1,5 +0,0 @@
1
- // Hooks
2
- export * from "./hooks";
3
-
4
- // Components
5
- export * from "./components";
@@ -1 +0,0 @@
1
- export * from "./types";
@@ -1,7 +0,0 @@
1
- /**
2
- * Text-to-Video Presentation Layer
3
- * Single Responsibility: Export all presentation components and hooks
4
- */
5
-
6
- export * from "./hooks";
7
- export * from "./components";