@umituz/react-native-ai-generation-content 1.17.91 → 1.17.93

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.91",
3
+ "version": "1.17.93",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -42,6 +42,7 @@
42
42
  "@umituz/react-native-firebase": "*",
43
43
  "@umituz/react-native-image": "*",
44
44
  "@umituz/react-native-offline": "*",
45
+ "@umituz/react-native-tanstack": "*",
45
46
  "@umituz/react-native-timezone": "*",
46
47
  "@umituz/react-native-uuid": "*"
47
48
  },
@@ -73,6 +74,7 @@
73
74
  "@umituz/react-native-localization": "latest",
74
75
  "@umituz/react-native-offline": "*",
75
76
  "@umituz/react-native-storage": "latest",
77
+ "@umituz/react-native-tanstack": "latest",
76
78
  "@umituz/react-native-timezone": "latest",
77
79
  "@umituz/react-native-uuid": "*",
78
80
  "eslint": "^9.0.0",
@@ -69,7 +69,6 @@ export {
69
69
  useFormState,
70
70
  useGeneration,
71
71
  useTextToImageForm,
72
- useTextToImageCallbacksBuilder,
73
72
  } from "./presentation";
74
73
  export type {
75
74
  UseFormStateOptions,
@@ -79,9 +78,6 @@ export type {
79
78
  UseGenerationReturn,
80
79
  UseTextToImageFormOptions,
81
80
  UseTextToImageFormReturn,
82
- TextToImageCallbacksBuilderConfig,
83
- UseTextToImageCallbacksBuilderOptions,
84
- UseTextToImageCallbacksBuilderReturn,
85
81
  } from "./presentation";
86
82
 
87
83
  // Provider-based Feature Hook
@@ -22,17 +22,9 @@ export type {
22
22
  UseTextToImageFormReturn,
23
23
  } from "./useTextToImageForm";
24
24
 
25
- // Provider-based Feature Hook (existing)
25
+ // Provider-based Feature Hook
26
26
  export { useTextToImageFeature } from "./useTextToImageFeature";
27
27
  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";
package/src/index.ts CHANGED
@@ -252,6 +252,7 @@ export {
252
252
  useBackgroundGeneration,
253
253
  usePhotoGeneration,
254
254
  useGenerationFlow,
255
+ useGenerationCallbacksBuilder,
255
256
  } from "./presentation/hooks";
256
257
 
257
258
  export type {
@@ -271,6 +272,11 @@ export type {
271
272
  PhotoGenerationStatus,
272
273
  UseGenerationFlowOptions,
273
274
  UseGenerationFlowReturn,
275
+ CreditType,
276
+ GenerationExecutionResult,
277
+ GenerationCallbacksConfig,
278
+ GenerationCallbacks,
279
+ UseGenerationCallbacksBuilderOptions,
274
280
  } from "./presentation/hooks";
275
281
 
276
282
  // =============================================================================
@@ -44,13 +44,16 @@ export const AIGenerationForm: React.FC<AIGenerationFormProps> = ({
44
44
  translations,
45
45
  children,
46
46
  }) => {
47
+ // Log immediately on every render
48
+ if (__DEV__) console.log("[AIGenerationForm] RENDERING NOW - hideGenerateButton:", hideGenerateButton);
49
+
47
50
  const tokens = useAppDesignTokens();
48
51
  const isAdvancedVisible = showAdvanced !== undefined ? showAdvanced : true;
49
52
  const buttonIsDisabled = onPromptChange ? !prompt?.trim() : false;
50
53
 
51
54
  useEffect(() => {
52
55
  if (__DEV__) {
53
- console.log("[AIGenerationForm] RENDER - prompt:", prompt, "isGenerating:", isGenerating, "buttonIsDisabled:", buttonIsDisabled, "hideGenerateButton:", hideGenerateButton);
56
+ console.log("[AIGenerationForm] MOUNTED/UPDATED - prompt:", prompt, "isGenerating:", isGenerating, "buttonIsDisabled:", buttonIsDisabled, "hideGenerateButton:", hideGenerateButton);
54
57
  }
55
58
  }, [prompt, isGenerating, buttonIsDisabled, hideGenerateButton]);
56
59
 
@@ -42,6 +42,9 @@ export const GenerateButton: React.FC<GenerateButtonProps> = ({
42
42
  onAccessoryRightPress,
43
43
  style,
44
44
  }) => {
45
+ // Log immediately on every render
46
+ if (__DEV__) console.log("[GenerateButton] RENDERING NOW");
47
+
45
48
  const tokens = useAppDesignTokens();
46
49
  const disabled = isDisabled || isProcessing;
47
50
  const displayText = isProcessing && processingText ? processingText : text;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Generation Callbacks Types
3
+ * Type definitions for unified generation flow
4
+ */
5
+
6
+ export type CreditType = "image" | "text" | "video" | "audio";
7
+
8
+ export interface GenerationExecutionResult<T = unknown> {
9
+ success: boolean;
10
+ data?: T;
11
+ error?: string;
12
+ }
13
+
14
+ export interface GenerationCallbacksConfig<TRequest, TResult> {
15
+ userId: string | null;
16
+ isAuthenticated: boolean;
17
+ creditBalance: number;
18
+ creditCost: number;
19
+ creditType: CreditType;
20
+ executor: (request: TRequest) => Promise<GenerationExecutionResult<TResult>>;
21
+ deductCredit: (type: CreditType) => Promise<void>;
22
+ openPaywall: () => void;
23
+ showAuthModal?: () => void;
24
+ saveCreation?: (result: TResult) => Promise<void>;
25
+ onNavigateAfterSuccess?: () => void;
26
+ invalidateQueryKeys?: string[];
27
+ }
28
+
29
+ export interface GenerationCallbacks<TRequest, TResult> {
30
+ canAfford: (cost?: number) => boolean;
31
+ isAuthenticated: () => boolean;
32
+ calculateCost: (multiplier?: number) => number;
33
+ execute: (request: TRequest) => Promise<GenerationExecutionResult<TResult>>;
34
+ onAuthRequired: () => void;
35
+ onCreditsRequired: () => void;
36
+ }
37
+
38
+ export interface UseGenerationCallbacksBuilderOptions<TRequest, TResult> {
39
+ config: GenerationCallbacksConfig<TRequest, TResult>;
40
+ onSuccess?: (result: TResult) => void;
41
+ onError?: (error: string) => void;
42
+ }
@@ -43,3 +43,12 @@ export type {
43
43
  UseGenerationFlowOptions,
44
44
  UseGenerationFlowReturn,
45
45
  } from "./useGenerationFlow";
46
+
47
+ export { useGenerationCallbacksBuilder } from "./useGenerationCallbacksBuilder";
48
+ export type {
49
+ CreditType,
50
+ GenerationExecutionResult,
51
+ GenerationCallbacksConfig,
52
+ GenerationCallbacks,
53
+ UseGenerationCallbacksBuilderOptions,
54
+ } from "./generation-callbacks.types";
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Generic Generation Callbacks Builder
3
+ * Unified hook for ALL generation types (image, video, audio, text)
4
+ */
5
+
6
+ import { useCallback, useMemo, useRef } from "react";
7
+ import { useQueryClient } from "@umituz/react-native-tanstack";
8
+ import type {
9
+ GenerationExecutionResult,
10
+ GenerationCallbacks,
11
+ UseGenerationCallbacksBuilderOptions,
12
+ } from "./generation-callbacks.types";
13
+
14
+ declare const __DEV__: boolean;
15
+
16
+ export function useGenerationCallbacksBuilder<TRequest, TResult>(
17
+ options: UseGenerationCallbacksBuilderOptions<TRequest, TResult>,
18
+ ): { callbacks: GenerationCallbacks<TRequest, TResult> } {
19
+ const { config, onSuccess, onError } = options;
20
+ const queryClient = useQueryClient();
21
+ const isExecutingRef = useRef(false);
22
+
23
+ const canAfford = useCallback(
24
+ (cost?: number): boolean => {
25
+ const actualCost = cost ?? config.creditCost;
26
+ return config.creditBalance >= actualCost;
27
+ },
28
+ [config.creditBalance, config.creditCost],
29
+ );
30
+
31
+ const isAuthenticated = useCallback(
32
+ (): boolean => config.isAuthenticated,
33
+ [config.isAuthenticated],
34
+ );
35
+
36
+ const calculateCost = useCallback(
37
+ (multiplier = 1): number => config.creditCost * multiplier,
38
+ [config.creditCost],
39
+ );
40
+
41
+ const onAuthRequired = useCallback(() => {
42
+ config.showAuthModal ? config.showAuthModal() : config.openPaywall();
43
+ }, [config]);
44
+
45
+ const onCreditsRequired = useCallback(() => {
46
+ config.openPaywall();
47
+ }, [config]);
48
+
49
+ const execute = useCallback(
50
+ async (request: TRequest): Promise<GenerationExecutionResult<TResult>> => {
51
+ if (isExecutingRef.current) {
52
+ return { success: false, error: "Generation already in progress" };
53
+ }
54
+
55
+ if (!config.isAuthenticated || !config.userId) {
56
+ onAuthRequired();
57
+ return { success: false, error: "Authentication required" };
58
+ }
59
+
60
+ if (!canAfford()) {
61
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
62
+ console.log("[Generation] Insufficient credits", {
63
+ balance: config.creditBalance,
64
+ cost: config.creditCost,
65
+ });
66
+ }
67
+ onCreditsRequired();
68
+ return { success: false, error: "Insufficient credits" };
69
+ }
70
+
71
+ isExecutingRef.current = true;
72
+
73
+ try {
74
+ const result = await config.executor(request);
75
+
76
+ if (!result.success || !result.data) {
77
+ return { success: false, error: result.error || "Generation failed" };
78
+ }
79
+
80
+ await config.deductCredit(config.creditType);
81
+
82
+ if (config.saveCreation) {
83
+ try {
84
+ await config.saveCreation(result.data);
85
+ } catch {
86
+ // Silent fail for save
87
+ }
88
+ }
89
+
90
+ const keys = config.invalidateQueryKeys ?? ["creations"];
91
+ keys.forEach((key) => queryClient.invalidateQueries({ queryKey: [key] }));
92
+
93
+ onSuccess?.(result.data);
94
+ config.onNavigateAfterSuccess?.();
95
+
96
+ return { success: true, data: result.data };
97
+ } catch (error) {
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ onError?.(message);
100
+ return { success: false, error: message };
101
+ } finally {
102
+ isExecutingRef.current = false;
103
+ }
104
+ },
105
+ [config, canAfford, onAuthRequired, onCreditsRequired, queryClient, onSuccess, onError],
106
+ );
107
+
108
+ const callbacks = useMemo<GenerationCallbacks<TRequest, TResult>>(
109
+ () => ({
110
+ canAfford,
111
+ isAuthenticated,
112
+ calculateCost,
113
+ execute,
114
+ onAuthRequired,
115
+ onCreditsRequired,
116
+ }),
117
+ [canAfford, isAuthenticated, calculateCost, execute, onAuthRequired, onCreditsRequired],
118
+ );
119
+
120
+ return { callbacks };
121
+ }
@@ -1,200 +0,0 @@
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
- }