@umituz/react-native-ai-generation-content 1.17.87 → 1.17.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.17.87",
3
+ "version": "1.17.89",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -65,7 +65,12 @@ export type { ExecuteTextToImageOptions } from "./infrastructure";
65
65
  // PRESENTATION LAYER - Hooks
66
66
  // =============================================================================
67
67
 
68
- export { useFormState, useGeneration, useTextToImageForm } from "./presentation";
68
+ export {
69
+ useFormState,
70
+ useGeneration,
71
+ useTextToImageForm,
72
+ useTextToImageCallbacksBuilder,
73
+ } from "./presentation";
69
74
  export type {
70
75
  UseFormStateOptions,
71
76
  UseFormStateReturn,
@@ -74,6 +79,9 @@ export type {
74
79
  UseGenerationReturn,
75
80
  UseTextToImageFormOptions,
76
81
  UseTextToImageFormReturn,
82
+ TextToImageCallbacksBuilderConfig,
83
+ UseTextToImageCallbacksBuilderOptions,
84
+ UseTextToImageCallbacksBuilderReturn,
77
85
  } from "./presentation";
78
86
 
79
87
  // Provider-based Feature Hook
@@ -28,3 +28,11 @@ export type {
28
28
  UseTextToImageFeatureProps,
29
29
  UseTextToImageFeatureReturn,
30
30
  } from "./useTextToImageFeature";
31
+
32
+ // Callbacks Builder Hook
33
+ export { useTextToImageCallbacksBuilder } from "./useTextToImageCallbacksBuilder";
34
+ export type {
35
+ TextToImageCallbacksBuilderConfig,
36
+ UseTextToImageCallbacksBuilderOptions,
37
+ UseTextToImageCallbacksBuilderReturn,
38
+ } from "./useTextToImageCallbacksBuilder";
@@ -35,6 +35,8 @@ const initialState: GenerationState = {
35
35
  error: null,
36
36
  };
37
37
 
38
+ declare const __DEV__: boolean;
39
+
38
40
  export function useGeneration(options: UseGenerationOptions): UseGenerationReturn {
39
41
  const { formState, callbacks, onPromptCleared } = options;
40
42
  const [generationState, setGenerationState] = useState<GenerationState>(initialState);
@@ -42,23 +44,35 @@ export function useGeneration(options: UseGenerationOptions): UseGenerationRetur
42
44
  const totalCost = callbacks.calculateCost(formState.numImages, formState.selectedModel);
43
45
 
44
46
  const handleGenerate = useCallback(async (): Promise<TextToImageGenerationResult | null> => {
47
+ if (__DEV__) console.log("[TextToImage] handleGenerate called");
48
+
45
49
  const trimmedPrompt = formState.prompt.trim();
46
50
 
47
51
  if (!trimmedPrompt) {
52
+ if (__DEV__) console.log("[TextToImage] No prompt provided");
48
53
  setGenerationState((prev) => ({ ...prev, error: "Prompt is required" }));
49
54
  return null;
50
55
  }
51
56
 
52
- if (!callbacks.isAuthenticated()) {
57
+ const isAuth = callbacks.isAuthenticated();
58
+ if (__DEV__) console.log("[TextToImage] isAuthenticated:", isAuth);
59
+
60
+ if (!isAuth) {
61
+ if (__DEV__) console.log("[TextToImage] Auth required - calling onAuthRequired");
53
62
  callbacks.onAuthRequired?.();
54
63
  return null;
55
64
  }
56
65
 
57
- if (!callbacks.canAfford(totalCost)) {
66
+ const affordable = callbacks.canAfford(totalCost);
67
+ if (__DEV__) console.log("[TextToImage] canAfford:", affordable, "totalCost:", totalCost);
68
+
69
+ if (!affordable) {
70
+ if (__DEV__) console.log("[TextToImage] Credits required - calling onCreditsRequired");
58
71
  callbacks.onCreditsRequired?.(totalCost);
59
72
  return null;
60
73
  }
61
74
 
75
+ if (__DEV__) console.log("[TextToImage] Starting generation...");
62
76
  setGenerationState({ isGenerating: true, progress: 0, error: null });
63
77
 
64
78
  const request: TextToImageGenerationRequest = {
@@ -73,14 +87,19 @@ export function useGeneration(options: UseGenerationOptions): UseGenerationRetur
73
87
  outputFormat: formState.outputFormat,
74
88
  };
75
89
 
90
+ if (__DEV__) console.log("[TextToImage] Request:", JSON.stringify(request, null, 2));
91
+
76
92
  try {
77
93
  const result = await callbacks.executeGeneration(request);
94
+ if (__DEV__) console.log("[TextToImage] Result:", JSON.stringify(result, null, 2));
78
95
 
79
96
  if (result.success === true) {
97
+ if (__DEV__) console.log("[TextToImage] Success! Image URLs:", result.imageUrls);
80
98
  callbacks.onSuccess?.(result.imageUrls);
81
99
  onPromptCleared?.();
82
100
  setGenerationState({ isGenerating: false, progress: 100, error: null });
83
101
  } else {
102
+ if (__DEV__) console.log("[TextToImage] Generation failed:", result.error);
84
103
  setGenerationState({ isGenerating: false, progress: 0, error: result.error });
85
104
  callbacks.onError?.(result.error);
86
105
  }
@@ -88,6 +107,7 @@ export function useGeneration(options: UseGenerationOptions): UseGenerationRetur
88
107
  return result;
89
108
  } catch (error) {
90
109
  const message = error instanceof Error ? error.message : String(error);
110
+ if (__DEV__) console.error("[TextToImage] Exception:", message);
91
111
  setGenerationState({ isGenerating: false, progress: 0, error: message });
92
112
  callbacks.onError?.(message);
93
113
  return null;
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Text-to-Image Callbacks Builder Hook
3
+ * Creates callbacks with integrated credit, auth, and creations systems
4
+ * Main app only provides config, package handles everything
5
+ */
6
+
7
+ import { useCallback, useMemo, useRef } from "react";
8
+ import { useQueryClient } from "@tanstack/react-query";
9
+ import type {
10
+ TextToImageCallbacks,
11
+ TextToImageGenerationRequest,
12
+ TextToImageGenerationResult,
13
+ NumImages,
14
+ TextToImageInputBuilder,
15
+ } from "../../domain/types";
16
+ import { executeTextToImage } from "../../infrastructure";
17
+
18
+ export interface TextToImageCallbacksBuilderConfig {
19
+ userId: string | null;
20
+ isAuthenticated: boolean;
21
+ isPremium: boolean;
22
+ imageCredits: number;
23
+ creditCostPerImage: number;
24
+ model: string;
25
+ buildInput: TextToImageInputBuilder;
26
+ deductCredit: (type: "image" | "text") => Promise<void>;
27
+ openPaywall: () => void;
28
+ onNavigateToCreations?: () => void;
29
+ saveCreation?: (imageUrl: string, prompt: string) => Promise<void>;
30
+ invalidateCreationsQuery?: () => void;
31
+ }
32
+
33
+ export interface UseTextToImageCallbacksBuilderOptions {
34
+ config: TextToImageCallbacksBuilderConfig;
35
+ onSuccess?: (imageUrls: string[]) => void;
36
+ onError?: (error: string) => void;
37
+ }
38
+
39
+ export interface UseTextToImageCallbacksBuilderReturn {
40
+ callbacks: TextToImageCallbacks;
41
+ }
42
+
43
+ declare const __DEV__: boolean;
44
+
45
+ export function useTextToImageCallbacksBuilder(
46
+ options: UseTextToImageCallbacksBuilderOptions,
47
+ ): UseTextToImageCallbacksBuilderReturn {
48
+ const { config, onSuccess, onError } = options;
49
+ const queryClient = useQueryClient();
50
+ const isGeneratingRef = useRef(false);
51
+
52
+ const executeGeneration = useCallback(
53
+ async (
54
+ request: TextToImageGenerationRequest,
55
+ ): Promise<TextToImageGenerationResult> => {
56
+ if (!config.userId) {
57
+ return { success: false, error: "User ID not found" };
58
+ }
59
+
60
+ if (isGeneratingRef.current) {
61
+ return { success: false, error: "Generation already in progress" };
62
+ }
63
+
64
+ isGeneratingRef.current = true;
65
+
66
+ try {
67
+ const result = await executeTextToImage(
68
+ {
69
+ prompt: request.prompt,
70
+ userId: config.userId,
71
+ negativePrompt: request.negativePrompt,
72
+ options: {
73
+ aspectRatio: request.aspectRatio,
74
+ size: request.size,
75
+ numImages: request.numImages,
76
+ guidanceScale: request.guidanceScale,
77
+ },
78
+ },
79
+ {
80
+ model: request.model || config.model,
81
+ buildInput: config.buildInput,
82
+ },
83
+ );
84
+
85
+ if (!result.success) {
86
+ return { success: false, error: result.error || "Generation failed" };
87
+ }
88
+
89
+ const imageUrls =
90
+ result.imageUrls || (result.imageUrl ? [result.imageUrl] : []);
91
+
92
+ if (imageUrls.length === 0) {
93
+ return { success: false, error: "No images generated" };
94
+ }
95
+
96
+ await config.deductCredit("image");
97
+
98
+ return { success: true, imageUrls };
99
+ } catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ return { success: false, error: message };
102
+ } finally {
103
+ isGeneratingRef.current = false;
104
+ }
105
+ },
106
+ [config],
107
+ );
108
+
109
+ const calculateCost = useCallback(
110
+ (numImages: NumImages, _model?: string | null): number => {
111
+ return config.creditCostPerImage * numImages;
112
+ },
113
+ [config.creditCostPerImage],
114
+ );
115
+
116
+ const checkCanAfford = useCallback(
117
+ (cost: number): boolean => {
118
+ if (config.isPremium) return true;
119
+ return config.imageCredits >= cost;
120
+ },
121
+ [config.isPremium, config.imageCredits],
122
+ );
123
+
124
+ const checkIsAuthenticated = useCallback(
125
+ (): boolean => config.isAuthenticated,
126
+ [config.isAuthenticated],
127
+ );
128
+
129
+ const handleAuthRequired = useCallback(() => {
130
+ config.openPaywall();
131
+ }, [config]);
132
+
133
+ const handleCreditsRequired = useCallback(
134
+ (_cost: number) => config.openPaywall(),
135
+ [config],
136
+ );
137
+
138
+ const handleSuccess = useCallback(
139
+ async (imageUrls: string[]) => {
140
+ if (!config.userId || imageUrls.length === 0) return;
141
+
142
+ try {
143
+ if (config.saveCreation) {
144
+ for (const imageUrl of imageUrls) {
145
+ await config.saveCreation(imageUrl, "");
146
+ }
147
+ }
148
+
149
+ if (config.invalidateCreationsQuery) {
150
+ config.invalidateCreationsQuery();
151
+ } else {
152
+ queryClient.invalidateQueries({ queryKey: ["creations"] });
153
+ }
154
+
155
+ onSuccess?.(imageUrls);
156
+ config.onNavigateToCreations?.();
157
+ } catch (error) {
158
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
159
+ console.error("[TextToImage] Failed to save creation:", error);
160
+ }
161
+ }
162
+ },
163
+ [config, queryClient, onSuccess],
164
+ );
165
+
166
+ const handleError = useCallback(
167
+ (error: string) => {
168
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
169
+ console.error("[TextToImage] Generation error:", error);
170
+ }
171
+ onError?.(error);
172
+ },
173
+ [onError],
174
+ );
175
+
176
+ const callbacks = useMemo<TextToImageCallbacks>(
177
+ () => ({
178
+ executeGeneration,
179
+ calculateCost,
180
+ canAfford: checkCanAfford,
181
+ isAuthenticated: checkIsAuthenticated,
182
+ onAuthRequired: handleAuthRequired,
183
+ onCreditsRequired: handleCreditsRequired,
184
+ onSuccess: handleSuccess,
185
+ onError: handleError,
186
+ }),
187
+ [
188
+ executeGeneration,
189
+ calculateCost,
190
+ checkCanAfford,
191
+ checkIsAuthenticated,
192
+ handleAuthRequired,
193
+ handleCreditsRequired,
194
+ handleSuccess,
195
+ handleError,
196
+ ],
197
+ );
198
+
199
+ return { callbacks };
200
+ }