@umituz/react-native-ai-generation-content 1.17.92 → 1.17.94

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.92",
3
+ "version": "1.17.94",
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,8 @@ export {
252
252
  useBackgroundGeneration,
253
253
  usePhotoGeneration,
254
254
  useGenerationFlow,
255
+ useGenerationCallbacksBuilder,
256
+ useAIFeatureCallbacks,
255
257
  } from "./presentation/hooks";
256
258
 
257
259
  export type {
@@ -271,6 +273,13 @@ export type {
271
273
  PhotoGenerationStatus,
272
274
  UseGenerationFlowOptions,
273
275
  UseGenerationFlowReturn,
276
+ CreditType,
277
+ GenerationExecutionResult,
278
+ GenerationCallbacksConfig,
279
+ GenerationCallbacks,
280
+ UseGenerationCallbacksBuilderOptions,
281
+ AIFeatureCallbacksConfig,
282
+ AIFeatureCallbacks,
274
283
  } from "./presentation/hooks";
275
284
 
276
285
  // =============================================================================
@@ -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,18 @@ 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";
55
+
56
+ export { useAIFeatureCallbacks } from "./useAIFeatureCallbacks";
57
+ export type {
58
+ AIFeatureCallbacksConfig,
59
+ AIFeatureCallbacks,
60
+ } from "./useAIFeatureCallbacks";
@@ -0,0 +1,167 @@
1
+ /**
2
+ * AI Feature Callbacks Adapter Hook
3
+ * Universal adapter for all AI generation features
4
+ * Works with: TextToImage, TextToVideo, ImageToVideo, etc.
5
+ */
6
+
7
+ import { useCallback, useMemo } from "react";
8
+
9
+ export interface AIFeatureCallbacksConfig<TRequest = unknown, TResult = unknown> {
10
+ // App provides reactive state
11
+ userId: string | null;
12
+ isAuthenticated: boolean;
13
+ creditBalance: number;
14
+
15
+ // Cost config
16
+ creditCostPerUnit: number;
17
+
18
+ // Executor - the actual generation function
19
+ executor: (request: TRequest) => Promise<{
20
+ success: boolean;
21
+ data?: TResult;
22
+ error?: string;
23
+ imageUrl?: string;
24
+ imageUrls?: string[];
25
+ }>;
26
+
27
+ // Actions from app
28
+ showAuthModal: () => void;
29
+ openPaywall: () => void;
30
+ deductCredits?: (amount: number) => Promise<void>;
31
+
32
+ // Optional callbacks
33
+ onSuccess?: (result: TResult) => void;
34
+ onError?: (error: string) => void;
35
+ }
36
+
37
+ /**
38
+ * Universal callbacks interface that maps to all feature-specific ones
39
+ */
40
+ export interface AIFeatureCallbacks<TRequest = unknown, TResult = unknown> {
41
+ // TextToImageCallbacks compatible
42
+ executeGeneration: (request: TRequest) => Promise<{
43
+ success: boolean;
44
+ imageUrls?: string[];
45
+ error?: string;
46
+ }>;
47
+ calculateCost: (multiplier?: number, _model?: string | null) => number;
48
+ canAfford: (cost: number) => boolean;
49
+ isAuthenticated: () => boolean;
50
+ onAuthRequired: () => void;
51
+ onCreditsRequired: (cost?: number) => void;
52
+ onSuccess?: (result: TResult) => void;
53
+ onError?: (error: string) => void;
54
+
55
+ // ImageToVideoCallbacks compatible
56
+ onCreditCheck: (cost: number) => boolean;
57
+ onShowPaywall: (cost: number) => void;
58
+
59
+ // TextToVideoCallbacks compatible
60
+ onAuthCheck: () => boolean;
61
+ }
62
+
63
+ export function useAIFeatureCallbacks<TRequest = unknown, TResult = unknown>(
64
+ config: AIFeatureCallbacksConfig<TRequest, TResult>,
65
+ ): AIFeatureCallbacks<TRequest, TResult> {
66
+ const {
67
+ userId,
68
+ isAuthenticated: isAuth,
69
+ creditBalance,
70
+ creditCostPerUnit,
71
+ executor,
72
+ showAuthModal,
73
+ openPaywall,
74
+ deductCredits,
75
+ onSuccess,
76
+ onError,
77
+ } = config;
78
+
79
+ const canAfford = useCallback(
80
+ (cost: number): boolean => creditBalance >= cost,
81
+ [creditBalance],
82
+ );
83
+
84
+ const isAuthenticated = useCallback(
85
+ (): boolean => isAuth && !!userId,
86
+ [isAuth, userId],
87
+ );
88
+
89
+ const calculateCost = useCallback(
90
+ (multiplier = 1, _model?: string | null): number => creditCostPerUnit * multiplier,
91
+ [creditCostPerUnit],
92
+ );
93
+
94
+ const onAuthRequired = useCallback(() => {
95
+ showAuthModal();
96
+ }, [showAuthModal]);
97
+
98
+ const onCreditsRequired = useCallback(
99
+ (_cost?: number) => {
100
+ openPaywall();
101
+ },
102
+ [openPaywall],
103
+ );
104
+
105
+ const executeGeneration = useCallback(
106
+ async (request: TRequest) => {
107
+ try {
108
+ const result = await executor(request);
109
+
110
+ if (result.success && deductCredits) {
111
+ await deductCredits(creditCostPerUnit);
112
+ }
113
+
114
+ if (result.success && result.data) {
115
+ onSuccess?.(result.data);
116
+ } else if (!result.success && result.error) {
117
+ onError?.(result.error);
118
+ }
119
+
120
+ return {
121
+ success: result.success,
122
+ imageUrls: result.imageUrls,
123
+ error: result.error,
124
+ };
125
+ } catch (error) {
126
+ const message = error instanceof Error ? error.message : String(error);
127
+ onError?.(message);
128
+ return { success: false, error: message };
129
+ }
130
+ },
131
+ [executor, deductCredits, creditCostPerUnit, onSuccess, onError],
132
+ );
133
+
134
+ // Aliases for different callback interfaces
135
+ const onCreditCheck = canAfford;
136
+ const onAuthCheck = isAuthenticated;
137
+ const onShowPaywall = onCreditsRequired;
138
+
139
+ return useMemo(
140
+ () => ({
141
+ executeGeneration,
142
+ calculateCost,
143
+ canAfford,
144
+ isAuthenticated,
145
+ onAuthRequired,
146
+ onCreditsRequired,
147
+ onSuccess,
148
+ onError,
149
+ onCreditCheck,
150
+ onAuthCheck,
151
+ onShowPaywall,
152
+ }),
153
+ [
154
+ executeGeneration,
155
+ calculateCost,
156
+ canAfford,
157
+ isAuthenticated,
158
+ onAuthRequired,
159
+ onCreditsRequired,
160
+ onSuccess,
161
+ onError,
162
+ onCreditCheck,
163
+ onAuthCheck,
164
+ onShowPaywall,
165
+ ],
166
+ );
167
+ }
@@ -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
- }